/* 
 | 
 * BlueALSA - bluez-a2dp.c 
 | 
 * Copyright (c) 2016-2018 Arkadiusz Bokowy 
 | 
 * 
 | 
 * This file is a part of bluez-alsa. 
 | 
 * 
 | 
 * This project is licensed under the terms of the MIT license. 
 | 
 * 
 | 
 */ 
 | 
  
 | 
#if HAVE_CONFIG_H 
 | 
# include "config.h" 
 | 
#endif 
 | 
  
 | 
#include "bluez-a2dp.h" 
 | 
#include "shared/defs.h" 
 | 
  
 | 
static const a2dp_sbc_t a2dp_sbc = { 
 | 
    .frequency = 
 | 
        SBC_SAMPLING_FREQ_16000 | 
 | 
        SBC_SAMPLING_FREQ_32000 | 
 | 
        SBC_SAMPLING_FREQ_44100 | 
 | 
        SBC_SAMPLING_FREQ_48000, 
 | 
    .channel_mode = 
 | 
        SBC_CHANNEL_MODE_MONO | 
 | 
        SBC_CHANNEL_MODE_DUAL_CHANNEL | 
 | 
        SBC_CHANNEL_MODE_STEREO | 
 | 
        SBC_CHANNEL_MODE_JOINT_STEREO, 
 | 
    .block_length = 
 | 
        SBC_BLOCK_LENGTH_4 | 
 | 
        SBC_BLOCK_LENGTH_8 | 
 | 
        SBC_BLOCK_LENGTH_12 | 
 | 
        SBC_BLOCK_LENGTH_16, 
 | 
    .subbands = 
 | 
        SBC_SUBBANDS_4 | 
 | 
        SBC_SUBBANDS_8, 
 | 
    .allocation_method = 
 | 
        SBC_ALLOCATION_SNR | 
 | 
        SBC_ALLOCATION_LOUDNESS, 
 | 
    .min_bitpool = SBC_MIN_BITPOOL, 
 | 
    .max_bitpool = SBC_MAX_BITPOOL, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_channel_mode a2dp_sbc_channels[] = { 
 | 
    { BLUEZ_A2DP_CHM_MONO, SBC_CHANNEL_MODE_MONO }, 
 | 
    { BLUEZ_A2DP_CHM_DUAL_CHANNEL, SBC_CHANNEL_MODE_DUAL_CHANNEL }, 
 | 
    { BLUEZ_A2DP_CHM_STEREO, SBC_CHANNEL_MODE_STEREO }, 
 | 
    { BLUEZ_A2DP_CHM_JOINT_STEREO, SBC_CHANNEL_MODE_JOINT_STEREO }, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_sampling_freq a2dp_sbc_samplings[] = { 
 | 
    { 16000, SBC_SAMPLING_FREQ_16000 }, 
 | 
    { 32000, SBC_SAMPLING_FREQ_32000 }, 
 | 
    { 44100, SBC_SAMPLING_FREQ_44100 }, 
 | 
    { 48000, SBC_SAMPLING_FREQ_48000 }, 
 | 
}; 
 | 
  
 | 
static const a2dp_mpeg_t a2dp_mpeg = { 
 | 
    .layer = 
 | 
        MPEG_LAYER_MP1 | 
 | 
        MPEG_LAYER_MP2 | 
 | 
        MPEG_LAYER_MP3, 
 | 
    .crc = 1, 
 | 
    .channel_mode = 
 | 
        MPEG_CHANNEL_MODE_MONO | 
 | 
        MPEG_CHANNEL_MODE_DUAL_CHANNEL | 
 | 
        MPEG_CHANNEL_MODE_STEREO | 
 | 
        MPEG_CHANNEL_MODE_JOINT_STEREO, 
 | 
    .mpf = 1, 
 | 
    .frequency = 
 | 
        MPEG_SAMPLING_FREQ_16000 | 
 | 
        MPEG_SAMPLING_FREQ_22050 | 
 | 
        MPEG_SAMPLING_FREQ_24000 | 
 | 
        MPEG_SAMPLING_FREQ_32000 | 
 | 
        MPEG_SAMPLING_FREQ_44100 | 
 | 
        MPEG_SAMPLING_FREQ_48000, 
 | 
    .bitrate = 
 | 
        MPEG_BIT_RATE_VBR | 
 | 
        MPEG_BIT_RATE_320000 | 
 | 
        MPEG_BIT_RATE_256000 | 
 | 
        MPEG_BIT_RATE_224000 | 
 | 
        MPEG_BIT_RATE_192000 | 
 | 
        MPEG_BIT_RATE_160000 | 
 | 
        MPEG_BIT_RATE_128000 | 
 | 
        MPEG_BIT_RATE_112000 | 
 | 
        MPEG_BIT_RATE_96000 | 
 | 
        MPEG_BIT_RATE_80000 | 
 | 
        MPEG_BIT_RATE_64000 | 
 | 
        MPEG_BIT_RATE_56000 | 
 | 
        MPEG_BIT_RATE_48000 | 
 | 
        MPEG_BIT_RATE_40000 | 
 | 
        MPEG_BIT_RATE_32000 | 
 | 
        MPEG_BIT_RATE_FREE, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_channel_mode a2dp_mpeg_channels[] = { 
 | 
    { BLUEZ_A2DP_CHM_MONO, MPEG_CHANNEL_MODE_MONO }, 
 | 
    { BLUEZ_A2DP_CHM_DUAL_CHANNEL, MPEG_CHANNEL_MODE_DUAL_CHANNEL }, 
 | 
    { BLUEZ_A2DP_CHM_STEREO, MPEG_CHANNEL_MODE_STEREO }, 
 | 
    { BLUEZ_A2DP_CHM_JOINT_STEREO, MPEG_CHANNEL_MODE_JOINT_STEREO }, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_sampling_freq a2dp_mpeg_samplings[] = { 
 | 
    { 16000, MPEG_SAMPLING_FREQ_16000 }, 
 | 
    { 22050, MPEG_SAMPLING_FREQ_22050 }, 
 | 
    { 24000, MPEG_SAMPLING_FREQ_24000 }, 
 | 
    { 32000, MPEG_SAMPLING_FREQ_32000 }, 
 | 
    { 44100, MPEG_SAMPLING_FREQ_44100 }, 
 | 
    { 48000, MPEG_SAMPLING_FREQ_48000 }, 
 | 
}; 
 | 
  
 | 
static const a2dp_aac_t a2dp_aac = { 
 | 
    .object_type = 
 | 
        /* NOTE: AAC Long Term Prediction and AAC Scalable are 
 | 
         *       not supported by the FDK-AAC library. */ 
 | 
        AAC_OBJECT_TYPE_MPEG2_AAC_LC | 
 | 
        AAC_OBJECT_TYPE_MPEG4_AAC_LC, 
 | 
    AAC_INIT_FREQUENCY( 
 | 
            AAC_SAMPLING_FREQ_8000 | 
 | 
            AAC_SAMPLING_FREQ_11025 | 
 | 
            AAC_SAMPLING_FREQ_12000 | 
 | 
            AAC_SAMPLING_FREQ_16000 | 
 | 
            AAC_SAMPLING_FREQ_22050 | 
 | 
            AAC_SAMPLING_FREQ_24000 | 
 | 
            AAC_SAMPLING_FREQ_32000 | 
 | 
            AAC_SAMPLING_FREQ_44100 | 
 | 
            AAC_SAMPLING_FREQ_48000 | 
 | 
            AAC_SAMPLING_FREQ_64000 | 
 | 
            AAC_SAMPLING_FREQ_88200 | 
 | 
            AAC_SAMPLING_FREQ_96000) 
 | 
    .channels = 
 | 
        AAC_CHANNELS_1 | 
 | 
        AAC_CHANNELS_2, 
 | 
    .vbr = 1, 
 | 
    AAC_INIT_BITRATE(320000) 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_channel_mode a2dp_aac_channels[] = { 
 | 
    { BLUEZ_A2DP_CHM_MONO, AAC_CHANNELS_1 }, 
 | 
    { BLUEZ_A2DP_CHM_STEREO, AAC_CHANNELS_2 }, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_sampling_freq a2dp_aac_samplings[] = { 
 | 
    { 8000, AAC_SAMPLING_FREQ_8000 }, 
 | 
    { 11025, AAC_SAMPLING_FREQ_11025 }, 
 | 
    { 12000, AAC_SAMPLING_FREQ_12000 }, 
 | 
    { 16000, AAC_SAMPLING_FREQ_16000 }, 
 | 
    { 22050, AAC_SAMPLING_FREQ_22050 }, 
 | 
    { 24000, AAC_SAMPLING_FREQ_24000 }, 
 | 
    { 32000, AAC_SAMPLING_FREQ_32000 }, 
 | 
    { 44100, AAC_SAMPLING_FREQ_44100 }, 
 | 
    { 48000, AAC_SAMPLING_FREQ_48000 }, 
 | 
    { 64000, AAC_SAMPLING_FREQ_64000 }, 
 | 
    { 88200, AAC_SAMPLING_FREQ_88200 }, 
 | 
    { 96000, AAC_SAMPLING_FREQ_96000 }, 
 | 
}; 
 | 
  
 | 
static const a2dp_aptx_t a2dp_aptx = { 
 | 
    .info.vendor_id = APTX_VENDOR_ID, 
 | 
    .info.codec_id = APTX_CODEC_ID, 
 | 
    .channel_mode = 
 | 
        /* NOTE: Used apt-X library does not support 
 | 
         *       single channel (mono) mode. */ 
 | 
        APTX_CHANNEL_MODE_STEREO, 
 | 
    .frequency = 
 | 
        APTX_SAMPLING_FREQ_16000 | 
 | 
        APTX_SAMPLING_FREQ_32000 | 
 | 
        APTX_SAMPLING_FREQ_44100 | 
 | 
        APTX_SAMPLING_FREQ_48000, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_channel_mode a2dp_aptx_channels[] = { 
 | 
    { BLUEZ_A2DP_CHM_STEREO, APTX_CHANNEL_MODE_STEREO }, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_sampling_freq a2dp_aptx_samplings[] = { 
 | 
    { 16000, APTX_SAMPLING_FREQ_16000 }, 
 | 
    { 32000, APTX_SAMPLING_FREQ_32000 }, 
 | 
    { 44100, APTX_SAMPLING_FREQ_44100 }, 
 | 
    { 48000, APTX_SAMPLING_FREQ_48000 }, 
 | 
}; 
 | 
  
 | 
static const a2dp_ldac_t a2dp_ldac = { 
 | 
    .info.vendor_id = LDAC_VENDOR_ID, 
 | 
    .info.codec_id = LDAC_CODEC_ID, 
 | 
    .channel_mode = 
 | 
        LDAC_CHANNEL_MODE_MONO | 
 | 
        LDAC_CHANNEL_MODE_DUAL_CHANNEL | 
 | 
        LDAC_CHANNEL_MODE_STEREO, 
 | 
    .frequency = 
 | 
        /* NOTE: Used LDAC library does not support 
 | 
         *       frequencies higher than 96 kHz. */ 
 | 
        LDAC_SAMPLING_FREQ_44100 | 
 | 
        LDAC_SAMPLING_FREQ_48000 | 
 | 
        LDAC_SAMPLING_FREQ_88200 | 
 | 
        LDAC_SAMPLING_FREQ_96000, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_channel_mode a2dp_ldac_channels[] = { 
 | 
    { BLUEZ_A2DP_CHM_MONO, LDAC_CHANNEL_MODE_MONO }, 
 | 
    { BLUEZ_A2DP_CHM_DUAL_CHANNEL, LDAC_CHANNEL_MODE_DUAL_CHANNEL }, 
 | 
    { BLUEZ_A2DP_CHM_STEREO, LDAC_CHANNEL_MODE_STEREO }, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_sampling_freq a2dp_ldac_samplings[] = { 
 | 
    { 44100, LDAC_SAMPLING_FREQ_44100 }, 
 | 
    { 48000, LDAC_SAMPLING_FREQ_48000 }, 
 | 
    { 88200, LDAC_SAMPLING_FREQ_88200 }, 
 | 
    { 96000, LDAC_SAMPLING_FREQ_96000 }, 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_source_sbc = { 
 | 
    .dir = BLUEZ_A2DP_SOURCE, 
 | 
    .id = A2DP_CODEC_SBC, 
 | 
    .cfg = &a2dp_sbc, 
 | 
    .cfg_size = sizeof(a2dp_sbc), 
 | 
    .channels = a2dp_sbc_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_sbc_channels), 
 | 
    .samplings = a2dp_sbc_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_sbc_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_sink_sbc = { 
 | 
    .dir = BLUEZ_A2DP_SINK, 
 | 
    .id = A2DP_CODEC_SBC, 
 | 
    .cfg = &a2dp_sbc, 
 | 
    .cfg_size = sizeof(a2dp_sbc), 
 | 
    .channels = a2dp_sbc_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_sbc_channels), 
 | 
    .samplings = a2dp_sbc_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_sbc_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_source_mpeg = { 
 | 
    .dir = BLUEZ_A2DP_SOURCE, 
 | 
    .id = A2DP_CODEC_MPEG12, 
 | 
    .cfg = &a2dp_mpeg, 
 | 
    .cfg_size = sizeof(a2dp_mpeg), 
 | 
    .channels = a2dp_mpeg_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_mpeg_channels), 
 | 
    .samplings = a2dp_mpeg_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_mpeg_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_sink_mpeg = { 
 | 
    .dir = BLUEZ_A2DP_SINK, 
 | 
    .id = A2DP_CODEC_MPEG12, 
 | 
    .cfg = &a2dp_mpeg, 
 | 
    .cfg_size = sizeof(a2dp_mpeg), 
 | 
    .channels = a2dp_mpeg_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_mpeg_channels), 
 | 
    .samplings = a2dp_mpeg_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_mpeg_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_source_aac = { 
 | 
    .dir = BLUEZ_A2DP_SOURCE, 
 | 
    .id = A2DP_CODEC_MPEG24, 
 | 
    .cfg = &a2dp_aac, 
 | 
    .cfg_size = sizeof(a2dp_aac), 
 | 
    .channels = a2dp_aac_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_aac_channels), 
 | 
    .samplings = a2dp_aac_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_aac_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_sink_aac = { 
 | 
    .dir = BLUEZ_A2DP_SINK, 
 | 
    .id = A2DP_CODEC_MPEG24, 
 | 
    .cfg = &a2dp_aac, 
 | 
    .cfg_size = sizeof(a2dp_aac), 
 | 
    .channels = a2dp_aac_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_aac_channels), 
 | 
    .samplings = a2dp_aac_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_aac_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_source_aptx = { 
 | 
    .dir = BLUEZ_A2DP_SOURCE, 
 | 
    .id = A2DP_CODEC_VENDOR_APTX, 
 | 
    .cfg = &a2dp_aptx, 
 | 
    .cfg_size = sizeof(a2dp_aptx), 
 | 
    .channels = a2dp_aptx_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_aptx_channels), 
 | 
    .samplings = a2dp_aptx_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_aptx_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_sink_aptx = { 
 | 
    .dir = BLUEZ_A2DP_SINK, 
 | 
    .id = A2DP_CODEC_VENDOR_APTX, 
 | 
    .cfg = &a2dp_aptx, 
 | 
    .cfg_size = sizeof(a2dp_aptx), 
 | 
    .channels = a2dp_aptx_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_aptx_channels), 
 | 
    .samplings = a2dp_aptx_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_aptx_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_source_ldac = { 
 | 
    .dir = BLUEZ_A2DP_SOURCE, 
 | 
    .id = A2DP_CODEC_VENDOR_LDAC, 
 | 
    .cfg = &a2dp_ldac, 
 | 
    .cfg_size = sizeof(a2dp_ldac), 
 | 
    .channels = a2dp_ldac_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_ldac_channels), 
 | 
    .samplings = a2dp_ldac_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_ldac_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec a2dp_codec_sink_ldac = { 
 | 
    .dir = BLUEZ_A2DP_SINK, 
 | 
    .id = A2DP_CODEC_VENDOR_LDAC, 
 | 
    .cfg = &a2dp_ldac, 
 | 
    .cfg_size = sizeof(a2dp_ldac), 
 | 
    .channels = a2dp_ldac_channels, 
 | 
    .channels_size = ARRAYSIZE(a2dp_ldac_channels), 
 | 
    .samplings = a2dp_ldac_samplings, 
 | 
    .samplings_size = ARRAYSIZE(a2dp_ldac_samplings), 
 | 
}; 
 | 
  
 | 
static const struct bluez_a2dp_codec *a2dp_codecs[] = { 
 | 
#if ENABLE_LDAC 
 | 
    &a2dp_codec_source_ldac, 
 | 
#endif 
 | 
#if ENABLE_APTX 
 | 
    &a2dp_codec_source_aptx, 
 | 
#endif 
 | 
#if ENABLE_AAC 
 | 
    &a2dp_codec_source_aac, 
 | 
    &a2dp_codec_sink_aac, 
 | 
#endif 
 | 
#if ENABLE_MPEG 
 | 
    &a2dp_codec_source_mpeg, 
 | 
    &a2dp_codec_sink_mpeg, 
 | 
#endif 
 | 
    &a2dp_codec_source_sbc, 
 | 
    &a2dp_codec_sink_sbc, 
 | 
    NULL, 
 | 
}; 
 | 
  
 | 
const struct bluez_a2dp_codec **bluez_a2dp_codecs = a2dp_codecs; 
 |