All of lore.kernel.org
 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

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

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

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

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

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.