#include "audio-msg.h"
#include "hal-log.h"
#include "hal-msg.h"
+#include "../profiles/audio/a2dp-codecs.h"
+
+static const uint8_t a2dp_src_uuid[] = {
+ 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb };
static int listen_sk = -1;
static int audio_sk = -1;
static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
+struct audio_input_config {
+ uint32_t rate;
+ uint32_t channels;
+ audio_format_t format;
+};
+
+static int sbc_get_presets(struct audio_preset *preset, size_t *len);
+
+struct audio_codec {
+ uint8_t type;
+
+ int (*get_presets) (struct audio_preset *preset, size_t *len);
+
+ int (*init) (struct audio_preset *preset, void **codec_data);
+ int (*cleanup) (void *codec_data);
+ int (*get_config) (void *codec_data,
+ struct audio_input_config *config);
+ ssize_t (*write_data) (void *codec_data, const void *buffer,
+ size_t bytes);
+};
+
+static const struct audio_codec audio_codecs[] = {
+ {
+ .type = A2DP_CODEC_SBC,
+
+ .get_presets = sbc_get_presets,
+ }
+};
+
+#define NUM_CODECS (sizeof(audio_codecs) / sizeof(audio_codecs[0]))
+
+#define MAX_AUDIO_ENDPOINTS NUM_CODECS
+
+struct audio_endpoint {
+ uint8_t id;
+ const struct audio_codec *codec;
+ void *codec_data;
+ int fd;
+};
+
+static struct audio_endpoint audio_endpoints[MAX_AUDIO_ENDPOINTS];
+
struct a2dp_audio_dev {
struct audio_hw_device dev;
struct audio_stream_out *out;
};
+static const a2dp_sbc_t sbc_presets[] = {
+ {
+ .frequency = 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,
+ .subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8,
+ .allocation_method = SBC_ALLOCATION_SNR |
+ SBC_ALLOCATION_LOUDNESS,
+ .block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 |
+ SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16,
+ .min_bitpool = MIN_BITPOOL,
+ .max_bitpool = MAX_BITPOOL
+ },
+ {
+ .frequency = SBC_SAMPLING_FREQ_44100,
+ .channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO,
+ .subbands = SBC_SUBBANDS_8,
+ .allocation_method = SBC_ALLOCATION_LOUDNESS,
+ .block_length = SBC_BLOCK_LENGTH_16,
+ .min_bitpool = MIN_BITPOOL,
+ .max_bitpool = MAX_BITPOOL
+ },
+ {
+ .frequency = SBC_SAMPLING_FREQ_48000,
+ .channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO,
+ .subbands = SBC_SUBBANDS_8,
+ .allocation_method = SBC_ALLOCATION_LOUDNESS,
+ .block_length = SBC_BLOCK_LENGTH_16,
+ .min_bitpool = MIN_BITPOOL,
+ .max_bitpool = MAX_BITPOOL
+ },
+};
+
+static int sbc_get_presets(struct audio_preset *preset, size_t *len)
+{
+ int i;
+ int count;
+ size_t new_len = 0;
+ uint8_t *ptr = (uint8_t *) preset;
+ size_t preset_size = sizeof(*preset) + sizeof(a2dp_sbc_t);
+
+ DBG("");
+
+ count = sizeof(sbc_presets) / sizeof(sbc_presets[0]);
+
+ for (i = 0; i < count; i++) {
+ preset = (struct audio_preset *) ptr;
+
+ if (new_len + preset_size > *len)
+ break;
+
+ preset->len = sizeof(a2dp_sbc_t);
+ memcpy(preset->data, &sbc_presets[i], preset->len);
+
+ new_len += preset_size;
+ ptr += preset_size;
+ }
+
+ *len = new_len;
+
+ return i;
+}
+
static void audio_ipc_cleanup(void)
{
if (audio_sk >= 0) {
return AUDIO_STATUS_FAILED;
}
+static int ipc_open_cmd(const struct audio_codec *codec)
+{
+ uint8_t buf[BLUEZ_AUDIO_MTU];
+ struct audio_cmd_open *cmd = (struct audio_cmd_open *) buf;
+ struct audio_rsp_open rsp;
+ size_t cmd_len = sizeof(buf) - sizeof(*cmd);
+ size_t rsp_len = sizeof(rsp);
+ int result;
+
+ DBG("");
+
+ memcpy(cmd->uuid, a2dp_src_uuid, sizeof(a2dp_src_uuid));
+
+ cmd->codec = codec->type;
+ cmd->presets = codec->get_presets(cmd->preset, &cmd_len);
+
+ cmd_len += sizeof(*cmd);
+
+ result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN, cmd_len, cmd,
+ &rsp_len, &rsp, NULL);
+
+ if (result != AUDIO_STATUS_SUCCESS)
+ return 0;
+
+ return rsp.id;
+}
+
+static int register_endpoints(void)
+{
+ struct audio_endpoint *ep = &audio_endpoints[0];
+ size_t i;
+
+ for (i = 0; i < NUM_CODECS; i++, ep++) {
+ const struct audio_codec *codec = &audio_codecs[i];
+
+ ep->id = ipc_open_cmd(codec);
+
+ if (!ep->id)
+ return AUDIO_STATUS_FAILED;
+
+ ep->codec = codec;
+ ep->codec_data = NULL;
+ ep->fd = -1;
+ }
+
+ return AUDIO_STATUS_SUCCESS;
+}
+
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
DBG("Audio IPC: Connected");
+ if (register_endpoints() != AUDIO_STATUS_SUCCESS) {
+ error("audio: Failed to register endpoints");
+
+ shutdown(audio_sk, SHUT_RDWR);
+ continue;
+ }
+
memset(&pfd, 0, sizeof(pfd));
pfd.fd = audio_sk;
pfd.events = POLLHUP | POLLERR | POLLNVAL;