All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCV2 01/28] android/ipc: Add ipc_is_connected() check
@ 2014-06-04 14:17 Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 02/28] android/handsfree: Connect SCO audio on demand Andrei Emeltchenko
                   ` (26 more replies)
  0 siblings, 27 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

Checks that ipc is connected
---
 android/ipc.c | 5 +++++
 android/ipc.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/android/ipc.c b/android/ipc.c
index 8cd34ea..137e6f9 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -287,6 +287,11 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
 	return FALSE;
 }
 
+bool ipc_is_connected(struct ipc *ipc)
+{
+	return ipc->cmd_watch;
+}
+
 struct ipc *ipc_init(const char *path, size_t size, int max_service_id,
 					bool notifications,
 					ipc_disconnect_cb cb, void *cb_data)
diff --git a/android/ipc.h b/android/ipc.h
index cc4e92d..171a77c 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -36,6 +36,7 @@ struct ipc;
 
 typedef void (*ipc_disconnect_cb) (void *data);
 
+bool ipc_is_connected(struct ipc *ipc);
 struct ipc *ipc_init(const char *path, size_t size, int max_service_id,
 					bool notifications,
 					ipc_disconnect_cb cb, void *cb_data);
-- 
1.8.3.2


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

* [RFCV2 02/28] android/handsfree: Connect SCO audio on demand
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 03/28] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/handsfree.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index b530aa9..49e6a22 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -169,6 +169,8 @@ static GIOChannel *hsp_server = NULL;
 
 static GIOChannel *sco_server = NULL;
 
+static void bt_sco_connect(const void *buf, uint16_t len);
+
 static void device_set_state(uint8_t state)
 {
 	struct hal_ev_handsfree_conn_state ev;
@@ -892,6 +894,9 @@ static void connect_sco_cb(GIOChannel *chan, GError *err, gpointer user_data)
 							sco_watch_cb, NULL);
 
 	device_set_audio_state(HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED);
+
+	if (ipc_is_connected(sco_ipc))
+		bt_sco_connect(NULL, 0);
 }
 
 static bool connect_sco(void)
@@ -2577,8 +2582,12 @@ static void bt_sco_connect(const void *buf, uint16_t len)
 
 	DBG("");
 
-	if (!device.sco)
-		goto failed;
+	if (!device.sco) {
+		DBG("SCO is not established, connecting...");
+		if (!connect_audio())
+			goto failed;
+		return;
+	}
 
 	err = NULL;
 	if (!bt_io_get(device.sco, &err, BT_IO_OPT_MTU, &rsp.mtu,
-- 
1.8.3.2


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

* [RFCV2 03/28] android/hal-sco: Use nanosleep for SCO synchronization
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 02/28] android/handsfree: Connect SCO audio on demand Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 04/28] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 5888275..701d15e 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] 28+ messages in thread

* [RFCV2 04/28] android/hal-sco: Fixes for unreliable mtu
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 02/28] android/handsfree: Connect SCO audio on demand Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 03/28] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 05/28] android/hal-sco: Add SCO packet cache Andrei Emeltchenko
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 701d15e..ecf7a09 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] 28+ messages in thread

* [RFCV2 05/28] android/hal-sco: Add SCO packet cache
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (2 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 04/28] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 06/28] android/hal-sco: Make use of config parameter Andrei Emeltchenko
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 ecf7a09..f3ccb0d 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 */
@@ -650,6 +680,7 @@ failed:
 	if (out->resampler)
 		release_resampler(out->resampler);
 
+	free(out->cache);
 	free(out->downmix_buf);
 	free(out);
 	stream_out = NULL;
@@ -674,6 +705,7 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 	if (out->resampler)
 		release_resampler(out->resampler);
 
+	free(out->cache);
 	free(out->downmix_buf);
 	free(out);
 	sco_dev->out = NULL;
-- 
1.8.3.2


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

* [RFCV2 06/28] android/hal-sco: Make use of config parameter
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (3 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 05/28] android/hal-sco: Add SCO packet cache Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 07/28] android/hal-sco: Implement open input stream Andrei Emeltchenko
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 f3ccb0d..292ced2 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] 28+ messages in thread

* [RFCV2 07/28] android/hal-sco: Implement open input stream
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (4 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 06/28] android/hal-sco: Make use of config parameter Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 08/28] android/hal-sco: Check file descriptor >= 0 Andrei Emeltchenko
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 292ced2..162ce25 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;
 };
 
 /*
@@ -787,23 +795,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] 28+ messages in thread

* [RFCV2 08/28] android/hal-sco: Check file descriptor >= 0
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (5 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 07/28] android/hal-sco: Implement open input stream Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 09/28] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 162ce25..e905d6b 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -713,11 +713,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;
 	}
 
 	if (out->resampler)
-- 
1.8.3.2


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

* [RFCV2 09/28] android/hal-sco: Use global sco file descriptor
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (6 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 08/28] android/hal-sco: Check file descriptor >= 0 Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 10/28] android/haltest: Add open/close input stream commands Andrei Emeltchenko
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 e905d6b..31c93b4 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:
@@ -707,18 +708,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();
 
 	if (out->resampler)
 		release_resampler(out->resampler);
@@ -971,7 +984,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] 28+ messages in thread

* [RFCV2 10/28] android/haltest: Add open/close input stream commands
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (7 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 09/28] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 11/28] android/haltest: Add read command Andrei Emeltchenko
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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] 28+ messages in thread

* [RFCV2 11/28] android/haltest: Add read command.
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (8 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 10/28] android/haltest: Add open/close input stream commands Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 12/28] android/haltest: Add loop command Andrei Emeltchenko
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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] 28+ messages in thread

* [RFCV2 12/28] android/haltest: Add loop command
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (9 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 11/28] android/haltest: Add read command Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 13/28] android/hal-sco: Make debug more readable Andrei Emeltchenko
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 | 45 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 42 insertions(+), 3 deletions(-)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index b4c3506..39c3e3a 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_in);
+}
+
 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;
@@ -218,7 +227,7 @@ static void *playback_thread(void *data)
 		pthread_mutex_unlock(&outstream_mutex);
 	} while (len && w_len > 0);
 
-	if (in)
+	if (in && data != stream_in)
 		fclose(in);
 
 	pthread_mutex_lock(&state_mutex);
@@ -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] 28+ messages in thread

* [RFCV2 13/28] android/hal-sco: Make debug more readable
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (10 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 12/28] android/haltest: Add loop command Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 14/28] android/hal-sco: Fix memory leak Andrei Emeltchenko
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 31c93b4..42267e0 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] 28+ messages in thread

* [RFCV2 14/28] android/hal-sco: Fix memory leak
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (11 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 13/28] android/hal-sco: Make debug more readable Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 15/28] android/hal-sco: Implement read Andrei Emeltchenko
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

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

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 42267e0..943a541 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -729,8 +729,10 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 
 	close_sco_socket();
 
-	if (out->resampler)
+	if (out->resampler) {
 		release_resampler(out->resampler);
+		free(out->resample_buf);
+	}
 
 	free(out->cache);
 	free(out->downmix_buf);
-- 
1.8.3.2


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

* [RFCV2 15/28] android/hal-sco: Implement read
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (12 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 14/28] android/hal-sco: Fix memory leak Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 16/28] android/haltest: Implement read to file Andrei Emeltchenko
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 149 insertions(+), 2 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 943a541..2fa8fb7 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 {
@@ -910,12 +915,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)
@@ -933,6 +1035,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("");
 
@@ -970,10 +1074,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,
@@ -986,6 +1128,11 @@ 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] 28+ messages in thread

* [RFCV2 16/28] android/haltest: Implement read to file
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (13 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 15/28] android/hal-sco: Implement read Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 17/28] android/hal-sco: Connect SCO when opening input stream Andrei Emeltchenko
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 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 | 55 ++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index a52aefe..79058e0 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -167,6 +167,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 39c3e3a..b5fa926 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 = get_unaligned(&input[i]);
+
+		put_unaligned(mono, &sample[0]);
+		put_unaligned(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)];
+	short buffer[buffer_size_in / 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] 28+ messages in thread

* [RFCV2 17/28] android/hal-sco: Connect SCO when opening input stream
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (14 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 16/28] android/haltest: Implement read to file Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 18/28] android/haltest: Add sample rate parameter when opening audio streams Andrei Emeltchenko
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/hal-sco.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 2fa8fb7..06e0261 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -1038,7 +1038,12 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 	int chan_num, ret;
 	size_t resample_size;
 
-	DBG("");
+	DBG("config %p device flags 0x%02x", config, devices);
+
+	if (ipc_connect_sco() != SCO_STATUS_SUCCESS) {
+		error("sco: cannot get fd");
+		return -EIO;
+	}
 
 	in = calloc(1, sizeof(struct sco_stream_in));
 	if (!in)
-- 
1.8.3.2


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

* [RFCV2 18/28] android/haltest: Add sample rate parameter when opening audio streams
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (15 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 17/28] android/hal-sco: Connect SCO when opening input stream Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 19/28] android/hal-sco: Skip resampling for output stream with 8k Andrei Emeltchenko
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

Opening input/output audio streams makes use of config with sample rate.
---
 android/client/if-sco.c | 40 ++++++++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index b5fa926..555c6f9 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -442,10 +442,21 @@ static void stop_p(int argc, const char **argv)
 
 static void open_output_stream_p(int argc, const char **argv)
 {
+	struct audio_config *config;
 	int err;
 
 	RETURN_IF_NULL(if_audio_sco);
 
+	if (argc < 3) {
+		haltest_info("No sampling rate specified. Use default conf\n");
+		config = NULL;
+	} else {
+		config = calloc(1, sizeof(struct audio_config));
+		config->sample_rate = atoi(argv[2]);
+		config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+		config->format = AUDIO_FORMAT_PCM_16_BIT;
+	}
+
 	pthread_mutex_lock(&state_mutex);
 	if (current_state == STATE_PLAYING) {
 		haltest_error("Already playing!\n");
@@ -458,11 +469,11 @@ static void open_output_stream_p(int argc, const char **argv)
 						0,
 						AUDIO_DEVICE_OUT_ALL_SCO,
 						AUDIO_OUTPUT_FLAG_NONE,
-						NULL,
+						config,
 						&stream_out);
 	if (err < 0) {
 		haltest_error("open output stream returned %d\n", err);
-		return;
+		goto failed;
 	}
 
 	buffer_size = stream_out->common.get_buffer_size(&stream_out->common);
@@ -470,6 +481,9 @@ static void open_output_stream_p(int argc, const char **argv)
 		haltest_error("Invalid buffer size received!\n");
 	else
 		haltest_info("Using buffer size: %zu\n", buffer_size);
+failed:
+	if (config)
+		free(config);
 }
 
 static void close_output_stream_p(int argc, const char **argv)
@@ -490,10 +504,21 @@ static void close_output_stream_p(int argc, const char **argv)
 
 static void open_input_stream_p(int argc, const char **argv)
 {
+	struct audio_config *config;
 	int err;
 
 	RETURN_IF_NULL(if_audio_sco);
 
+	if (argc < 3) {
+		haltest_info("No sampling rate specified. Use default conf\n");
+		config = NULL;
+	} else {
+		config = calloc(1, sizeof(struct audio_config));
+		config->sample_rate = atoi(argv[2]);
+		config->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+		config->format = AUDIO_FORMAT_PCM_16_BIT;
+	}
+
 	pthread_mutex_lock(&state_mutex);
 	if (current_state == STATE_PLAYING) {
 		haltest_error("Already playing!\n");
@@ -505,11 +530,11 @@ static void open_input_stream_p(int argc, const char **argv)
 	err = if_audio_sco->open_input_stream(if_audio_sco,
 						0,
 						AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
-						NULL,
+						config,
 						&stream_in);
 	if (err < 0) {
 		haltest_error("open output stream returned %d\n", err);
-		return;
+		goto failed;
 	}
 
 	buffer_size_in = stream_in->common.get_buffer_size(&stream_in->common);
@@ -517,6 +542,9 @@ static void open_input_stream_p(int argc, const char **argv)
 		haltest_error("Invalid buffer size received!\n");
 	else
 		haltest_info("Using buffer size: %zu\n", buffer_size_in);
+failed:
+	if (config)
+		free(config);
 }
 
 static void close_input_stream_p(int argc, const char **argv)
@@ -693,8 +721,8 @@ static struct method methods[] = {
 	STD_METHOD(init),
 	STD_METHOD(cleanup),
 	STD_METHOD(open_output_stream),
-	STD_METHOD(close_output_stream),
-	STD_METHOD(open_input_stream),
+	STD_METHODH(close_output_stream, "sample_rate"),
+	STD_METHODH(open_input_stream, "sampling rate"),
 	STD_METHOD(close_input_stream),
 	STD_METHODH(play, "<path to pcm file>"),
 	STD_METHOD(read),
-- 
1.8.3.2


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

* [RFCV2 19/28] android/hal-sco: Skip resampling for output stream with 8k
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (16 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 18/28] android/haltest: Add sample rate parameter when opening audio streams Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 20/28] android/hal-sco: Skip resampling for input of 8k Andrei Emeltchenko
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

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

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 06e0261..e3d5242 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -659,6 +659,9 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 		return -ENOMEM;
 	}
 
+	if (out->cfg.rate == AUDIO_STREAM_SCO_RATE)
+		goto skip_resampler;
+
 	/* Channel numbers for resampler */
 	chan_num = 1;
 
@@ -691,7 +694,7 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 	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);
-
+skip_resampler:
 	*stream_out = &out->stream;
 	adev->out = out;
 
-- 
1.8.3.2


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

* [RFCV2 20/28] android/hal-sco: Skip resampling for input of 8k
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (17 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 19/28] android/hal-sco: Skip resampling for output stream with 8k Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 21/28] android/haltest: Correct check for similar buffer size Andrei Emeltchenko
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

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

diff --git a/android/hal-sco.c b/android/hal-sco.c
index e3d5242..5b05601 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -977,7 +977,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
 	size_t frame_num = bytes / frame_size;
 	size_t input_frame_num = frame_num;
 	void *read_buf = buffer;
-	size_t total, read_frames;
+	size_t total = bytes;
 	int ret;
 
 	DBG("Read from fd %d bytes %zu", sco_fd, bytes);
@@ -998,27 +998,29 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
 		}
 
 		read_buf = in->resample_buf;
-	}
 
-	total = input_frame_num * sizeof(int16_t) * 1;
+		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,
+	if (in->resampler) {
+		ret = in->resampler->resample_from_input(in->resampler,
 							in->resample_buf,
-							&read_frames,
+							&input_frame_num,
 							(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;
-	}
+		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);
+		DBG("resampler: remain %zd output %zd frames", input_frame_num,
+								frame_num);
+	}
 
 	return bytes;
 }
@@ -1084,6 +1086,9 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 
 	in->cfg.frame_num = IN_STREAM_FRAMES;
 
+	if (in->cfg.rate == AUDIO_STREAM_SCO_RATE)
+		goto skip_resampler;
+
 	/* Channel numbers for resampler */
 	chan_num = 1;
 
@@ -1111,7 +1116,7 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 	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);
-
+skip_resampler:
 	*stream_in = &in->stream;
 	sco_dev->in = in;
 
-- 
1.8.3.2


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

* [RFCV2 21/28] android/haltest: Correct check for similar buffer size
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (18 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 20/28] android/hal-sco: Skip resampling for input of 8k Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 22/28] android/haltest: Add mono to stereo conversion for loopback Andrei Emeltchenko
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

The new check takes into account number of channels.
---
 android/client/if-sco.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index 555c6f9..35ed3b0 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -354,16 +354,21 @@ fail:
 
 static void loop_p(int argc, const char **argv)
 {
+	int chan_out, chan_in;
+
 	RETURN_IF_NULL(if_audio_sco);
 	RETURN_IF_NULL(stream_out);
 	RETURN_IF_NULL(stream_in);
 
+	chan_out = popcount(stream_out->common.get_channels(&stream_out->common));
+	chan_in = popcount(stream_in->common.get_channels(&stream_in->common));
+
 	if (!buffer_size || !buffer_size_in) {
 		haltest_error("Invalid buffer sizes. Streams opened\n");
 		return;
 	}
 
-	if (buffer_size != buffer_size_in) {
+	if (buffer_size / chan_out != buffer_size_in / chan_in) {
 		haltest_error("read/write buffers differ, not supported\n");
 		return;
 	}
-- 
1.8.3.2


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

* [RFCV2 22/28] android/haltest: Add mono to stereo conversion for loopback
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (19 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 21/28] android/haltest: Correct check for similar buffer size Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 23/28] android/hal-sco: Choose buffer size Andrei Emeltchenko
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

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

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index 35ed3b0..b7377f4 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -174,10 +174,24 @@ static void prepare_sample(void)
 	sample_pos = 0;
 }
 
+static void mono_to_stereo_pcm16(const int16_t *in, int16_t *out, size_t samples)
+{
+	int16_t mono;
+	size_t i;
+
+	for (i = 0; i < samples; i++) {
+		mono = get_unaligned(&in[i]);
+
+		put_unaligned(mono, &out[2 * i]);
+		put_unaligned(mono, &out[2 * i + 1]);
+	}
+}
+
 static void *playback_thread(void *data)
 {
 	int (*filbuff_cb) (short*, void*);
 	short buffer[buffer_size / sizeof(short)];
+	short buffer_in[buffer_size_in / sizeof(short)];
 	size_t len = 0;
 	ssize_t w_len = 0;
 	FILE *in = data;
@@ -217,7 +231,19 @@ static void *playback_thread(void *data)
 
 		pthread_mutex_unlock(&state_mutex);
 
-		len = filbuff_cb(buffer, cb_data);
+		if (data == stream_in) {
+			int chan_in = popcount(stream_in->common.get_channels(&stream_in->common));
+			int chan_out = popcount(stream_out->common.get_channels(&stream_out->common));
+
+			len = filbuff_cb(buffer_in, cb_data);
+
+			if (chan_in == 1 && chan_out == 2) {
+				mono_to_stereo_pcm16(buffer_in,
+							buffer,
+							buffer_size_in / 2);
+			}
+		} else
+			len = filbuff_cb(buffer, cb_data);
 
 		pthread_mutex_lock(&outstream_mutex);
 		if (!stream_out) {
-- 
1.8.3.2


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

* [RFCV2 23/28] android/hal-sco: Choose buffer size
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (20 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 22/28] android/haltest: Add mono to stereo conversion for loopback Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 24/28] android/hal-sco: Add stream synchronization Andrei Emeltchenko
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

For 8k choose buffer size 576 which is multiple from 48 and 64.
---
 android/hal-sco.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 5b05601..fe0d98c 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -40,7 +40,7 @@
 
 #define OUT_BUFFER_SIZE			2560
 #define OUT_STREAM_FRAMES		2560
-#define IN_STREAM_FRAMES		/* 5292 */ 5120
+#define IN_STREAM_FRAMES		5292
 
 #define SOCKET_POLL_TIMEOUT_MS		500
 
@@ -490,6 +490,10 @@ static size_t out_get_buffer_size(const struct audio_stream *stream)
 	size_t size = audio_stream_frame_size(&out->stream.common) *
 							out->cfg.frame_num;
 
+	/* buffer size without resampling */
+	if (out->cfg.rate == AUDIO_STREAM_SCO_RATE)
+		size = 576 * 2;
+
 	DBG("buf size %zd", size);
 
 	return size;
@@ -836,6 +840,10 @@ static size_t in_get_buffer_size(const struct audio_stream *stream)
 	size_t size = audio_stream_frame_size(&in->stream.common) *
 							in->cfg.frame_num;
 
+	/* buffer size without resampling */
+	if (in->cfg.rate == AUDIO_STREAM_SCO_RATE)
+		size = 576;
+
 	DBG("buf size %zd", size);
 
 	return size;
-- 
1.8.3.2


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

* [RFCV2 24/28] android/hal-sco: Add stream synchronization
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (21 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 23/28] android/hal-sco: Choose buffer size Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 25/28] android/haltest: Refactor stop and closing streams Andrei Emeltchenko
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/hal-sco.c | 81 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 57 insertions(+), 24 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index fe0d98c..955f511 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -54,6 +54,9 @@ static pthread_mutex_t sco_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_t ipc_th = 0;
 static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+static struct sco_stream_in *sco_stream_in = NULL;
+static struct sco_stream_out *sco_stream_out = NULL;
+
 struct sco_audio_config {
 	uint32_t rate;
 	uint32_t channels;
@@ -78,6 +81,18 @@ struct sco_stream_out {
 	uint32_t resample_frame_num;
 };
 
+static void sco_close_socket(void)
+{
+	DBG("sco fd %d", sco_fd);
+
+	if (sco_fd < 0)
+		return;
+
+	shutdown(sco_fd, SHUT_RDWR);
+	close(sco_fd);
+	sco_fd = -1;
+}
+
 struct sco_stream_in {
 	struct audio_stream_in stream;
 
@@ -428,6 +443,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 
 	DBG("write to fd %d bytes %zu", sco_fd, bytes);
 
+	if (sco_fd < 0)
+		return -1;
+
 	if (!out->downmix_buf) {
 		error("sco: downmix buffer not initialized");
 		return -1;
@@ -606,17 +624,22 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 
 	DBG("config %p device flags 0x%02x", config, devices);
 
+	if (sco_stream_out) {
+		DBG("stream_out already open");
+		return -EIO;
+	}
+
 	if (ipc_connect_sco() != SCO_STATUS_SUCCESS) {
 		error("sco: cannot get fd");
 		return -EIO;
 	}
 
-	DBG("got sco fd %d mtu %u", sco_fd, sco_mtu);
-
 	out = calloc(1, sizeof(struct sco_stream_out));
 	if (!out)
 		return -ENOMEM;
 
+	DBG("stream %p sco fd %d mtu %u", out, sco_fd, sco_mtu);
+
 	out->stream.common.get_sample_rate = out_get_sample_rate;
 	out->stream.common.set_sample_rate = out_set_sample_rate;
 	out->stream.common.get_buffer_size = out_get_buffer_size;
@@ -701,6 +724,7 @@ static int sco_open_output_stream(struct audio_hw_device *dev,
 skip_resampler:
 	*stream_out = &out->stream;
 	adev->out = out;
+	sco_stream_out = out;
 
 	return 0;
 failed:
@@ -712,25 +736,11 @@ failed:
 	free(out);
 	stream_out = NULL;
 	adev->out = NULL;
+	sco_stream_out = NULL;
 
 	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)
 {
@@ -739,8 +749,6 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 
 	DBG("dev %p stream %p fd %d", dev, out, sco_fd);
 
-	close_sco_socket();
-
 	if (out->resampler) {
 		release_resampler(out->resampler);
 		free(out->resample_buf);
@@ -750,6 +758,15 @@ static void sco_close_output_stream(struct audio_hw_device *dev,
 	free(out->downmix_buf);
 	free(out);
 	sco_dev->out = NULL;
+
+	pthread_mutex_lock(&sco_mutex);
+
+	sco_stream_out = NULL;
+
+	if (!sco_stream_in)
+		sco_close_socket();
+
+	pthread_mutex_unlock(&sco_mutex);
 }
 
 static int sco_set_parameters(struct audio_hw_device *dev,
@@ -990,6 +1007,9 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
 
 	DBG("Read from fd %d bytes %zu", sco_fd, bytes);
 
+	if (sco_fd < 0)
+		return -1;
+
 	if (!in->resampler && in->cfg.rate != AUDIO_STREAM_SCO_RATE) {
 		error("Cannot find resampler");
 		return -1;
@@ -1053,15 +1073,18 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 
 	DBG("config %p device flags 0x%02x", config, devices);
 
-	if (ipc_connect_sco() != SCO_STATUS_SUCCESS) {
-		error("sco: cannot get fd");
-		return -EIO;
+	if (sco_stream_in) {
+		DBG("stream_in already open");
+		ret = -EIO;
+		goto failed2;
 	}
 
 	in = calloc(1, sizeof(struct sco_stream_in));
 	if (!in)
 		return -ENOMEM;
 
+	DBG("stream %p sco fd %d mtu %u", in, sco_fd, sco_mtu);
+
 	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;
@@ -1127,14 +1150,17 @@ static int sco_open_input_stream(struct audio_hw_device *dev,
 skip_resampler:
 	*stream_in = &in->stream;
 	sco_dev->in = in;
+	sco_stream_in = in;
 
 	return 0;
 failed:
 	if (in->resampler)
 		release_resampler(in->resampler);
 	free(in);
+failed2:
 	stream_in = NULL;
 	sco_dev->in = NULL;
+	sco_stream_in = NULL;
 
 	return ret;
 }
@@ -1147,8 +1173,6 @@ static void sco_close_input_stream(struct audio_hw_device *dev,
 
 	DBG("dev %p stream %p fd %d", dev, in, sco_fd);
 
-	close_sco_socket();
-
 	if (in->resampler) {
 		release_resampler(in->resampler);
 		free(in->resample_buf);
@@ -1156,6 +1180,15 @@ static void sco_close_input_stream(struct audio_hw_device *dev,
 
 	free(in);
 	sco_dev->in = NULL;
+
+	pthread_mutex_lock(&sco_mutex);
+
+	sco_stream_in = NULL;
+
+	if (!sco_stream_out)
+		sco_close_socket();
+
+	pthread_mutex_unlock(&sco_mutex);
 }
 
 static int sco_dump(const audio_hw_device_t *device, int fd)
-- 
1.8.3.2


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

* [RFCV2 25/28] android/haltest: Refactor stop and closing streams
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (22 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 24/28] android/hal-sco: Add stream synchronization Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 26/28] android/hal-sco: Connect SCO audio on demand Andrei Emeltchenko
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/client/if-sco.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/android/client/if-sco.c b/android/client/if-sco.c
index b7377f4..6983f4e 100644
--- a/android/client/if-sco.c
+++ b/android/client/if-sco.c
@@ -455,6 +455,9 @@ static void read_p(int argc, const char **argv)
 
 static void stop_p(int argc, const char **argv)
 {
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(play_thread);
+
 	pthread_mutex_lock(&state_mutex);
 	if (current_state == STATE_STOPPED || current_state == STATE_STOPPING) {
 		pthread_mutex_unlock(&state_mutex);
@@ -464,6 +467,9 @@ static void stop_p(int argc, const char **argv)
 	current_state = STATE_STOPPING;
 	pthread_mutex_unlock(&state_mutex);
 
+	pthread_join(play_thread, NULL);
+	play_thread = 0;
+
 	pthread_mutex_lock(&outstream_mutex);
 	stream_out->common.standby(&stream_out->common);
 	pthread_mutex_unlock(&outstream_mutex);
@@ -522,10 +528,8 @@ static void close_output_stream_p(int argc, const char **argv)
 	RETURN_IF_NULL(if_audio_sco);
 	RETURN_IF_NULL(stream_out);
 
-	stop_p(argc, argv);
-
-	haltest_info("Waiting for playback thread...\n");
-	pthread_join(play_thread, NULL);
+	if (play_thread)
+		stop_p(argc, argv);
 
 	if_audio_sco->close_output_stream(if_audio_sco, stream_out);
 
@@ -583,10 +587,8 @@ 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 (play_thread)
+		stop_p(argc, argv);
 
 	if_audio_sco->close_input_stream(if_audio_sco, stream_in);
 
-- 
1.8.3.2


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

* [RFCV2 26/28] android/hal-sco: Connect SCO audio on demand
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (23 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 25/28] android/haltest: Refactor stop and closing streams Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 27/28] android/hal-sco: Disconnect SCO audio on standby() Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 28/28] android/handsfree: Refactor SCO audio connect sequence Andrei Emeltchenko
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

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

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 955f511..b4667e5 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -280,15 +280,16 @@ failed:
 
 static int ipc_connect_sco(void)
 {
-	struct sco_rsp_connect rsp;
-	size_t rsp_len = sizeof(rsp);
 	int ret = SCO_STATUS_SUCCESS;
 
-	DBG("");
-
 	pthread_mutex_lock(&sco_mutex);
 
 	if (sco_fd < 0) {
+		struct sco_rsp_connect rsp;
+		size_t rsp_len = sizeof(rsp);
+
+		DBG("Connecting SCO");
+
 		ret = sco_ipc_cmd(SCO_SERVICE_ID, SCO_OP_CONNECT, 0, NULL,
 						&rsp_len, &rsp, &sco_fd);
 
@@ -443,7 +444,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 
 	DBG("write to fd %d bytes %zu", sco_fd, bytes);
 
-	if (sco_fd < 0)
+	if (ipc_connect_sco() != SCO_STATUS_SUCCESS)
 		return -1;
 
 	if (!out->downmix_buf) {
@@ -1007,7 +1008,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
 
 	DBG("Read from fd %d bytes %zu", sco_fd, bytes);
 
-	if (sco_fd < 0)
+	if (ipc_connect_sco() != SCO_STATUS_SUCCESS)
 		return -1;
 
 	if (!in->resampler && in->cfg.rate != AUDIO_STREAM_SCO_RATE) {
-- 
1.8.3.2


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

* [RFCV2 27/28] android/hal-sco: Disconnect SCO audio on standby()
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (24 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 26/28] android/hal-sco: Connect SCO audio on demand Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  2014-06-04 14:17 ` [RFCV2 28/28] android/handsfree: Refactor SCO audio connect sequence Andrei Emeltchenko
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/hal-sco.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index b4667e5..fc12b50 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -545,7 +545,11 @@ static int out_set_format(struct audio_stream *stream, audio_format_t format)
 
 static int out_standby(struct audio_stream *stream)
 {
-	DBG("");
+	DBG("stream %p", stream);
+
+	pthread_mutex_lock(&sco_mutex);
+	sco_close_socket();
+	pthread_mutex_unlock(&sco_mutex);
 
 	return 0;
 }
-- 
1.8.3.2


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

* [RFCV2 28/28] android/handsfree: Refactor SCO audio connect sequence
  2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
                   ` (25 preceding siblings ...)
  2014-06-04 14:17 ` [RFCV2 27/28] android/hal-sco: Disconnect SCO audio on standby() Andrei Emeltchenko
@ 2014-06-04 14:17 ` Andrei Emeltchenko
  26 siblings, 0 replies; 28+ messages in thread
From: Andrei Emeltchenko @ 2014-06-04 14:17 UTC (permalink / raw)
  To: linux-bluetooth

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

Use connect_pending to identify when we need to return msg to HAL.
---
 android/handsfree.c | 41 ++++++++++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 49e6a22..28fcb2c 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -169,7 +169,8 @@ static GIOChannel *hsp_server = NULL;
 
 static GIOChannel *sco_server = NULL;
 
-static void bt_sco_connect(const void *buf, uint16_t len);
+static bool connect_pending = false;
+static void bt_sco_connect_rsp(bool is_error);
 
 static void device_set_state(uint8_t state)
 {
@@ -896,7 +897,7 @@ static void connect_sco_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	device_set_audio_state(HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED);
 
 	if (ipc_is_connected(sco_ipc))
-		bt_sco_connect(NULL, 0);
+		bt_sco_connect_rsp(false);
 }
 
 static bool connect_sco(void)
@@ -2574,22 +2575,22 @@ static void disable_sco_server(void)
 	}
 }
 
-static void bt_sco_connect(const void *buf, uint16_t len)
+static void bt_sco_connect_rsp(bool is_error)
 {
 	int fd;
-	GError *err;
+	GError *err = NULL;
 	struct sco_rsp_connect rsp;
 
-	DBG("");
+	DBG("error %d pending %d", is_error, connect_pending);
 
-	if (!device.sco) {
-		DBG("SCO is not established, connecting...");
-		if (!connect_audio())
-			goto failed;
+	if (!connect_pending)
 		return;
-	}
 
-	err = NULL;
+	connect_pending = false;
+
+	if (is_error)
+		goto failed;
+
 	if (!bt_io_get(device.sco, &err, BT_IO_OPT_MTU, &rsp.mtu,
 							BT_IO_OPT_INVALID)) {
 		error("Unable to get MTU: %s\n", err->message);
@@ -2610,6 +2611,24 @@ failed:
 	ipc_send_rsp(sco_ipc, SCO_SERVICE_ID, SCO_OP_STATUS, SCO_STATUS_FAILED);
 }
 
+static void bt_sco_connect(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	connect_pending = true;
+
+	if (!device.sco) {
+		DBG("SCO is not established, connecting...");
+		if (!connect_audio()) {
+			DBG("Connect audio failed");
+			return bt_sco_connect_rsp(true);
+		} else
+			return;
+	}
+
+	return bt_sco_connect_rsp(false);
+}
+
 static const struct ipc_handler sco_handlers[] = {
 	/* SCO_OP_CONNECT */
 	{ bt_sco_connect, false, 0 }
-- 
1.8.3.2


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

end of thread, other threads:[~2014-06-04 14:17 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-04 14:17 [RFCV2 01/28] android/ipc: Add ipc_is_connected() check Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 02/28] android/handsfree: Connect SCO audio on demand Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 03/28] android/hal-sco: Use nanosleep for SCO synchronization Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 04/28] android/hal-sco: Fixes for unreliable mtu Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 05/28] android/hal-sco: Add SCO packet cache Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 06/28] android/hal-sco: Make use of config parameter Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 07/28] android/hal-sco: Implement open input stream Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 08/28] android/hal-sco: Check file descriptor >= 0 Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 09/28] android/hal-sco: Use global sco file descriptor Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 10/28] android/haltest: Add open/close input stream commands Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 11/28] android/haltest: Add read command Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 12/28] android/haltest: Add loop command Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 13/28] android/hal-sco: Make debug more readable Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 14/28] android/hal-sco: Fix memory leak Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 15/28] android/hal-sco: Implement read Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 16/28] android/haltest: Implement read to file Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 17/28] android/hal-sco: Connect SCO when opening input stream Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 18/28] android/haltest: Add sample rate parameter when opening audio streams Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 19/28] android/hal-sco: Skip resampling for output stream with 8k Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 20/28] android/hal-sco: Skip resampling for input of 8k Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 21/28] android/haltest: Correct check for similar buffer size Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 22/28] android/haltest: Add mono to stereo conversion for loopback Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 23/28] android/hal-sco: Choose buffer size Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 24/28] android/hal-sco: Add stream synchronization Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 25/28] android/haltest: Refactor stop and closing streams Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 26/28] android/hal-sco: Connect SCO audio on demand Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 27/28] android/hal-sco: Disconnect SCO audio on standby() Andrei Emeltchenko
2014-06-04 14:17 ` [RFCV2 28/28] android/handsfree: Refactor SCO audio connect sequence Andrei Emeltchenko

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.