Diff between 089c397d7aabc63cca82fd56f579bf2537ea73f6 and 9dc257e9dbbef634479dd058ce136c83c9e3e8b0

Changed Files

File Additions Deletions Status
android/hal-audio.c +56 -30 modified

Full Patch

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 6104183..8271647 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -411,6 +411,42 @@ static void sbc_resume(void *codec_data)
 	sbc_data->frames_sent = 0;
 }
 
+static void write_media_packet(int fd, struct sbc_data *sbc_data,
+				struct media_packet *mp, size_t data_len)
+{
+	struct timespec cur;
+	struct timespec diff;
+	unsigned expected_frames;
+	int ret;
+
+	ret = write(fd, mp, sizeof(*mp) + data_len);
+	if (ret < 0) {
+		int err = errno;
+		DBG("error writing data: %d (%s)", err,
+						strerror(err));
+	}
+
+	sbc_data->frames_sent += mp->payload.frame_count;
+
+	clock_gettime(CLOCK_MONOTONIC, &cur);
+	timespec_diff(&cur, &sbc_data->start, &diff);
+	expected_frames = (diff.tv_sec * 1000000 + diff.tv_nsec / 1000) /
+						sbc_data->frame_duration;
+
+	/* AudioFlinger does not seem to provide any *working*
+	 * API to provide data in some interval and will just
+	 * send another buffer as soon as we process current
+	 * one. To prevent overflowing L2CAP socket, we need to
+	 * introduce some artificial delay here base on how many
+	 * audio frames were sent so far, i.e. if we're not
+	 * lagging behind audio stream, we can sleep for
+	 * duration of single media packet.
+	 */
+	if (sbc_data->frames_sent >= expected_frames)
+		usleep(sbc_data->frame_duration *
+				mp->payload.frame_count);
+}
+
 static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 				size_t bytes, int fd)
 {
@@ -419,9 +455,6 @@ static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 	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);
-	struct timespec cur;
-	struct timespec diff;
-	unsigned expected_frames;
 	int ret;
 
 	mp->hdr.v = 2;
@@ -448,39 +481,28 @@ static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 		consumed += ret;
 		encoded += written;
 		free_space -= written;
-	}
 
-	ret = write(fd, mp, sizeof(*mp) + encoded);
-	if (ret < 0) {
-		int err = errno;
-		DBG("error writing data: %d (%s)", err, strerror(err));
+		/* 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) {
+			write_media_packet(fd, sbc_data, mp, encoded);
+
+			encoded = 0;
+			free_space = sbc_data->out_buf_size - sizeof(*mp);
+			mp->payload.frame_count = 0;
+		}
 	}
 
-	if (consumed != bytes || free_space != 0) {
-		/* we should encode all input data and fill output buffer
+	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
 		 */
 		DBG("some data were not encoded");
 	}
 
-	sbc_data->frames_sent += mp->payload.frame_count;
-
-	clock_gettime(CLOCK_MONOTONIC, &cur);
-	timespec_diff(&cur, &sbc_data->start, &diff);
-	expected_frames = (diff.tv_sec * 1000000 + diff.tv_nsec / 1000) /
-				sbc_data->frame_duration;
-
-	/* AudioFlinger does not seem to provide any *working* API to provide
-	 * data in some interval and will just send another buffer as soon as
-	 * we process current one. To prevent overflowing L2CAP socket, we need
-	 * to introduce some artificial delay here base on how many audio frames
-	 * were sent so far, i.e. if we're not lagging behind audio stream, we
-	 * can sleep for duration of single media packet.
-	 */
-	if (sbc_data->frames_sent >= expected_frames)
-		usleep(sbc_data->frame_duration * mp->payload.frame_count);
-
 	/* we always assume that all data was processed and sent */
 	return bytes;
 }
@@ -844,11 +866,15 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
 
 static size_t out_get_buffer_size(const struct audio_stream *stream)
 {
-	struct a2dp_stream_out *out = (struct a2dp_stream_out *) stream;
-
 	DBG("");
 
-	return out->ep->codec->get_buffer_size(out->ep->codec_data);
+	/* We should return proper buffer size calculated by codec (so each
+	 * input buffer is encoded into single media packed) but this does not
+	 * work well with AudioFlinger and causes problems. For this reason we
+	 * use magic value here and out_write code takes care of splitting
+	 * input buffer into multiple media packets.
+	 */
+	return 20 * 512;
 }
 
 static uint32_t out_get_channels(const struct audio_stream *stream)