Blame android/hal-audio-sbc.c

Packit 34410b
/*
Packit 34410b
 * Copyright (C) 2013 Intel Corporation
Packit 34410b
 *
Packit 34410b
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 34410b
 * you may not use this file except in compliance with the License.
Packit 34410b
 * You may obtain a copy of the License at
Packit 34410b
 *
Packit 34410b
 *      http://www.apache.org/licenses/LICENSE-2.0
Packit 34410b
 *
Packit 34410b
 * Unless required by applicable law or agreed to in writing, software
Packit 34410b
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 34410b
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 34410b
 * See the License for the specific language governing permissions and
Packit 34410b
 * limitations under the License.
Packit 34410b
 *
Packit 34410b
 */
Packit 34410b
Packit 34410b
#define _GNU_SOURCE
Packit 34410b
#include <stdbool.h>
Packit 34410b
#include <string.h>
Packit 34410b
#include <malloc.h>
Packit 34410b
#include <stdlib.h>
Packit 34410b
Packit 34410b
#include <sbc/sbc.h>
Packit 34410b
#include "audio-msg.h"
Packit 34410b
#include "hal-audio.h"
Packit 34410b
#include "hal-log.h"
Packit 34410b
#include "../profiles/audio/a2dp-codecs.h"
Packit 34410b
Packit 34410b
#define MAX_FRAMES_IN_PAYLOAD 15
Packit 34410b
Packit 34410b
#define SBC_QUALITY_MIN_BITPOOL	33
Packit 34410b
#define SBC_QUALITY_STEP	5
Packit 34410b
Packit 34410b
Packit 34410b
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 34410b
Packit 34410b
struct rtp_payload {
Packit 34410b
	unsigned frame_count:4;
Packit 34410b
	unsigned rfa0:1;
Packit 34410b
	unsigned is_last_fragment:1;
Packit 34410b
	unsigned is_first_fragment:1;
Packit 34410b
	unsigned is_fragmented:1;
Packit 34410b
} __attribute__ ((packed));
Packit 34410b
Packit 34410b
#elif __BYTE_ORDER == __BIG_ENDIAN
Packit 34410b
Packit 34410b
struct rtp_payload {
Packit 34410b
	unsigned is_fragmented:1;
Packit 34410b
	unsigned is_first_fragment:1;
Packit 34410b
	unsigned is_last_fragment:1;
Packit 34410b
	unsigned rfa0:1;
Packit 34410b
	unsigned frame_count:4;
Packit 34410b
} __attribute__ ((packed));
Packit 34410b
Packit 34410b
#else
Packit 34410b
#error "Unknown byte order"
Packit 34410b
#endif
Packit 34410b
Packit 34410b
struct media_packet_sbc {
Packit 34410b
	struct media_packet_rtp hdr;
Packit 34410b
	struct rtp_payload payload;
Packit 34410b
	uint8_t data[0];
Packit 34410b
};
Packit 34410b
Packit 34410b
struct sbc_data {
Packit 34410b
	a2dp_sbc_t sbc;
Packit 34410b
Packit 34410b
	sbc_t enc;
Packit 34410b
Packit 34410b
	uint16_t payload_len;
Packit 34410b
Packit 34410b
	size_t in_frame_len;
Packit 34410b
	size_t in_buf_size;
Packit 34410b
Packit 34410b
	size_t out_frame_len;
Packit 34410b
Packit 34410b
	unsigned frame_duration;
Packit 34410b
	unsigned frames_per_packet;
Packit 34410b
};
Packit 34410b
Packit 34410b
static const a2dp_sbc_t sbc_presets[] = {
Packit 34410b
	{
Packit 34410b
		.frequency = SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_48000,
Packit 34410b
		.channel_mode = SBC_CHANNEL_MODE_MONO |
Packit 34410b
				SBC_CHANNEL_MODE_DUAL_CHANNEL |
Packit 34410b
				SBC_CHANNEL_MODE_STEREO |
Packit 34410b
				SBC_CHANNEL_MODE_JOINT_STEREO,
Packit 34410b
		.subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8,
Packit 34410b
		.allocation_method = SBC_ALLOCATION_SNR |
Packit 34410b
					SBC_ALLOCATION_LOUDNESS,
Packit 34410b
		.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 |
Packit 34410b
				SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16,
Packit 34410b
		.min_bitpool = SBC_MIN_BITPOOL,
Packit 34410b
		.max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100,
Packit 34410b
	},
Packit 34410b
	{
Packit 34410b
		.frequency = SBC_SAMPLING_FREQ_44100,
Packit 34410b
		.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO,
Packit 34410b
		.subbands = SBC_SUBBANDS_8,
Packit 34410b
		.allocation_method = SBC_ALLOCATION_LOUDNESS,
Packit 34410b
		.block_length = SBC_BLOCK_LENGTH_16,
Packit 34410b
		.min_bitpool = SBC_MIN_BITPOOL,
Packit 34410b
		.max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100,
Packit 34410b
	},
Packit 34410b
	{
Packit 34410b
		.frequency = SBC_SAMPLING_FREQ_48000,
Packit 34410b
		.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO,
Packit 34410b
		.subbands = SBC_SUBBANDS_8,
Packit 34410b
		.allocation_method = SBC_ALLOCATION_LOUDNESS,
Packit 34410b
		.block_length = SBC_BLOCK_LENGTH_16,
Packit 34410b
		.min_bitpool = SBC_MIN_BITPOOL,
Packit 34410b
		.max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_48000,
Packit 34410b
	},
Packit 34410b
};
Packit 34410b
Packit 34410b
static int sbc_get_presets(struct audio_preset *preset, size_t *len)
Packit 34410b
{
Packit 34410b
	int i;
Packit 34410b
	int count;
Packit 34410b
	size_t new_len = 0;
Packit 34410b
	uint8_t *ptr = (uint8_t *) preset;
Packit 34410b
	size_t preset_size = sizeof(*preset) + sizeof(a2dp_sbc_t);
Packit 34410b
Packit 34410b
	count = sizeof(sbc_presets) / sizeof(sbc_presets[0]);
Packit 34410b
Packit 34410b
	for (i = 0; i < count; i++) {
Packit 34410b
		preset = (struct audio_preset *) ptr;
Packit 34410b
Packit 34410b
		if (new_len + preset_size > *len)
Packit 34410b
			break;
Packit 34410b
Packit 34410b
		preset->len = sizeof(a2dp_sbc_t);
Packit 34410b
		memcpy(preset->data, &sbc_presets[i], preset->len);
Packit 34410b
Packit 34410b
		new_len += preset_size;
Packit 34410b
		ptr += preset_size;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	*len = new_len;
Packit 34410b
Packit 34410b
	return i;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int sbc_freq2int(uint8_t freq)
Packit 34410b
{
Packit 34410b
	switch (freq) {
Packit 34410b
	case SBC_SAMPLING_FREQ_16000:
Packit 34410b
		return 16000;
Packit 34410b
	case SBC_SAMPLING_FREQ_32000:
Packit 34410b
		return 32000;
Packit 34410b
	case SBC_SAMPLING_FREQ_44100:
Packit 34410b
		return 44100;
Packit 34410b
	case SBC_SAMPLING_FREQ_48000:
Packit 34410b
		return 48000;
Packit 34410b
	default:
Packit 34410b
		return 0;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static const char *sbc_mode2str(uint8_t mode)
Packit 34410b
{
Packit 34410b
	switch (mode) {
Packit 34410b
	case SBC_CHANNEL_MODE_MONO:
Packit 34410b
		return "Mono";
Packit 34410b
	case SBC_CHANNEL_MODE_DUAL_CHANNEL:
Packit 34410b
		return "DualChannel";
Packit 34410b
	case SBC_CHANNEL_MODE_STEREO:
Packit 34410b
		return "Stereo";
Packit 34410b
	case SBC_CHANNEL_MODE_JOINT_STEREO:
Packit 34410b
		return "JointStereo";
Packit 34410b
	default:
Packit 34410b
		return "(unknown)";
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static int sbc_blocks2int(uint8_t blocks)
Packit 34410b
{
Packit 34410b
	switch (blocks) {
Packit 34410b
	case SBC_BLOCK_LENGTH_4:
Packit 34410b
		return 4;
Packit 34410b
	case SBC_BLOCK_LENGTH_8:
Packit 34410b
		return 8;
Packit 34410b
	case SBC_BLOCK_LENGTH_12:
Packit 34410b
		return 12;
Packit 34410b
	case SBC_BLOCK_LENGTH_16:
Packit 34410b
		return 16;
Packit 34410b
	default:
Packit 34410b
		return 0;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static int sbc_subbands2int(uint8_t subbands)
Packit 34410b
{
Packit 34410b
	switch (subbands) {
Packit 34410b
	case SBC_SUBBANDS_4:
Packit 34410b
		return 4;
Packit 34410b
	case SBC_SUBBANDS_8:
Packit 34410b
		return 8;
Packit 34410b
	default:
Packit 34410b
		return 0;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static const char *sbc_allocation2str(uint8_t allocation)
Packit 34410b
{
Packit 34410b
	switch (allocation) {
Packit 34410b
	case SBC_ALLOCATION_SNR:
Packit 34410b
		return "SNR";
Packit 34410b
	case SBC_ALLOCATION_LOUDNESS:
Packit 34410b
		return "Loudness";
Packit 34410b
	default:
Packit 34410b
		return "(unknown)";
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void sbc_init_encoder(struct sbc_data *sbc_data)
Packit 34410b
{
Packit 34410b
	a2dp_sbc_t *in = &sbc_data->sbc;
Packit 34410b
	sbc_t *out = &sbc_data->enc;
Packit 34410b
Packit 34410b
	sbc_init_a2dp(out, 0L, in, sizeof(*in));
Packit 34410b
Packit 34410b
	out->endian = SBC_LE;
Packit 34410b
	out->bitpool = in->max_bitpool;
Packit 34410b
Packit 34410b
	DBG("frequency=%d channel_mode=%s block_length=%d subbands=%d allocation=%s bitpool=%d-%d",
Packit 34410b
			sbc_freq2int(in->frequency),
Packit 34410b
			sbc_mode2str(in->channel_mode),
Packit 34410b
			sbc_blocks2int(in->block_length),
Packit 34410b
			sbc_subbands2int(in->subbands),
Packit 34410b
			sbc_allocation2str(in->allocation_method),
Packit 34410b
			in->min_bitpool, in->max_bitpool);
Packit 34410b
}
Packit 34410b
Packit 34410b
static void sbc_codec_calculate(struct sbc_data *sbc_data)
Packit 34410b
{
Packit 34410b
	size_t in_frame_len;
Packit 34410b
	size_t out_frame_len;
Packit 34410b
	size_t num_frames;
Packit 34410b
Packit 34410b
	in_frame_len = sbc_get_codesize(&sbc_data->enc);
Packit 34410b
	out_frame_len = sbc_get_frame_length(&sbc_data->enc);
Packit 34410b
	num_frames = sbc_data->payload_len / out_frame_len;
Packit 34410b
Packit 34410b
	if (num_frames > MAX_FRAMES_IN_PAYLOAD)
Packit 34410b
		num_frames = MAX_FRAMES_IN_PAYLOAD;
Packit 34410b
Packit 34410b
	sbc_data->in_frame_len = in_frame_len;
Packit 34410b
	sbc_data->in_buf_size = num_frames * in_frame_len;
Packit 34410b
Packit 34410b
	sbc_data->out_frame_len = out_frame_len;
Packit 34410b
Packit 34410b
	sbc_data->frame_duration = sbc_get_frame_duration(&sbc_data->enc);
Packit 34410b
	sbc_data->frames_per_packet = num_frames;
Packit 34410b
Packit 34410b
	DBG("in_frame_len=%zu out_frame_len=%zu frames_per_packet=%zu",
Packit 34410b
				in_frame_len, out_frame_len, num_frames);
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool sbc_codec_init(struct audio_preset *preset, uint16_t payload_len,
Packit 34410b
							void **codec_data)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data;
Packit 34410b
Packit 34410b
	if (preset->len != sizeof(a2dp_sbc_t)) {
Packit 34410b
		error("SBC: preset size mismatch");
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	sbc_data = calloc(sizeof(struct sbc_data), 1);
Packit 34410b
	if (!sbc_data)
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	memcpy(&sbc_data->sbc, preset->data, preset->len);
Packit 34410b
Packit 34410b
	sbc_init_encoder(sbc_data);
Packit 34410b
Packit 34410b
	sbc_data->payload_len = payload_len;
Packit 34410b
Packit 34410b
	sbc_codec_calculate(sbc_data);
Packit 34410b
Packit 34410b
	*codec_data = sbc_data;
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool sbc_cleanup(void *codec_data)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
Packit 34410b
Packit 34410b
	sbc_finish(&sbc_data->enc);
Packit 34410b
	free(codec_data);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool sbc_get_config(void *codec_data, struct audio_input_config *config)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
Packit 34410b
Packit 34410b
	switch (sbc_data->sbc.frequency) {
Packit 34410b
	case SBC_SAMPLING_FREQ_16000:
Packit 34410b
		config->rate = 16000;
Packit 34410b
		break;
Packit 34410b
	case SBC_SAMPLING_FREQ_32000:
Packit 34410b
		config->rate = 32000;
Packit 34410b
		break;
Packit 34410b
	case SBC_SAMPLING_FREQ_44100:
Packit 34410b
		config->rate = 44100;
Packit 34410b
		break;
Packit 34410b
	case SBC_SAMPLING_FREQ_48000:
Packit 34410b
		config->rate = 48000;
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		return false;
Packit 34410b
	}
Packit 34410b
	config->channels = sbc_data->sbc.channel_mode == SBC_CHANNEL_MODE_MONO ?
Packit 34410b
				AUDIO_CHANNEL_OUT_MONO :
Packit 34410b
				AUDIO_CHANNEL_OUT_STEREO;
Packit 34410b
	config->format = AUDIO_FORMAT_PCM_16_BIT;
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static size_t sbc_get_buffer_size(void *codec_data)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
Packit 34410b
Packit 34410b
	return sbc_data->in_buf_size;
Packit 34410b
}
Packit 34410b
Packit 34410b
static size_t sbc_get_mediapacket_duration(void *codec_data)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
Packit 34410b
Packit 34410b
	return sbc_data->frame_duration * sbc_data->frames_per_packet;
Packit 34410b
}
Packit 34410b
Packit 34410b
static ssize_t sbc_encode_mediapacket(void *codec_data, const uint8_t *buffer,
Packit 34410b
					size_t len, struct media_packet *mp,
Packit 34410b
					size_t mp_data_len, size_t *written)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
Packit 34410b
	struct media_packet_sbc *mp_sbc = (struct media_packet_sbc *) mp;
Packit 34410b
	size_t consumed = 0;
Packit 34410b
	size_t encoded = 0;
Packit 34410b
	uint8_t frame_count = 0;
Packit 34410b
Packit 34410b
	mp_data_len -= sizeof(mp_sbc->payload);
Packit 34410b
Packit 34410b
	while (len - consumed >= sbc_data->in_frame_len &&
Packit 34410b
			mp_data_len - encoded >= sbc_data->out_frame_len &&
Packit 34410b
			frame_count < sbc_data->frames_per_packet) {
Packit 34410b
		ssize_t read;
Packit 34410b
		ssize_t written = 0;
Packit 34410b
Packit 34410b
		read = sbc_encode(&sbc_data->enc, buffer + consumed,
Packit 34410b
				sbc_data->in_frame_len, mp_sbc->data + encoded,
Packit 34410b
				mp_data_len - encoded, &written);
Packit 34410b
Packit 34410b
		if (read < 0) {
Packit 34410b
			error("SBC: failed to encode block at frame %d (%zd)",
Packit 34410b
							frame_count, read);
Packit 34410b
			break;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		frame_count++;
Packit 34410b
		consumed += read;
Packit 34410b
		encoded += written;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	*written = encoded + sizeof(mp_sbc->payload);
Packit 34410b
	mp_sbc->payload.frame_count = frame_count;
Packit 34410b
Packit 34410b
	return consumed;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool sbc_update_qos(void *codec_data, uint8_t op)
Packit 34410b
{
Packit 34410b
	struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
Packit 34410b
	uint8_t curr_bitpool = sbc_data->enc.bitpool;
Packit 34410b
	uint8_t new_bitpool = curr_bitpool;
Packit 34410b
Packit 34410b
	switch (op) {
Packit 34410b
	case QOS_POLICY_DEFAULT:
Packit 34410b
		new_bitpool = sbc_data->sbc.max_bitpool;
Packit 34410b
		break;
Packit 34410b
Packit 34410b
	case QOS_POLICY_DECREASE:
Packit 34410b
		if (curr_bitpool > SBC_QUALITY_MIN_BITPOOL) {
Packit 34410b
			new_bitpool = curr_bitpool - SBC_QUALITY_STEP;
Packit 34410b
			if (new_bitpool < SBC_QUALITY_MIN_BITPOOL)
Packit 34410b
				new_bitpool = SBC_QUALITY_MIN_BITPOOL;
Packit 34410b
		}
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (new_bitpool == curr_bitpool)
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	sbc_data->enc.bitpool = new_bitpool;
Packit 34410b
Packit 34410b
	sbc_codec_calculate(sbc_data);
Packit 34410b
Packit 34410b
	info("SBC: bitpool changed: %d -> %d", curr_bitpool, new_bitpool);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static const struct audio_codec codec = {
Packit 34410b
	.type = A2DP_CODEC_SBC,
Packit 34410b
	.use_rtp = true,
Packit 34410b
Packit 34410b
	.get_presets = sbc_get_presets,
Packit 34410b
Packit 34410b
	.init = sbc_codec_init,
Packit 34410b
	.cleanup = sbc_cleanup,
Packit 34410b
	.get_config = sbc_get_config,
Packit 34410b
	.get_buffer_size = sbc_get_buffer_size,
Packit 34410b
	.get_mediapacket_duration = sbc_get_mediapacket_duration,
Packit 34410b
	.encode_mediapacket = sbc_encode_mediapacket,
Packit 34410b
	.update_qos = sbc_update_qos,
Packit 34410b
};
Packit 34410b
Packit 34410b
const struct audio_codec *codec_sbc(void)
Packit 34410b
{
Packit 34410b
	return &codec;
Packit 34410b
}