linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization
@ 2014-05-22 12:05 Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 02/14] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:05 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/hal-sco.c | 56 +++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index ea9857e..fb7b4d4 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -64,6 +64,8 @@ struct sco_stream_out {
 	int fd;
 
 	uint8_t *downmix_buf;
+	size_t samples;
+	struct timespec start;
 
 	struct resampler_itfe *resampler;
 	int16_t *resample_buf;
@@ -277,6 +279,21 @@ static void downmix_to_mono(struct sco_stream_out *out, const uint8_t *buffer,
 	}
 }
 
+static uint64_t timespec_diff_us(struct timespec *a, struct timespec *b)
+{
+	struct timespec res;
+
+	res.tv_sec = a->tv_sec - b->tv_sec;
+	res.tv_nsec = a->tv_nsec - b->tv_nsec;
+
+	if (res.tv_nsec < 0) {
+		res.tv_sec--;
+		res.tv_nsec += 1000000000ll; /* 1sec */
+	}
+
+	return res.tv_sec * 1000000ll + res.tv_nsec / 1000ll;
+}
+
 static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 								size_t bytes)
 {
@@ -284,13 +301,13 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 	size_t len, written = 0;
 	int ret;
 	uint16_t mtu = /* out->cfg.mtu */ 48;
-	uint8_t read_buf[mtu];
-	bool do_write = false;
+	uint64_t audio_sent_us, audio_passed_us;
 
 	pfd.fd = out->fd;
 	pfd.events = POLLOUT | POLLIN | POLLHUP | POLLNVAL;
 
 	while (bytes > written) {
+		struct timespec now;
 
 		/* poll for sending */
 		if (poll(&pfd, 1, SOCKET_POLL_TIMEOUT_MS) == 0) {
@@ -303,27 +320,38 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 			return false;
 		}
 
-		/* FIXME synchronize by time instead of read() */
-		if (pfd.revents & POLLIN) {
-			ret = read(out->fd, read_buf, mtu);
-			if (ret < 0) {
-				error("Error reading fd %d (%s)", out->fd,
-							strerror(errno));
-				return false;
-			}
 
-			do_write = true;
+		clock_gettime(CLOCK_REALTIME, &now);
+		/* Mark start of the stream */
+		if (!out->samples)
+			memcpy(&out->start, &now, sizeof(out->start));
+
+		audio_sent_us = out->samples * 1000000ll / AUDIO_STREAM_SCO_RATE;
+		audio_passed_us = timespec_diff_us(&now, &out->start);
+		if ((int) (audio_sent_us - audio_passed_us) > 1500) {
+			struct timespec timeout = {0,
+						(audio_sent_us -
+						 audio_passed_us) * 1000};
+			DBG("Sleeping for %d ms",
+					(int) (audio_sent_us - audio_passed_us));
+			nanosleep(&timeout, NULL);
+		} else if ((int)(audio_passed_us - audio_sent_us) > 50000) {
+			DBG("\n\nResync\n\n");
+			out->samples = 0;
+			memcpy(&out->start, &now, sizeof(out->start));
 		}
 
-		if (!do_write)
-			continue;
 
 		len = bytes - written > mtu ? mtu : bytes - written;
 
 		ret = write(out->fd, buffer + written, len);
 		if (ret > 0) {
 			written += ret;
-			do_write = false;
+
+			out->samples += ret / 2;
+
+			DBG("written %d samples %zd total %zd bytes",
+					ret, out->samples, written);
 			continue;
 		}
 
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 02/14] android/hal-sco: Fixes for unreliable mtu
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
@ 2014-05-22 12:05 ` Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 03/14] android/hal-sco: Add SCO packet cache Andrei Emeltchenko
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:05 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/hal-sco.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index fb7b4d4..3c6e5bf 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -300,7 +300,7 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 	struct pollfd pfd;
 	size_t len, written = 0;
 	int ret;
-	uint16_t mtu = /* out->cfg.mtu */ 48;
+	uint16_t mtu = out->cfg.mtu;
 	uint64_t audio_sent_us, audio_passed_us;
 
 	pfd.fd = out->fd;
@@ -594,7 +594,9 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 	out->cfg.channels = AUDIO_CHANNEL_OUT_STEREO;
 	out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
 	out->cfg.frame_num = OUT_STREAM_FRAMES;
-	out->cfg.mtu = mtu;
+
+	/* we get wrong mtu size for some reason */
+	out->cfg.mtu = /* mtu */ 48;
 
 	out->downmix_buf = malloc(out_get_buffer_size(&out->stream.common));
 	if (!out->downmix_buf) {
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 03/14] android/hal-sco: Add SCO packet cache
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 02/14] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
@ 2014-05-22 12:05 ` Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 04/14] android/hal-sco: Make use of config parameter Andrei Emeltchenko
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:05 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

SCO cached is used when Android writes with packet sizes which cannot
fit to 48 bytes SCO frames. Remaining frames are cached and written next
time Android perform out->write().
---
 android/hal-sco.c | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 3c6e5bf..5cd63c2 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -64,6 +64,9 @@ struct sco_stream_out {
 	int fd;
 
 	uint8_t *downmix_buf;
+	uint8_t *cache;
+	size_t cache_len;
+
 	size_t samples;
 	struct timespec start;
 
@@ -301,6 +304,7 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 	size_t len, written = 0;
 	int ret;
 	uint16_t mtu = out->cfg.mtu;
+	uint8_t *p;
 	uint64_t audio_sent_us, audio_passed_us;
 
 	pfd.fd = out->fd;
@@ -320,6 +324,7 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 			return false;
 		}
 
+		len = bytes - written > mtu ? mtu : bytes - written;
 
 		clock_gettime(CLOCK_REALTIME, &now);
 		/* Mark start of the stream */
@@ -341,12 +346,30 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 			memcpy(&out->start, &now, sizeof(out->start));
 		}
 
+		if (out->cache_len) {
+			DBG("First packet cache_len %zd", out->cache_len);
+			memcpy(out->cache + out->cache_len, buffer,
+							mtu - out->cache_len);
+			p = out->cache;
+		}
 
-		len = bytes - written > mtu ? mtu : bytes - written;
+		if (bytes - written >= mtu)
+			p = (void *) buffer + written;
+		else {
+			memcpy(out->cache, buffer + written, bytes - written);
+			out->cache_len = bytes - written;
+			DBG("Last packet, cache %zd bytes", bytes - written);
+			written += bytes - written;
+			continue;
+		}
 
-		ret = write(out->fd, buffer + written, len);
+		ret = write(out->fd, p, len);
 		if (ret > 0) {
-			written += ret;
+			if (out->cache_len) {
+				written = mtu - out->cache_len;
+				out->cache_len = 0;
+			} else
+				written += ret;
 
 			out->samples += ret / 2;
 
@@ -604,6 +627,13 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 		return -ENOMEM;
 	}
 
+	out->cache = malloc(out->cfg.mtu);
+	if (!out->cache) {
+		free(out->downmix_buf);
+		free(out);
+		return -ENOMEM;
+	}
+
 	DBG("size %zd", out_get_buffer_size(&out->stream.common));
 
 	/* Channel numbers for resampler */
@@ -647,6 +677,7 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 
 	return 0;
 failed:
+	free(out->cache);
 	free(out->downmix_buf);
 	free(out);
 	stream_out = NULL;
@@ -668,6 +699,7 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 		sco_dev->out->fd = -1;
 	}
 
+	free(out->cache);
 	free(out->downmix_buf);
 	free(out);
 	sco_dev->out = NULL;
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 04/14] android/hal-sco: Make use of config parameter
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 02/14] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 03/14] android/hal-sco: Add SCO packet cache Andrei Emeltchenko
@ 2014-05-22 12:05 ` Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 05/14] android/hal-sco: Implement open input stream Andrei Emeltchenko
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:05 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Use config parameter when opening output stream.
---
 android/hal-sco.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 5cd63c2..402b184 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -582,7 +582,7 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 	size_t resample_size;
 	uint16_t mtu;
 
-	DBG("");
+	DBG("config %p device flags 0x%02x", config, devices);
 
 	if (ipc_connect_sco(&fd, &mtu) != SCO_STATUS_SUCCESS) {
 		error("sco: cannot get fd");
@@ -612,10 +612,20 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 	out->stream.write = out_write;
 	out->stream.get_render_position = out_get_render_position;
 
-	/* Configuration for Android */
-	out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
-	out->cfg.channels = AUDIO_CHANNEL_OUT_STEREO;
-	out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+	if (config) {
+		DBG("config: rate %u chan mask %x format %d offload %p",
+				config->sample_rate, config->channel_mask,
+				config->format, &config->offload_info);
+
+		out->cfg.format = config->format;
+		out->cfg.channels = config->channel_mask;
+		out->cfg.rate = config->sample_rate;
+	} else {
+		out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+		out->cfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+		out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+	}
+
 	out->cfg.frame_num = OUT_STREAM_FRAMES;
 
 	/* we get wrong mtu size for some reason */
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 05/14] android/hal-sco: Implement open input stream
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (2 preceding siblings ...)
  2014-05-22 12:05 ` [RFCv0 04/14] android/hal-sco: Make use of config parameter Andrei Emeltchenko
@ 2014-05-22 12:05 ` Andrei Emeltchenko
  2014-05-22 12:05 ` [RFCv0 06/14] android/hal-sco: Check file descriptor >= 0 Andrei Emeltchenko
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:05 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/hal-sco.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 173 insertions(+), 2 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 402b184..4ac5d00 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -75,9 +75,17 @@ struct sco_stream_out {
 	uint32_t resample_frame_num;
 };
 
+struct sco_stream_in {
+	struct audio_stream_in stream;
+
+	struct sco_audio_config cfg;
+	int fd;
+};
+
 struct sco_dev {
 	struct audio_hw_device dev;
 	struct sco_stream_out *out;
+	struct sco_stream_in *in;
 };
 
 /*
@@ -781,23 +789,186 @@ static size_t sco_get_input_buffer_size(const struct audio_hw_device *dev,
 	return -ENOSYS;
 }
 
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+	struct sco_stream_in *in = (struct sco_stream_in *) stream;
+
+	DBG("rate %u", in->cfg.rate);
+
+	return in->cfg.rate;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+	DBG("rate %u", rate);
+
+	return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+	struct sco_stream_in *in = (struct sco_stream_in *) stream;
+	size_t size = audio_stream_frame_size(&in->stream.common) *
+							in->cfg.frame_num;
+
+	DBG("buf size %zd", size);
+
+	return size;
+}
+
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+	struct sco_stream_in *in = (struct sco_stream_in *) stream;
+
+	DBG("channels num: %u", popcount(in->cfg.channels));
+
+	return in->cfg.channels;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+	struct sco_stream_in *in = (struct sco_stream_in *) stream;
+
+	DBG("format: %u", in->cfg.format);
+
+	return in->cfg.format;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+	DBG("");
+
+	return 0;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+	DBG("%s", kvpairs);
+
+	return 0;
+}
+
+static char *in_get_parameters(const struct audio_stream *stream,
+							const char *keys)
+{
+	DBG("");
+
+	return strdup("");
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
+								size_t bytes)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
 static int sco_open_input_stream(struct audio_hw_device *dev,
 					audio_io_handle_t handle,
 					audio_devices_t devices,
 					struct audio_config *config,
 					struct audio_stream_in **stream_in)
 {
+	struct sco_dev *sco_dev = (struct sco_dev *) dev;
+	struct sco_stream_in *in;
+
 	DBG("");
 
+	in = calloc(1, sizeof(struct sco_stream_in));
+	if (!in)
+		return -ENOMEM;
+
+	in->stream.common.get_sample_rate = in_get_sample_rate;
+	in->stream.common.set_sample_rate = in_set_sample_rate;
+	in->stream.common.get_buffer_size = in_get_buffer_size;
+	in->stream.common.get_channels = in_get_channels;
+	in->stream.common.get_format = in_get_format;
+	in->stream.common.set_format = in_set_format;
+	in->stream.common.standby = in_standby;
+	in->stream.common.dump = in_dump;
+	in->stream.common.set_parameters = in_set_parameters;
+	in->stream.common.get_parameters = in_get_parameters;
+	in->stream.common.add_audio_effect = in_add_audio_effect;
+	in->stream.common.remove_audio_effect = in_remove_audio_effect;
+	in->stream.set_gain = in_set_gain;
+	in->stream.read = in_read;
+	in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+	if (config) {
+		DBG("config: rate %u chan mask %x format %d offload %p",
+				config->sample_rate, config->channel_mask,
+				config->format, &config->offload_info);
+
+		in->cfg.format = config->format;
+		in->cfg.channels = config->channel_mask;
+		in->cfg.rate = config->sample_rate;
+	} else {
+		in->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+		in->cfg.channels = AUDIO_CHANNEL_OUT_MONO;
+		in->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+	}
+
+	*stream_in = &in->stream;
+	sco_dev->in = in;
+
 	return 0;
 }
 
 static void sco_close_input_stream(struct audio_hw_device *dev,
 					struct audio_stream_in *stream_in)
 {
-	DBG("");
+	struct sco_dev *sco_dev = (struct sco_dev *) dev;
+	struct sco_stream_in *in = (struct sco_stream_in *) stream_in;
+
+	DBG("dev %p stream %p fd %d", dev, in, in->fd);
 
-	free(stream_in);
+	free(in);
+	sco_dev->in = NULL;
 }
 
 static int sco_dump(const audio_hw_device_t *device, int fd)
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 06/14] android/hal-sco: Check file descriptor >= 0
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (3 preceding siblings ...)
  2014-05-22 12:05 ` [RFCv0 05/14] android/hal-sco: Implement open input stream Andrei Emeltchenko
@ 2014-05-22 12:05 ` Andrei Emeltchenko
  2014-05-22 12:06 ` [RFCv0 07/14] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:05 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/hal-sco.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 4ac5d00..e940547 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -710,11 +710,11 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 	struct sco_dev *sco_dev = (struct sco_dev *) dev;
 	struct sco_stream_out *out = (struct sco_stream_out *) stream_out;
 
-	DBG("dev %p stream %p fd %d", dev, stream_out, sco_dev->out->fd);
+	DBG("dev %p stream %p fd %d", dev, out, sco_dev->out->fd);
 
-	if (sco_dev->out && sco_dev->out->fd) {
-		close(sco_dev->out->fd);
-		sco_dev->out->fd = -1;
+	if (out && out->fd >= 0) {
+		close(out->fd);
+		out->fd = -1;
 	}
 
 	free(out->cache);
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 07/14] android/hal-sco: Use global sco file descriptor
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (4 preceding siblings ...)
  2014-05-22 12:05 ` [RFCv0 06/14] android/hal-sco: Check file descriptor >= 0 Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-27 13:08   ` Luiz Augusto von Dentz
  2014-05-22 12:06 ` [RFCv0 08/14] android/haltest: Add open/close input stream commands Andrei Emeltchenko
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Android may open input/output stream independently so we use global sco
file descriptor and mutexes.
---
 android/hal-sco.c | 85 ++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 50 insertions(+), 35 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index e940547..8c2549b 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -46,6 +46,10 @@
 static int listen_sk = -1;
 static int ipc_sk = -1;
 
+static int sco_fd = -1;
+static uint16_t sco_mtu = 0;
+static pthread_mutex_t sco_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 static pthread_t ipc_th = 0;
 static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -53,7 +57,6 @@ struct sco_audio_config {
 	uint32_t rate;
 	uint32_t channels;
 	uint32_t frame_num;
-	uint16_t mtu;
 	audio_format_t format;
 };
 
@@ -61,7 +64,6 @@ struct sco_stream_out {
 	struct audio_stream_out stream;
 
 	struct sco_audio_config cfg;
-	int fd;
 
 	uint8_t *downmix_buf;
 	uint8_t *cache;
@@ -79,7 +81,6 @@ struct sco_stream_in {
 	struct audio_stream_in stream;
 
 	struct sco_audio_config cfg;
-	int fd;
 };
 
 struct sco_dev {
@@ -257,18 +258,25 @@ failed:
 	return SCO_STATUS_FAILED;
 }
 
-static int ipc_connect_sco(int *fd, uint16_t *mtu)
+static int ipc_connect_sco(void)
 {
 	struct sco_rsp_connect rsp;
 	size_t rsp_len = sizeof(rsp);
-	int ret;
+	int ret = SCO_STATUS_SUCCESS;
 
 	DBG("");
 
-	ret = sco_ipc_cmd(SCO_SERVICE_ID, SCO_OP_CONNECT, 0, NULL, &rsp_len,
-								&rsp, fd);
+	pthread_mutex_lock(&sco_mutex);
+
+	if (sco_fd < 0) {
+		ret = sco_ipc_cmd(SCO_SERVICE_ID, SCO_OP_CONNECT, 0, NULL,
+						&rsp_len, &rsp, &sco_fd);
+
+		/* Sometimes mtu returned is wrong */
+		sco_mtu = /* rsp.mtu */ 48;
+	}
 
-	*mtu = rsp.mtu;
+	pthread_mutex_unlock(&sco_mutex);
 
 	return ret;
 }
@@ -311,28 +319,27 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 	struct pollfd pfd;
 	size_t len, written = 0;
 	int ret;
-	uint16_t mtu = out->cfg.mtu;
 	uint8_t *p;
 	uint64_t audio_sent_us, audio_passed_us;
 
-	pfd.fd = out->fd;
-	pfd.events = POLLOUT | POLLIN | POLLHUP | POLLNVAL;
+	pfd.fd = sco_fd;
+	pfd.events = POLLOUT | POLLHUP | POLLNVAL;
 
 	while (bytes > written) {
 		struct timespec now;
 
 		/* poll for sending */
 		if (poll(&pfd, 1, SOCKET_POLL_TIMEOUT_MS) == 0) {
-			DBG("timeout fd %d", out->fd);
+			DBG("timeout fd %d", sco_fd);
 			return false;
 		}
 
 		if (pfd.revents & (POLLHUP | POLLNVAL)) {
-			error("error fd %d, events 0x%x", out->fd, pfd.revents);
+			error("error fd %d, events 0x%x", sco_fd, pfd.revents);
 			return false;
 		}
 
-		len = bytes - written > mtu ? mtu : bytes - written;
+		len = bytes - written > sco_mtu ? sco_mtu : bytes - written;
 
 		clock_gettime(CLOCK_REALTIME, &now);
 		/* Mark start of the stream */
@@ -357,11 +364,11 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 		if (out->cache_len) {
 			DBG("First packet cache_len %zd", out->cache_len);
 			memcpy(out->cache + out->cache_len, buffer,
-							mtu - out->cache_len);
+						sco_mtu - out->cache_len);
 			p = out->cache;
 		}
 
-		if (bytes - written >= mtu)
+		if (bytes - written >= sco_mtu)
 			p = (void *) buffer + written;
 		else {
 			memcpy(out->cache, buffer + written, bytes - written);
@@ -371,10 +378,10 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 			continue;
 		}
 
-		ret = write(out->fd, p, len);
+		ret = write(sco_fd, p, len);
 		if (ret > 0) {
 			if (out->cache_len) {
-				written = mtu - out->cache_len;
+				written = sco_mtu - out->cache_len;
 				out->cache_len = 0;
 			} else
 				written += ret;
@@ -394,7 +401,7 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
 
 		if (errno != EINTR) {
 			ret = errno;
-			error("write failed (%d) fd %d bytes %zd", ret, out->fd,
+			error("write failed (%d) fd %d bytes %zd", ret, sco_fd,
 									bytes);
 			return false;
 		}
@@ -414,7 +421,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 	void *send_buf = out->downmix_buf;
 	size_t total;
 
-	DBG("write to fd %d bytes %zu", out->fd, bytes);
+	DBG("write to fd %d bytes %zu", sco_fd, bytes);
 
 	if (!out->downmix_buf) {
 		error("sco: downmix buffer not initialized");
@@ -585,19 +592,17 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 {
 	struct sco_dev *adev = (struct sco_dev *) dev;
 	struct sco_stream_out *out;
-	int fd = -1;
 	int chan_num, ret;
 	size_t resample_size;
-	uint16_t mtu;
 
 	DBG("config %p device flags 0x%02x", config, devices);
 
-	if (ipc_connect_sco(&fd, &mtu) != SCO_STATUS_SUCCESS) {
+	if (ipc_connect_sco() != SCO_STATUS_SUCCESS) {
 		error("sco: cannot get fd");
 		return -EIO;
 	}
 
-	DBG("got sco fd %d mtu %u", fd, mtu);
+	DBG("got sco fd %d mtu %u", sco_fd, sco_mtu);
 
 	out = calloc(1, sizeof(struct sco_stream_out));
 	if (!out)
@@ -636,16 +641,13 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 
 	out->cfg.frame_num = OUT_STREAM_FRAMES;
 
-	/* we get wrong mtu size for some reason */
-	out->cfg.mtu = /* mtu */ 48;
-
 	out->downmix_buf = malloc(out_get_buffer_size(&out->stream.common));
 	if (!out->downmix_buf) {
 		free(out);
 		return -ENOMEM;
 	}
 
-	out->cache = malloc(out->cfg.mtu);
+	out->cache = malloc(sco_mtu);
 	if (!out->cache) {
 		free(out->downmix_buf);
 		free(out);
@@ -691,7 +693,6 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 
 	*stream_out = &out->stream;
 	adev->out = out;
-	out->fd = fd;
 
 	return 0;
 failed:
@@ -704,18 +705,30 @@ failed:
 	return ret;
 }
 
+static void close_sco_socket(void)
+{
+	DBG("");
+
+	pthread_mutex_lock(&sco_mutex);
+
+	if (sco_fd >= 0) {
+		shutdown(sco_fd, SHUT_RDWR);
+		close(sco_fd);
+		sco_fd = -1;
+	}
+
+	pthread_mutex_unlock(&sco_mutex);
+}
+
 static void sco_close_output_stream(struct audio_hw_device *dev,
 					struct audio_stream_out *stream_out)
 {
 	struct sco_dev *sco_dev = (struct sco_dev *) dev;
 	struct sco_stream_out *out = (struct sco_stream_out *) stream_out;
 
-	DBG("dev %p stream %p fd %d", dev, out, sco_dev->out->fd);
+	DBG("dev %p stream %p fd %d", dev, out, sco_fd);
 
-	if (out && out->fd >= 0) {
-		close(out->fd);
-		out->fd = -1;
-	}
+	close_sco_socket();
 
 	free(out->cache);
 	free(out->downmix_buf);
@@ -965,7 +978,9 @@ static void sco_close_input_stream(struct audio_hw_device *dev,
 	struct sco_dev *sco_dev = (struct sco_dev *) dev;
 	struct sco_stream_in *in = (struct sco_stream_in *) stream_in;
 
-	DBG("dev %p stream %p fd %d", dev, in, in->fd);
+	DBG("dev %p stream %p fd %d", dev, in, sco_fd);
+
+	close_sco_socket();
 
 	free(in);
 	sco_dev->in = NULL;
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 08/14] android/haltest: Add open/close input stream commands
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (5 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 07/14] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-22 12:06 ` [RFCv0 09/14] android/haltest: Add read command Andrei Emeltchenko
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/client/if-sco.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index b7f5a80..c71d0b4 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -23,8 +23,10 @@
 
 audio_hw_device_t *if_audio_sco = NULL;
 static struct audio_stream_out *stream_out = NULL;
+static struct audio_stream_in *stream_in = NULL;
 
 static size_t buffer_size = 0;
+static size_t buffer_size_in = 0;
 static pthread_t play_thread = 0;
 static pthread_mutex_t outstream_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -340,6 +342,53 @@ static void close_output_stream_p(int argc, const char **argv)
 	buffer_size = 0;
 }
 
+static void open_input_stream_p(int argc, const char **argv)
+{
+	int err;
+
+	RETURN_IF_NULL(if_audio_sco);
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state == STATE_PLAYING) {
+		haltest_error("Already playing!\n");
+		pthread_mutex_unlock(&state_mutex);
+		return;
+	}
+	pthread_mutex_unlock(&state_mutex);
+
+	err = if_audio_sco->open_input_stream(if_audio_sco,
+						0,
+						AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+						NULL,
+						&stream_in);
+	if (err < 0) {
+		haltest_error("open output stream returned %d\n", err);
+		return;
+	}
+
+	buffer_size_in = stream_in->common.get_buffer_size(&stream_in->common);
+	if (buffer_size_in == 0)
+		haltest_error("Invalid buffer size received!\n");
+	else
+		haltest_info("Using buffer size: %zu\n", buffer_size_in);
+}
+
+static void close_input_stream_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_in);
+
+	stop_p(argc, argv);
+
+	haltest_info("Waiting for playback thread...\n");
+	pthread_join(play_thread, NULL);
+
+	if_audio_sco->close_input_stream(if_audio_sco, stream_in);
+
+	stream_in = NULL;
+	buffer_size_in = 0;
+}
+
 static void cleanup_p(int argc, const char **argv)
 {
 	int err;
@@ -499,6 +548,8 @@ static struct method methods[] = {
 	STD_METHOD(cleanup),
 	STD_METHOD(open_output_stream),
 	STD_METHOD(close_output_stream),
+	STD_METHOD(open_input_stream),
+	STD_METHOD(close_input_stream),
 	STD_METHODH(play, "<path to pcm file>"),
 	STD_METHOD(stop),
 	STD_METHOD(suspend),
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 09/14] android/haltest: Add read command.
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (6 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 08/14] android/haltest: Add open/close input stream commands Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-22 12:06 ` [RFCv0 10/14] android/haltest: Add loop command Andrei Emeltchenko
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Read command makes stream_in->read() call to Audio HAL.
---
 android/client/if-sco.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index c71d0b4..b4c3506 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -230,6 +230,45 @@ static void *playback_thread(void *data)
 	return NULL;
 }
 
+static void *read_thread(void *data)
+{
+	int (*filbuff_cb) (short*, void*) = feed_from_in;
+	short buffer[buffer_size / sizeof(short)];
+	size_t len = 0;
+	void *cb_data = NULL;
+
+	pthread_mutex_lock(&state_mutex);
+	current_state = STATE_PLAYING;
+	pthread_mutex_unlock(&state_mutex);
+
+	do {
+		pthread_mutex_lock(&state_mutex);
+
+		if (current_state == STATE_STOPPING) {
+			haltest_info("Detected stopping\n");
+			pthread_mutex_unlock(&state_mutex);
+			break;
+		} else if (current_state == STATE_SUSPENDED) {
+			pthread_mutex_unlock(&state_mutex);
+			usleep(500);
+			continue;
+		}
+
+		pthread_mutex_unlock(&state_mutex);
+
+		len = filbuff_cb(buffer, cb_data);
+		haltest_info("len %zd\n", len);
+	} while (len);
+
+	pthread_mutex_lock(&state_mutex);
+	current_state = STATE_STOPPED;
+	pthread_mutex_unlock(&state_mutex);
+
+	haltest_info("Done reading.\n");
+
+	return NULL;
+}
+
 static void play_p(int argc, const char **argv)
 {
 	const char *fname = NULL;
@@ -276,6 +315,30 @@ fail:
 		fclose(in);
 }
 
+static void read_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_in);
+
+	if (!buffer_size_in) {
+		haltest_error("Invalid buffer sizes. Streams opened\n");
+		return;
+	}
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state != STATE_STOPPED) {
+		haltest_error("Already playing or stream suspended!\n");
+		pthread_mutex_unlock(&state_mutex);
+		return;
+	}
+	pthread_mutex_unlock(&state_mutex);
+
+	if (pthread_create(&play_thread, NULL, read_thread,
+							stream_in) != 0)
+		haltest_error("Cannot create playback thread!\n");
+
+}
+
 static void stop_p(int argc, const char **argv)
 {
 	pthread_mutex_lock(&state_mutex);
@@ -551,6 +614,7 @@ static struct method methods[] = {
 	STD_METHOD(open_input_stream),
 	STD_METHOD(close_input_stream),
 	STD_METHODH(play, "<path to pcm file>"),
+	STD_METHOD(read),
 	STD_METHOD(stop),
 	STD_METHOD(suspend),
 	STD_METHOD(resume),
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 10/14] android/haltest: Add loop command
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (7 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 09/14] android/haltest: Add read command Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-22 12:06 ` [RFCv0 11/14] android/hal-sco: Make debug more readable Andrei Emeltchenko
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

loop command makes stream_in->read() and then stream_out->write(). At
the moment buffers shall be equal.
---
 android/client/if-sco.c | 43 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index b4c3506..87e2d79 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -148,6 +148,11 @@ static int feed_from_generator(short *buffer, void *data)
 	return buffer_size;
 }
 
+static int feed_from_in(short *buffer, void *data)
+{
+	return stream_in->read(stream_in, buffer, buffer_size);
+}
+
 static void prepare_sample(void)
 {
 	int x;
@@ -179,8 +184,12 @@ static void *playback_thread(void *data)
 
 	/* Use file or fall back to generator */
 	if (in) {
-		filbuff_cb = feed_from_file;
-		cb_data = in;
+		if (data == stream_in)
+			filbuff_cb = feed_from_in;
+		else {
+			filbuff_cb = feed_from_file;
+			cb_data = in;
+		}
 	} else {
 		prepare_sample();
 		filbuff_cb = feed_from_generator;
@@ -315,6 +324,35 @@ fail:
 		fclose(in);
 }
 
+static void loop_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+	RETURN_IF_NULL(stream_in);
+
+	if (!buffer_size || !buffer_size_in) {
+		haltest_error("Invalid buffer sizes. Streams opened\n");
+		return;
+	}
+
+	if (buffer_size != buffer_size_in) {
+		haltest_error("read/write buffers differ, not supported\n");
+		return;
+	}
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state != STATE_STOPPED) {
+		haltest_error("Already playing or stream suspended!\n");
+		pthread_mutex_unlock(&state_mutex);
+		return;
+	}
+	pthread_mutex_unlock(&state_mutex);
+
+	if (pthread_create(&play_thread, NULL, playback_thread,
+							stream_in) != 0)
+		haltest_error("Cannot create playback thread!\n");
+}
+
 static void read_p(int argc, const char **argv)
 {
 	RETURN_IF_NULL(if_audio_sco);
@@ -615,6 +653,7 @@ static struct method methods[] = {
 	STD_METHOD(close_input_stream),
 	STD_METHODH(play, "<path to pcm file>"),
 	STD_METHOD(read),
+	STD_METHOD(loop),
 	STD_METHOD(stop),
 	STD_METHOD(suspend),
 	STD_METHOD(resume),
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 11/14] android/hal-sco: Make debug more readable
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (8 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 10/14] android/haltest: Add loop command Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-22 12:06 ` [RFCv0 12/14] android/hal-sco: Fix memory leak Andrei Emeltchenko
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/hal-sco.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 8c2549b..8635866 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -654,8 +654,6 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 		return -ENOMEM;
 	}
 
-	DBG("size %zd", out_get_buffer_size(&out->stream.common));
-
 	/* Channel numbers for resampler */
 	chan_num = 1;
 
@@ -667,9 +665,6 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 		goto failed;
 	}
 
-	DBG("Created resampler: input rate [%d] output rate [%d] channels [%d]",
-				out->cfg.rate, AUDIO_STREAM_SCO_RATE, chan_num);
-
 	out->resample_frame_num = get_resample_frame_num(AUDIO_STREAM_SCO_RATE,
 							out->cfg.rate,
 							out->cfg.frame_num, 1);
@@ -688,8 +683,9 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 		goto failed;
 	}
 
-	DBG("resampler: frame num %u buf size %zd bytes",
-					out->resample_frame_num, resample_size);
+	DBG("Resampler: input %d output %d chan %d frames %u size %zd",
+				out->cfg.rate, AUDIO_STREAM_SCO_RATE, chan_num,
+				out->resample_frame_num, resample_size);
 
 	*stream_out = &out->stream;
 	adev->out = out;
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 12/14] android/hal-sco: Fix memory leak
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (9 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 11/14] android/hal-sco: Make debug more readable Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-27 13:40   ` Luiz Augusto von Dentz
  2014-05-22 12:06 ` [RFCv0 13/14] android/hal-sco: Implement read Andrei Emeltchenko
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Release resampler on exit.
---
 android/hal-sco.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 8635866..bf3b6d4 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -692,6 +692,8 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 
 	return 0;
 failed:
+	if (out->resampler)
+		release_resampler(out->resampler);
 	free(out->cache);
 	free(out->downmix_buf);
 	free(out);
@@ -726,6 +728,9 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 
 	close_sco_socket();
 
+	if (out->resampler)
+		release_resampler(out->resampler);
+	free(out->resample_buf);
 	free(out->cache);
 	free(out->downmix_buf);
 	free(out);
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 13/14] android/hal-sco: Implement read
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (10 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 12/14] android/hal-sco: Fix memory leak Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-22 12:06 ` [RFCv0 14/14] android/haltest: Implement read to file Andrei Emeltchenko
  2014-05-27 13:26 ` [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Luiz Augusto von Dentz
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Add read and resampling from 8000 to 44100.
---
 android/hal-sco.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 147 insertions(+), 2 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index bf3b6d4..8c40043 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -40,6 +40,7 @@
 
 #define OUT_BUFFER_SIZE			2560
 #define OUT_STREAM_FRAMES		2560
+#define IN_STREAM_FRAMES		/* 5292 */ 5120
 
 #define SOCKET_POLL_TIMEOUT_MS		500
 
@@ -81,6 +82,10 @@ struct sco_stream_in {
 	struct audio_stream_in stream;
 
 	struct sco_audio_config cfg;
+
+	struct resampler_itfe *resampler;
+	int16_t *resample_buf;
+	uint32_t resample_frame_num;
 };
 
 struct sco_dev {
@@ -907,12 +912,109 @@ static int in_set_gain(struct audio_stream_in *stream, float gain)
 	return -ENOSYS;
 }
 
+static bool read_data(struct sco_stream_in *in, char *buffer, size_t bytes)
+{
+	struct pollfd pfd;
+	size_t len, read_bytes = 0;
+
+	pfd.fd = sco_fd;
+	pfd.events = POLLIN | POLLHUP | POLLNVAL;
+
+	while (bytes > read_bytes) {
+		int ret;
+
+		/* poll for reading */
+		if (poll(&pfd, 1, SOCKET_POLL_TIMEOUT_MS) == 0) {
+			DBG("timeout fd %d", sco_fd);
+			return false;
+		}
+
+		if (pfd.revents & (POLLHUP | POLLNVAL)) {
+			error("error fd %d, events 0x%x", sco_fd, pfd.revents);
+			return false;
+		}
+
+		len = bytes - read_bytes > sco_mtu ? sco_mtu :
+							bytes - read_bytes;
+
+		ret = read(sco_fd, buffer + read_bytes, len);
+		if (ret > 0) {
+			read_bytes += ret;
+			DBG("read %d total %zd", ret, read_bytes);
+			continue;
+		}
+
+		if (errno == EAGAIN) {
+			ret = errno;
+			warn("read failed (%d)", ret);
+			continue;
+		}
+
+		if (errno != EINTR) {
+			ret = errno;
+			error("read failed (%d) fd %d bytes %zd", ret, sco_fd,
+									bytes);
+			return false;
+		}
+	}
+
+	DBG("read %zd bytes", read_bytes);
+
+	return true;
+}
+
 static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
 								size_t bytes)
 {
-	DBG("");
+	struct sco_stream_in *in = (struct sco_stream_in *) stream;
+	size_t frame_size = audio_stream_frame_size(&stream->common);
+	size_t frame_num = bytes / frame_size;
+	size_t input_frame_num = frame_num;
+	void *read_buf = buffer;
+	size_t total, read_frames;
+	int ret;
 
-	return -ENOSYS;
+	DBG("Read from fd %d bytes %zu", sco_fd, bytes);
+
+	if (!in->resampler && in->cfg.rate != AUDIO_STREAM_SCO_RATE) {
+		error("Cannot find resampler");
+		return -1;
+	}
+
+	if (in->resampler) {
+		input_frame_num = get_resample_frame_num(AUDIO_STREAM_SCO_RATE,
+							in->cfg.rate,
+							frame_num, 0);
+		if (input_frame_num > in->resample_frame_num) {
+			DBG("resize input frames from %zd to %d",
+				input_frame_num, in->resample_frame_num);
+			input_frame_num = in->resample_frame_num;
+		}
+
+		read_buf = in->resample_buf;
+	}
+
+	total = input_frame_num * sizeof(int16_t) * 1;
+
+	if(!read_data(in, read_buf, total))
+		return -1;
+
+	read_frames = input_frame_num;
+
+	ret = in->resampler->resample_from_input(in->resampler,
+							in->resample_buf,
+							&read_frames,
+							(int16_t *) buffer,
+							&frame_num);
+	if (ret) {
+		error("Failed to resample frames: %zd input %zd (%s)",
+				frame_num, input_frame_num, strerror(ret));
+		return -1;
+	}
+
+        DBG("resampler: remain %zd output %zd frames", read_frames, frame_num);
+
+	return bytes;
 }
 
 static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
@@ -930,6 +1032,8 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 {
 	struct sco_dev *sco_dev = (struct sco_dev *) dev;
 	struct sco_stream_in *in;
+	int chan_num, ret;
+	size_t resample_size;
 
 	DBG("");
 
@@ -967,10 +1071,48 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 		in->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
 	}
 
+	in->cfg.frame_num = IN_STREAM_FRAMES;
+
+	/* Channel numbers for resampler */
+	chan_num = 1;
+
+	ret = create_resampler(AUDIO_STREAM_SCO_RATE, in->cfg.rate, chan_num,
+						RESAMPLER_QUALITY_DEFAULT, NULL,
+						&in->resampler);
+	if (ret) {
+		error("Failed to create resampler (%s)", strerror(ret));
+		goto failed;
+	}
+
+	in->resample_frame_num = get_resample_frame_num(AUDIO_STREAM_SCO_RATE,
+							in->cfg.rate,
+							in->cfg.frame_num, 0);
+
+	resample_size = sizeof(int16_t) * chan_num * in->resample_frame_num;
+
+	in->resample_buf = malloc(resample_size);
+	if (!in->resample_buf) {
+		error("failed to allocate resample buffer for %d frames",
+							in->resample_frame_num);
+		goto failed;
+	}
+
+	DBG("Resampler: input %d output %d chan %d frames %u size %zd",
+				AUDIO_STREAM_SCO_RATE, in->cfg.rate, chan_num,
+				in->resample_frame_num, resample_size);
+
 	*stream_in = &in->stream;
 	sco_dev->in = in;
 
 	return 0;
+failed:
+	if (in->resampler)
+		release_resampler(in->resampler);
+	free(in);
+	stream_in = NULL;
+	sco_dev->in = NULL;
+
+	return ret;
 }
 
 static void sco_close_input_stream(struct audio_hw_device *dev,
@@ -983,6 +1125,9 @@ static void sco_close_input_stream(struct audio_hw_device *dev,
 
 	close_sco_socket();
 
+	if (in->resampler)
+		release_resampler(in->resampler);
+	free(in->resample_buf);
 	free(in);
 	sco_dev->in = NULL;
 }
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [RFCv0 14/14] android/haltest: Implement read to file
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (11 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 13/14] android/hal-sco: Implement read Andrei Emeltchenko
@ 2014-05-22 12:06 ` Andrei Emeltchenko
  2014-05-27 13:26 ` [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Luiz Augusto von Dentz
  13 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-22 12:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Reads data from stream_in and write to specified file.
---
 android/Android.mk      |  3 +++
 android/client/if-sco.c | 53 +++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index cc0f8f5..0da16b6 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -165,6 +165,9 @@ LOCAL_C_INCLUDES += \
 	$(call include-path-for, system-core) \
 	$(call include-path-for, libhardware) \
 
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/bluez/android \
+
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_SHARED_LIBRARIES := libhardware
diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index 87e2d79..d575d99 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -15,6 +15,8 @@
  *
  */
 
+#include "../src/shared/util.h"
+
 #include "if-main.h"
 #include "../hal-utils.h"
 #include "pthread.h"
@@ -239,12 +241,29 @@ static void *playback_thread(void *data)
 	return NULL;
 }
 
+static void write_stereo_pcm16(char *buffer, size_t len, FILE *out)
+{
+	const int16_t *input = (const void *) buffer;
+	int16_t sample[2];
+	size_t i;
+
+	for (i = 0; i < len / 2; i++) {
+		int16_t mono = le16_to_cpu(get_unaligned(&input[i]));
+
+		put_unaligned(cpu_to_le16(mono), &sample[0]);
+		put_unaligned(cpu_to_le16(mono), &sample[1]);
+
+		fwrite(sample, sizeof(sample), 1, out);
+	}
+}
+
 static void *read_thread(void *data)
 {
 	int (*filbuff_cb) (short*, void*) = feed_from_in;
 	short buffer[buffer_size / sizeof(short)];
 	size_t len = 0;
 	void *cb_data = NULL;
+	FILE *out = data;
 
 	pthread_mutex_lock(&state_mutex);
 	current_state = STATE_PLAYING;
@@ -266,9 +285,18 @@ static void *read_thread(void *data)
 		pthread_mutex_unlock(&state_mutex);
 
 		len = filbuff_cb(buffer, cb_data);
-		haltest_info("len %zd\n", len);
+
+		haltest_info("Read %zd bytes\n", len);
+
+		if (out) {
+			write_stereo_pcm16((char *) buffer, len, out);
+			haltest_info("Written %zd bytes\n", len * 2);
+		}
 	} while (len);
 
+	if (out)
+		fclose(out);
+
 	pthread_mutex_lock(&state_mutex);
 	current_state = STATE_STOPPED;
 	pthread_mutex_unlock(&state_mutex);
@@ -355,9 +383,26 @@ static void loop_p(int argc, const char **argv)
 
 static void read_p(int argc, const char **argv)
 {
+	const char *fname = NULL;
+	FILE *out = NULL;
+
 	RETURN_IF_NULL(if_audio_sco);
 	RETURN_IF_NULL(stream_in);
 
+	if (argc < 3) {
+		haltest_error("Invalid audio file path.\n");
+		haltest_info("Using read and through away\n");
+	} else {
+		fname = argv[2];
+		out = fopen(fname, "w");
+		if (!out) {
+			haltest_error("Cannot open file: %s\n", fname);
+			return;
+		}
+
+		haltest_info("Reading to file: %s\n", fname);
+	}
+
 	if (!buffer_size_in) {
 		haltest_error("Invalid buffer sizes. Streams opened\n");
 		return;
@@ -371,10 +416,10 @@ static void read_p(int argc, const char **argv)
 	}
 	pthread_mutex_unlock(&state_mutex);
 
-	if (pthread_create(&play_thread, NULL, read_thread,
-							stream_in) != 0)
+	if (pthread_create(&play_thread, NULL, read_thread, out) != 0) {
 		haltest_error("Cannot create playback thread!\n");
-
+		fclose(out);
+	}
 }
 
 static void stop_p(int argc, const char **argv)
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [RFCv0 07/14] android/hal-sco: Use global sco file descriptor
  2014-05-22 12:06 ` [RFCv0 07/14] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
@ 2014-05-27 13:08   ` Luiz Augusto von Dentz
  2014-05-28 10:24     ` Andrei Emeltchenko
  0 siblings, 1 reply; 19+ messages in thread
From: Luiz Augusto von Dentz @ 2014-05-27 13:08 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org

Hi Andrei,

On Thu, May 22, 2014 at 3:06 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Android may open input/output stream independently so we use global sco
> file descriptor and mutexes.
> ---
>  android/hal-sco.c | 85 ++++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 50 insertions(+), 35 deletions(-)
>
> diff --git a/android/hal-sco.c b/android/hal-sco.c
> index e940547..8c2549b 100644
> --- a/android/hal-sco.c
> +++ b/android/hal-sco.c
> @@ -46,6 +46,10 @@
>  static int listen_sk = -1;
>  static int ipc_sk = -1;
>
> +static int sco_fd = -1;
> +static uint16_t sco_mtu = 0;
> +static pthread_mutex_t sco_mutex = PTHREAD_MUTEX_INITIALIZER;
> +

Do we really need a mutex for this? I mean this is almost the same as
protecting the device itself for opening concurrent input and output,
if that is the case then I think it is better to put the mutex there.

>  static pthread_t ipc_th = 0;
>  static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
>
> @@ -53,7 +57,6 @@ struct sco_audio_config {
>         uint32_t rate;
>         uint32_t channels;
>         uint32_t frame_num;
> -       uint16_t mtu;
>         audio_format_t format;
>  };
>
> @@ -61,7 +64,6 @@ struct sco_stream_out {
>         struct audio_stream_out stream;
>
>         struct sco_audio_config cfg;
> -       int fd;
>
>         uint8_t *downmix_buf;
>         uint8_t *cache;
> @@ -79,7 +81,6 @@ struct sco_stream_in {
>         struct audio_stream_in stream;
>
>         struct sco_audio_config cfg;
> -       int fd;
>  };
>
>  struct sco_dev {
> @@ -257,18 +258,25 @@ failed:
>         return SCO_STATUS_FAILED;
>  }
>
> -static int ipc_connect_sco(int *fd, uint16_t *mtu)
> +static int ipc_connect_sco(void)
>  {
>         struct sco_rsp_connect rsp;
>         size_t rsp_len = sizeof(rsp);
> -       int ret;
> +       int ret = SCO_STATUS_SUCCESS;
>
>         DBG("");
>
> -       ret = sco_ipc_cmd(SCO_SERVICE_ID, SCO_OP_CONNECT, 0, NULL, &rsp_len,
> -                                                               &rsp, fd);
> +       pthread_mutex_lock(&sco_mutex);
> +
> +       if (sco_fd < 0) {
> +               ret = sco_ipc_cmd(SCO_SERVICE_ID, SCO_OP_CONNECT, 0, NULL,
> +                                               &rsp_len, &rsp, &sco_fd);
> +
> +               /* Sometimes mtu returned is wrong */
> +               sco_mtu = /* rsp.mtu */ 48;
> +       }
>
> -       *mtu = rsp.mtu;
> +       pthread_mutex_unlock(&sco_mutex);
>
>         return ret;
>  }
> @@ -311,28 +319,27 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>         struct pollfd pfd;
>         size_t len, written = 0;
>         int ret;
> -       uint16_t mtu = out->cfg.mtu;
>         uint8_t *p;
>         uint64_t audio_sent_us, audio_passed_us;
>
> -       pfd.fd = out->fd;
> -       pfd.events = POLLOUT | POLLIN | POLLHUP | POLLNVAL;
> +       pfd.fd = sco_fd;
> +       pfd.events = POLLOUT | POLLHUP | POLLNVAL;
>
>         while (bytes > written) {
>                 struct timespec now;
>
>                 /* poll for sending */
>                 if (poll(&pfd, 1, SOCKET_POLL_TIMEOUT_MS) == 0) {
> -                       DBG("timeout fd %d", out->fd);
> +                       DBG("timeout fd %d", sco_fd);
>                         return false;
>                 }
>
>                 if (pfd.revents & (POLLHUP | POLLNVAL)) {
> -                       error("error fd %d, events 0x%x", out->fd, pfd.revents);
> +                       error("error fd %d, events 0x%x", sco_fd, pfd.revents);
>                         return false;
>                 }
>
> -               len = bytes - written > mtu ? mtu : bytes - written;
> +               len = bytes - written > sco_mtu ? sco_mtu : bytes - written;
>
>                 clock_gettime(CLOCK_REALTIME, &now);
>                 /* Mark start of the stream */
> @@ -357,11 +364,11 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>                 if (out->cache_len) {
>                         DBG("First packet cache_len %zd", out->cache_len);
>                         memcpy(out->cache + out->cache_len, buffer,
> -                                                       mtu - out->cache_len);
> +                                               sco_mtu - out->cache_len);
>                         p = out->cache;
>                 }
>
> -               if (bytes - written >= mtu)
> +               if (bytes - written >= sco_mtu)
>                         p = (void *) buffer + written;
>                 else {
>                         memcpy(out->cache, buffer + written, bytes - written);
> @@ -371,10 +378,10 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>                         continue;
>                 }
>
> -               ret = write(out->fd, p, len);
> +               ret = write(sco_fd, p, len);
>                 if (ret > 0) {
>                         if (out->cache_len) {
> -                               written = mtu - out->cache_len;
> +                               written = sco_mtu - out->cache_len;
>                                 out->cache_len = 0;
>                         } else
>                                 written += ret;
> @@ -394,7 +401,7 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>
>                 if (errno != EINTR) {
>                         ret = errno;
> -                       error("write failed (%d) fd %d bytes %zd", ret, out->fd,
> +                       error("write failed (%d) fd %d bytes %zd", ret, sco_fd,
>                                                                         bytes);
>                         return false;
>                 }
> @@ -414,7 +421,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
>         void *send_buf = out->downmix_buf;
>         size_t total;
>
> -       DBG("write to fd %d bytes %zu", out->fd, bytes);
> +       DBG("write to fd %d bytes %zu", sco_fd, bytes);
>
>         if (!out->downmix_buf) {
>                 error("sco: downmix buffer not initialized");
> @@ -585,19 +592,17 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
>  {
>         struct sco_dev *adev = (struct sco_dev *) dev;
>         struct sco_stream_out *out;
> -       int fd = -1;
>         int chan_num, ret;
>         size_t resample_size;
> -       uint16_t mtu;
>
>         DBG("config %p device flags 0x%02x", config, devices);
>
> -       if (ipc_connect_sco(&fd, &mtu) != SCO_STATUS_SUCCESS) {
> +       if (ipc_connect_sco() != SCO_STATUS_SUCCESS) {
>                 error("sco: cannot get fd");
>                 return -EIO;
>         }
>
> -       DBG("got sco fd %d mtu %u", fd, mtu);
> +       DBG("got sco fd %d mtu %u", sco_fd, sco_mtu);
>
>         out = calloc(1, sizeof(struct sco_stream_out));
>         if (!out)
> @@ -636,16 +641,13 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
>
>         out->cfg.frame_num = OUT_STREAM_FRAMES;
>
> -       /* we get wrong mtu size for some reason */
> -       out->cfg.mtu = /* mtu */ 48;
> -
>         out->downmix_buf = malloc(out_get_buffer_size(&out->stream.common));
>         if (!out->downmix_buf) {
>                 free(out);
>                 return -ENOMEM;
>         }
>
> -       out->cache = malloc(out->cfg.mtu);
> +       out->cache = malloc(sco_mtu);
>         if (!out->cache) {
>                 free(out->downmix_buf);
>                 free(out);
> @@ -691,7 +693,6 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
>
>         *stream_out = &out->stream;
>         adev->out = out;
> -       out->fd = fd;
>
>         return 0;
>  failed:
> @@ -704,18 +705,30 @@ failed:
>         return ret;
>  }
>
> +static void close_sco_socket(void)
> +{
> +       DBG("");
> +
> +       pthread_mutex_lock(&sco_mutex);
> +
> +       if (sco_fd >= 0) {
> +               shutdown(sco_fd, SHUT_RDWR);
> +               close(sco_fd);
> +               sco_fd = -1;
> +       }
> +
> +       pthread_mutex_unlock(&sco_mutex);
> +}
> +
>  static void sco_close_output_stream(struct audio_hw_device *dev,
>                                         struct audio_stream_out *stream_out)
>  {
>         struct sco_dev *sco_dev = (struct sco_dev *) dev;
>         struct sco_stream_out *out = (struct sco_stream_out *) stream_out;
>
> -       DBG("dev %p stream %p fd %d", dev, out, sco_dev->out->fd);
> +       DBG("dev %p stream %p fd %d", dev, out, sco_fd);
>
> -       if (out && out->fd >= 0) {
> -               close(out->fd);
> -               out->fd = -1;
> -       }
> +       close_sco_socket();
>
>         free(out->cache);
>         free(out->downmix_buf);
> @@ -965,7 +978,9 @@ static void sco_close_input_stream(struct audio_hw_device *dev,
>         struct sco_dev *sco_dev = (struct sco_dev *) dev;
>         struct sco_stream_in *in = (struct sco_stream_in *) stream_in;
>
> -       DBG("dev %p stream %p fd %d", dev, in, in->fd);
> +       DBG("dev %p stream %p fd %d", dev, in, sco_fd);
> +
> +       close_sco_socket();
>
>         free(in);
>         sco_dev->in = NULL;
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization
  2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (12 preceding siblings ...)
  2014-05-22 12:06 ` [RFCv0 14/14] android/haltest: Implement read to file Andrei Emeltchenko
@ 2014-05-27 13:26 ` Luiz Augusto von Dentz
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Augusto von Dentz @ 2014-05-27 13:26 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org

Hi Andrei,

On Thu, May 22, 2014 at 3:05 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> ---
>  android/hal-sco.c | 56 +++++++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 42 insertions(+), 14 deletions(-)
>
> diff --git a/android/hal-sco.c b/android/hal-sco.c
> index ea9857e..fb7b4d4 100644
> --- a/android/hal-sco.c
> +++ b/android/hal-sco.c
> @@ -64,6 +64,8 @@ struct sco_stream_out {
>         int fd;
>
>         uint8_t *downmix_buf;
> +       size_t samples;
> +       struct timespec start;
>
>         struct resampler_itfe *resampler;
>         int16_t *resample_buf;
> @@ -277,6 +279,21 @@ static void downmix_to_mono(struct sco_stream_out *out, const uint8_t *buffer,
>         }
>  }
>
> +static uint64_t timespec_diff_us(struct timespec *a, struct timespec *b)
> +{
> +       struct timespec res;
> +
> +       res.tv_sec = a->tv_sec - b->tv_sec;
> +       res.tv_nsec = a->tv_nsec - b->tv_nsec;
> +
> +       if (res.tv_nsec < 0) {
> +               res.tv_sec--;
> +               res.tv_nsec += 1000000000ll; /* 1sec */
> +       }
> +
> +       return res.tv_sec * 1000000ll + res.tv_nsec / 1000ll;
> +}
> +
>  static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>                                                                 size_t bytes)
>  {
> @@ -284,13 +301,13 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>         size_t len, written = 0;
>         int ret;
>         uint16_t mtu = /* out->cfg.mtu */ 48;
> -       uint8_t read_buf[mtu];
> -       bool do_write = false;
> +       uint64_t audio_sent_us, audio_passed_us;
>
>         pfd.fd = out->fd;
>         pfd.events = POLLOUT | POLLIN | POLLHUP | POLLNVAL;
>
>         while (bytes > written) {
> +               struct timespec now;
>
>                 /* poll for sending */
>                 if (poll(&pfd, 1, SOCKET_POLL_TIMEOUT_MS) == 0) {
> @@ -303,27 +320,38 @@ static bool write_data(struct sco_stream_out *out, const uint8_t *buffer,
>                         return false;
>                 }
>
> -               /* FIXME synchronize by time instead of read() */
> -               if (pfd.revents & POLLIN) {
> -                       ret = read(out->fd, read_buf, mtu);
> -                       if (ret < 0) {
> -                               error("Error reading fd %d (%s)", out->fd,
> -                                                       strerror(errno));
> -                               return false;
> -                       }
>
> -                       do_write = true;
> +               clock_gettime(CLOCK_REALTIME, &now);

Im not sure why did you choose to got with CLOCK_REALTIME, we used
CLOCK_MONOTONIC on hal-audio.c for a very important reason because it
is nonsettable.

> +               /* Mark start of the stream */
> +               if (!out->samples)
> +                       memcpy(&out->start, &now, sizeof(out->start));
> +
> +               audio_sent_us = out->samples * 1000000ll / AUDIO_STREAM_SCO_RATE;
> +               audio_passed_us = timespec_diff_us(&now, &out->start);
> +               if ((int) (audio_sent_us - audio_passed_us) > 1500) {

What is 1500 for?

> +                       struct timespec timeout = {0,
> +                                               (audio_sent_us -
> +                                                audio_passed_us) * 1000};
> +                       DBG("Sleeping for %d ms",
> +                                       (int) (audio_sent_us - audio_passed_us));
> +                       nanosleep(&timeout, NULL);

Also we should use clock_nanosleep just as hal-audio.c.

> +               } else if ((int)(audio_passed_us - audio_sent_us) > 50000) {
> +                       DBG("\n\nResync\n\n");
> +                       out->samples = 0;
> +                       memcpy(&out->start, &now, sizeof(out->start));
>                 }
>
> -               if (!do_write)
> -                       continue;
>
>                 len = bytes - written > mtu ? mtu : bytes - written;
>
>                 ret = write(out->fd, buffer + written, len);
>                 if (ret > 0) {
>                         written += ret;
> -                       do_write = false;
> +
> +                       out->samples += ret / 2;
> +
> +                       DBG("written %d samples %zd total %zd bytes",
> +                                       ret, out->samples, written);
>                         continue;
>                 }
>
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFCv0 12/14] android/hal-sco: Fix memory leak
  2014-05-22 12:06 ` [RFCv0 12/14] android/hal-sco: Fix memory leak Andrei Emeltchenko
@ 2014-05-27 13:40   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 19+ messages in thread
From: Luiz Augusto von Dentz @ 2014-05-27 13:40 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org

Hi Andrei,

On Thu, May 22, 2014 at 3:06 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Release resampler on exit.
> ---
>  android/hal-sco.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/android/hal-sco.c b/android/hal-sco.c
> index 8635866..bf3b6d4 100644
> --- a/android/hal-sco.c
> +++ b/android/hal-sco.c
> @@ -692,6 +692,8 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
>
>         return 0;
>  failed:
> +       if (out->resampler)
> +               release_resampler(out->resampler);
>         free(out->cache);
>         free(out->downmix_buf);
>         free(out);
> @@ -726,6 +728,9 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
>
>         close_sco_socket();
>
> +       if (out->resampler)
> +               release_resampler(out->resampler);
> +       free(out->resample_buf);
>         free(out->cache);
>         free(out->downmix_buf);
>         free(out);
> --
> 1.8.3.2

Ive pushed just this one, please rebase this set.


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFCv0 07/14] android/hal-sco: Use global sco file descriptor
  2014-05-27 13:08   ` Luiz Augusto von Dentz
@ 2014-05-28 10:24     ` Andrei Emeltchenko
  2014-05-28 10:32       ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-28 10:24 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org

Hi Luiz,

On Tue, May 27, 2014 at 04:08:09PM +0300, Luiz Augusto von Dentz wrote:
> Hi Andrei,
> 
> On Thu, May 22, 2014 at 3:06 PM, Andrei Emeltchenko
> <Andrei.Emeltchenko.news@gmail.com> wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > Android may open input/output stream independently so we use global sco
> > file descriptor and mutexes.
> > ---
> >  android/hal-sco.c | 85 ++++++++++++++++++++++++++++++++-----------------------
> >  1 file changed, 50 insertions(+), 35 deletions(-)
> >
> > diff --git a/android/hal-sco.c b/android/hal-sco.c
> > index e940547..8c2549b 100644
> > --- a/android/hal-sco.c
> > +++ b/android/hal-sco.c
> > @@ -46,6 +46,10 @@
> >  static int listen_sk = -1;
> >  static int ipc_sk = -1;
> >
> > +static int sco_fd = -1;
> > +static uint16_t sco_mtu = 0;
> > +static pthread_mutex_t sco_mutex = PTHREAD_MUTEX_INITIALIZER;
> > +
> 
> Do we really need a mutex for this? I mean this is almost the same as
> protecting the device itself for opening concurrent input and output,
> if that is the case then I think it is better to put the mutex there.
> 

For some reason Android tries to open several input streams from different
threads. So input/output streams looks might be open/closed from different
threads.

Best regards 
Andrei Emeltchenko 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFCv0 07/14] android/hal-sco: Use global sco file descriptor
  2014-05-28 10:24     ` Andrei Emeltchenko
@ 2014-05-28 10:32       ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 19+ messages in thread
From: Luiz Augusto von Dentz @ 2014-05-28 10:32 UTC (permalink / raw)
  To: Andrei Emeltchenko, Luiz Augusto von Dentz,
	linux-bluetooth@vger.kernel.org

Hi Andrei,

On Wed, May 28, 2014 at 1:24 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> Hi Luiz,
>
> On Tue, May 27, 2014 at 04:08:09PM +0300, Luiz Augusto von Dentz wrote:
>> Hi Andrei,
>>
>> On Thu, May 22, 2014 at 3:06 PM, Andrei Emeltchenko
>> <Andrei.Emeltchenko.news@gmail.com> wrote:
>> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>> >
>> > Android may open input/output stream independently so we use global sco
>> > file descriptor and mutexes.
>> > ---
>> >  android/hal-sco.c | 85 ++++++++++++++++++++++++++++++++-----------------------
>> >  1 file changed, 50 insertions(+), 35 deletions(-)
>> >
>> > diff --git a/android/hal-sco.c b/android/hal-sco.c
>> > index e940547..8c2549b 100644
>> > --- a/android/hal-sco.c
>> > +++ b/android/hal-sco.c
>> > @@ -46,6 +46,10 @@
>> >  static int listen_sk = -1;
>> >  static int ipc_sk = -1;
>> >
>> > +static int sco_fd = -1;
>> > +static uint16_t sco_mtu = 0;
>> > +static pthread_mutex_t sco_mutex = PTHREAD_MUTEX_INITIALIZER;
>> > +
>>
>> Do we really need a mutex for this? I mean this is almost the same as
>> protecting the device itself for opening concurrent input and output,
>> if that is the case then I think it is better to put the mutex there.
>>
>
> For some reason Android tries to open several input streams from different
> threads. So input/output streams looks might be open/closed from different
> threads.

So the device itself has to be protected otherwise you risk having more mutexes.


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2014-05-28 10:32 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-22 12:05 [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
2014-05-22 12:05 ` [RFCv0 02/14] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
2014-05-22 12:05 ` [RFCv0 03/14] android/hal-sco: Add SCO packet cache Andrei Emeltchenko
2014-05-22 12:05 ` [RFCv0 04/14] android/hal-sco: Make use of config parameter Andrei Emeltchenko
2014-05-22 12:05 ` [RFCv0 05/14] android/hal-sco: Implement open input stream Andrei Emeltchenko
2014-05-22 12:05 ` [RFCv0 06/14] android/hal-sco: Check file descriptor >= 0 Andrei Emeltchenko
2014-05-22 12:06 ` [RFCv0 07/14] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
2014-05-27 13:08   ` Luiz Augusto von Dentz
2014-05-28 10:24     ` Andrei Emeltchenko
2014-05-28 10:32       ` Luiz Augusto von Dentz
2014-05-22 12:06 ` [RFCv0 08/14] android/haltest: Add open/close input stream commands Andrei Emeltchenko
2014-05-22 12:06 ` [RFCv0 09/14] android/haltest: Add read command Andrei Emeltchenko
2014-05-22 12:06 ` [RFCv0 10/14] android/haltest: Add loop command Andrei Emeltchenko
2014-05-22 12:06 ` [RFCv0 11/14] android/hal-sco: Make debug more readable Andrei Emeltchenko
2014-05-22 12:06 ` [RFCv0 12/14] android/hal-sco: Fix memory leak Andrei Emeltchenko
2014-05-27 13:40   ` Luiz Augusto von Dentz
2014-05-22 12:06 ` [RFCv0 13/14] android/hal-sco: Implement read Andrei Emeltchenko
2014-05-22 12:06 ` [RFCv0 14/14] android/haltest: Implement read to file Andrei Emeltchenko
2014-05-27 13:26 ` [RFCv0 01/14] android/hal-sco: Use nanosleep for SCO synchronization Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).