diff options
-rw-r--r-- | android/hal-audio.c | 102 |
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; } |