summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/hal-audio.c102
1 files changed, 57 insertions, 45 deletions
diff --git a/android/hal-audio.c b/android/hal-audio.c
index f6bc998f4..cf4951458 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -129,6 +129,7 @@ struct sbc_data {
size_t in_frame_len;
size_t in_buf_size;
+ size_t out_frame_len;
size_t out_buf_size;
uint8_t *out_buf;
@@ -417,6 +418,7 @@ static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
sbc_data->in_frame_len = in_frame_len;
sbc_data->in_buf_size = num_frames * in_frame_len;
+ sbc_data->out_frame_len = out_frame_len;
sbc_data->out_buf_size = hdr_len + num_frames * out_frame_len;
sbc_data->out_buf = calloc(1, sbc_data->out_buf_size);
@@ -536,75 +538,85 @@ static int write_media_packet(int fd, struct sbc_data *sbc_data,
return ret;
}
+static ssize_t sbc_encode_mediapacket(void *codec_data, const uint8_t *buffer,
+ size_t len, struct media_packet *mp,
+ size_t mp_data_len, size_t *written)
+{
+ struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
+ size_t consumed = 0;
+ size_t encoded = 0;
+ uint8_t frame_count = 0;
+
+ while (len - consumed >= sbc_data->in_frame_len &&
+ mp_data_len - encoded >= sbc_data->out_frame_len &&
+ frame_count < MAX_FRAMES_IN_PAYLOAD) {
+ ssize_t read;
+ ssize_t written = 0;
+
+ read = sbc_encode(&sbc_data->enc, buffer + consumed,
+ sbc_data->in_frame_len, mp->data + encoded,
+ mp_data_len - encoded, &written);
+
+ if (read < 0) {
+ error("SBC: failed to encode block at frame %d (%zd)",
+ frame_count, read);
+ break;
+ }
+
+ frame_count++;
+ consumed += read;
+ encoded += written;
+ }
+
+ *written = encoded;
+ mp->payload.frame_count = frame_count;
+
+ return consumed;
+}
+
static ssize_t sbc_write_data(void *codec_data, const void *buffer,
size_t bytes, int fd)
{
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
size_t consumed = 0;
- size_t encoded = 0;
struct media_packet *mp = (struct media_packet *) sbc_data->out_buf;
size_t free_space = sbc_data->out_buf_size - sizeof(*mp);
- int ret;
- ssize_t bytes_read;
mp->hdr.v = 2;
mp->hdr.pt = 1;
mp->hdr.ssrc = htonl(1);
- mp->hdr.timestamp = htonl(sbc_data->timestamp);
- mp->payload.frame_count = 0;
- while (bytes - consumed >= sbc_data->in_frame_len) {
- ssize_t written = 0;
+ while (consumed < bytes) {
+ size_t written = 0;
+ ssize_t read;
+ int ret;
- bytes_read = sbc_encode(&sbc_data->enc, buffer + consumed,
- sbc_data->in_frame_len,
- mp->data + encoded, free_space,
- &written);
+ read = sbc_encode_mediapacket(codec_data, buffer + consumed,
+ bytes - consumed, mp,
+ free_space,
+ &written);
- if (bytes_read < 0) {
- error("SBC: failed to encode block (%zd)", bytes_read);
- break;
+ if (read <= 0) {
+ error("sbc_encode_mediapacket failed (%zd)", read);
+ goto done;
}
- mp->payload.frame_count++;
+ consumed += read;
- consumed += bytes_read;
- encoded += written;
- free_space -= written;
+ mp->hdr.sequence_number = htons(sbc_data->seq++);
+ mp->hdr.timestamp = htonl(sbc_data->timestamp);
/* AudioFlinger provides PCM 16bit stereo only, thus sample size
* is always 4 bytes
*/
- sbc_data->timestamp += (bytes_read / 4);
+ sbc_data->timestamp += (read / 4);
- /* write data if we either filled media packed or encoded all
- * input data
- */
- if (mp->payload.frame_count == sbc_data->frames_per_packet ||
- bytes == consumed ||
- mp->payload.frame_count ==
- MAX_FRAMES_IN_PAYLOAD) {
- mp->hdr.sequence_number = htons(sbc_data->seq++);
-
- ret = write_media_packet(fd, sbc_data, mp, encoded);
- if (ret < 0)
- return ret;
-
- encoded = 0;
- free_space = sbc_data->out_buf_size - sizeof(*mp);
- mp->hdr.timestamp = htonl(sbc_data->timestamp);
- mp->payload.frame_count = 0;
- }
- }
-
- if (consumed != bytes) {
- /* we should encode all input data
- * if we did not, something went wrong but we can't really
- * handle this so this is just sanity check
- */
- error("SBC: failed to encode complete input buffer");
+ ret = write_media_packet(fd, sbc_data, mp, written);
+ if (ret < 0)
+ return ret;
}
+done:
/* we always assume that all data was processed and sent */
return bytes;
}