Diff between 987fae95139f80d0a22c8fdb818a99bf1d7fbf95 and 87353f527ee43bbbf37e8fe7c6655ffadd87c168

Changed Files

File Additions Deletions Status
android/hal-audio.c +167 -0 modified

Full Patch

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 354c3cf..d5ffd14 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -31,6 +31,11 @@
 #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;
@@ -40,11 +45,118 @@ static pthread_t ipc_th = 0;
 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) {
@@ -200,6 +312,54 @@ failed:
 	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)
 {
@@ -592,6 +752,13 @@ static void *ipc_handler(void *data)
 
 		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;