Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCHv3 00/12] SCO Audio interface for Android
@ 2014-05-08  8:01 Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling Andrei Emeltchenko
                   ` (11 more replies)
  0 siblings, 12 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

Changes:
	* v3: Refactored code following comments, renamed API commands
	to connect_sco instead of get_sco_fd. Better code split.

Andrei Emeltchenko (12):
  android/hal-sco: Add audio HAL for SCO handling
  android/hal-audio-hsp: Add open_output_stream()
  android/audio: Add Audio SCO message API
  android/handsfree: Add SCO Audio IPC
  android/hal-sco: Implement Audio IPC on Audio HAL
  android/ipc: Use error printing error messages
  android/haltest: Add testinng for audio SCO HAL
  android/audio: Add resampler support
  audio/haltest: Make audio_stream static
  android/audio: Add downmix support to audio SCO HAL
  android/audio: Use resampler interface to resample SCO
  android/audio: Add write to SCO

 android/Android.mk                            |  26 +
 android/Makefile.am                           |  20 +
 android/audio_utils/resampler.c               | 265 ++++++++
 android/audio_utils/resampler.h               | 109 +++
 android/client/haltest.c                      |   3 +
 android/client/{if-audio.c => if-audio-sco.c} |  60 +-
 android/client/if-audio.c                     |   2 +-
 android/client/if-main.h                      |   1 +
 android/hal-sco.c                             | 912 ++++++++++++++++++++++++++
 android/handsfree.c                           |  58 +-
 android/ipc.c                                 |  12 +-
 android/sco-ipc-api.txt                       |  36 +
 android/sco-msg.h                             |  36 +
 configure.ac                                  |   7 +
 14 files changed, 1510 insertions(+), 37 deletions(-)
 create mode 100644 android/audio_utils/resampler.c
 create mode 100644 android/audio_utils/resampler.h
 copy android/client/{if-audio.c => if-audio-sco.c} (90%)
 create mode 100644 android/hal-sco.c
 create mode 100644 android/sco-ipc-api.txt
 create mode 100644 android/sco-msg.h

-- 
1.8.3.2


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

* [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:55   ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream() Andrei Emeltchenko
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds audio HAL for handling SCO. Following needs to be added to
audio_policy.conf:

  sco {
    outputs {
      sco {
        ...
        devices AUDIO_DEVICE_OUT_ALL_SCO
        ...
      }
    }
---
 android/Android.mk  |  23 ++++++
 android/Makefile.am |  15 ++++
 android/hal-sco.c   | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 249 insertions(+)
 create mode 100644 android/hal-sco.c

diff --git a/android/Android.mk b/android/Android.mk
index 638a042..b7b284d 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -271,6 +271,29 @@ LOCAL_MODULE := audio.a2dp.default
 include $(BUILD_SHARED_LIBRARY)
 
 #
+# SCO audio
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bluez/android/hal-sco.c
+
+LOCAL_C_INCLUDES = \
+	$(call include-path-for, system-core) \
+	$(call include-path-for, libhardware) \
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := audio.sco.default
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
 # l2cap-test
 #
 
diff --git a/android/Makefile.am b/android/Makefile.am
index 5ab6411..990ce6b 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -169,6 +169,21 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
 					android/hardware/hardware.h \
 					android/system/audio.h
 
+android_audio_sco_default_la_SOURCES = android/audio-msg.h \
+					android/hal-msg.h \
+					android/hal-sco.c \
+					android/hardware/audio.h \
+					android/hardware/audio_effect.h \
+					android/hardware/hardware.h \
+					android/system/audio.h
+
+android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+
+android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+					-no-undefined -lrt
+
+plugin_LTLIBRARIES += android/audio.sco.default.la
+
 unit_tests += android/test-ipc
 
 android_test_ipc_SOURCES = android/test-ipc.c \
diff --git a/android/hal-sco.c b/android/hal-sco.c
new file mode 100644
index 0000000..c7ba504
--- /dev/null
+++ b/android/hal-sco.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+
+#include "hal-log.h"
+
+struct hsp_audio_dev {
+	struct audio_hw_device dev;
+	struct a2dp_stream_out *out;
+};
+
+static int audio_open_output_stream(struct audio_hw_device *dev,
+					audio_io_handle_t handle,
+					audio_devices_t devices,
+					audio_output_flags_t flags,
+					struct audio_config *config,
+					struct audio_stream_out **stream_out)
+
+{
+	DBG("");
+
+	return -EINVAL;
+}
+
+static void audio_close_output_stream(struct audio_hw_device *dev,
+					struct audio_stream_out *stream_out)
+{
+	DBG("");
+
+	free(stream_out);
+}
+
+static int audio_set_parameters(struct audio_hw_device *dev,
+							const char *kvpairs)
+{
+	DBG("%s", kvpairs);
+
+	return 0;
+}
+
+static char *audio_get_parameters(const struct audio_hw_device *dev,
+							const char *keys)
+{
+	DBG("");
+
+	return strdup("");
+}
+
+static int audio_init_check(const struct audio_hw_device *dev)
+{
+	DBG("");
+
+	return 0;
+}
+
+static int audio_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+	DBG("%f", volume);
+
+	return 0;
+}
+
+static int audio_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+	DBG("%f", volume);
+
+	return 0;
+}
+
+static int audio_set_mode(struct audio_hw_device *dev, int mode)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int audio_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int audio_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static size_t audio_get_input_buffer_size(const struct audio_hw_device *dev,
+					const struct audio_config *config)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int audio_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)
+{
+	DBG("");
+
+	return 0;
+}
+
+static void audio_close_input_stream(struct audio_hw_device *dev,
+					struct audio_stream_in *stream_in)
+{
+	DBG("");
+
+	free(stream_in);
+}
+
+static int audio_dump(const audio_hw_device_t *device, int fd)
+{
+	DBG("");
+
+	return 0;
+}
+
+static int audio_close(hw_device_t *device)
+{
+	DBG("");
+
+	free(device);
+
+	return 0;
+}
+
+static int audio_open(const hw_module_t *module, const char *name,
+							hw_device_t **device)
+{
+	struct hsp_audio_dev *adev;
+
+	DBG("");
+
+	if (strcmp(name, AUDIO_HARDWARE_INTERFACE)) {
+		error("audio: interface %s not matching [%s]", name,
+						AUDIO_HARDWARE_INTERFACE);
+		return -EINVAL;
+	}
+
+	adev = calloc(1, sizeof(struct hsp_audio_dev));
+	if (!adev)
+		return -ENOMEM;
+
+	adev->dev.common.tag = HARDWARE_DEVICE_TAG;
+	adev->dev.common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
+	adev->dev.common.module = (struct hw_module_t *) module;
+	adev->dev.common.close = audio_close;
+
+	adev->dev.init_check = audio_init_check;
+	adev->dev.set_voice_volume = audio_set_voice_volume;
+	adev->dev.set_master_volume = audio_set_master_volume;
+	adev->dev.set_mode = audio_set_mode;
+	adev->dev.set_mic_mute = audio_set_mic_mute;
+	adev->dev.get_mic_mute = audio_get_mic_mute;
+	adev->dev.set_parameters = audio_set_parameters;
+	adev->dev.get_parameters = audio_get_parameters;
+	adev->dev.get_input_buffer_size = audio_get_input_buffer_size;
+	adev->dev.open_output_stream = audio_open_output_stream;
+	adev->dev.close_output_stream = audio_close_output_stream;
+	adev->dev.open_input_stream = audio_open_input_stream;
+	adev->dev.close_input_stream = audio_close_input_stream;
+	adev->dev.dump = audio_dump;
+
+	*device = &adev->dev.common;
+
+	return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+	.open = audio_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+	.common = {
+		.tag = HARDWARE_MODULE_TAG,
+		.version_major = 1,
+		.version_minor = 0,
+		.id = AUDIO_HARDWARE_MODULE_ID,
+		.name = "HSP Audio HW HAL",
+		.author = "Intel Corporation",
+		.methods = &hal_module_methods,
+	},
+};
-- 
1.8.3.2


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

* [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream()
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08 11:24   ` Luiz Augusto von Dentz
  2014-05-08  8:01 ` [PATCHv3 03/12] android/audio: Add Audio SCO message API Andrei Emeltchenko
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

Function adds audio_open_output_stream() and sets dummy callbacks.
---
 android/hal-sco.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 176 insertions(+), 3 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index c7ba504..bc7d987 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -25,22 +25,195 @@
 
 #include "hal-log.h"
 
+#define AUDIO_STREAM_DEFAULT_RATE	44100
+#define AUDIO_STREAM_DEFAULT_FORMAT	AUDIO_FORMAT_PCM_16_BIT
+
+#define OUT_BUFFER_SIZE			2560
+
+struct hsp_audio_config {
+	uint32_t rate;
+	uint32_t channels;
+	audio_format_t format;
+};
+
+struct hsp_stream_out {
+	struct audio_stream_out stream;
+	struct hsp_audio_config cfg;
+};
+
 struct hsp_audio_dev {
 	struct audio_hw_device dev;
-	struct a2dp_stream_out *out;
+	struct hsp_stream_out *out;
 };
 
+/* Audio stream functions */
+
+static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
+								size_t bytes)
+{
+	/* write data */
+
+	return bytes;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
+
+	DBG("rate %u", out->cfg.rate);
+
+	return out->cfg.rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+	DBG("rate %u", rate);
+
+	return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+	DBG("buf size %u", OUT_BUFFER_SIZE);
+
+	return OUT_BUFFER_SIZE;
+}
+
+static uint32_t out_get_channels(const struct audio_stream *stream)
+{
+	DBG("");
+
+	/* AudioFlinger can only provide stereo stream, so we return it here and
+	 * later we'll downmix this to mono in case codec requires it
+	 */
+	return AUDIO_CHANNEL_OUT_STEREO;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
+
+	DBG("");
+
+	return out->cfg.format;
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+	DBG("");
+
+	return 0;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+	DBG("%s", kvpairs);
+
+	return 0;
+}
+
+static char *out_get_parameters(const struct audio_stream *stream,
+							const char *keys)
+{
+	DBG("");
+
+	return strdup("");
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+	DBG("");
+
+	return 0;
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+								float right)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+							uint32_t *dsp_frames)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+
+	return -ENOSYS;
+}
+
 static int audio_open_output_stream(struct audio_hw_device *dev,
 					audio_io_handle_t handle,
 					audio_devices_t devices,
 					audio_output_flags_t flags,
 					struct audio_config *config,
 					struct audio_stream_out **stream_out)
-
 {
+	struct hsp_audio_dev *adev = (struct hsp_audio_dev *) dev;
+	struct hsp_stream_out *out;
+
 	DBG("");
 
-	return -EINVAL;
+	out = calloc(1, sizeof(struct hsp_stream_out));
+	if (!out)
+		return -ENOMEM;
+
+	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;
+	out->stream.common.get_channels = out_get_channels;
+	out->stream.common.get_format = out_get_format;
+	out->stream.common.set_format = out_set_format;
+	out->stream.common.standby = out_standby;
+	out->stream.common.dump = out_dump;
+	out->stream.common.set_parameters = out_set_parameters;
+	out->stream.common.get_parameters = out_get_parameters;
+	out->stream.common.add_audio_effect = out_add_audio_effect;
+	out->stream.common.remove_audio_effect = out_remove_audio_effect;
+	out->stream.get_latency = out_get_latency;
+	out->stream.set_volume = out_set_volume;
+	out->stream.write = out_write;
+	out->stream.get_render_position = out_get_render_position;
+
+	out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+	out->cfg.channels = AUDIO_CHANNEL_OUT_MONO;
+	out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+
+	*stream_out = &out->stream;
+	adev->out = out;
+
+	return 0;
 }
 
 static void audio_close_output_stream(struct audio_hw_device *dev,
-- 
1.8.3.2


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

* [PATCHv3 03/12] android/audio: Add Audio SCO message API
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream() Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 04/12] android/handsfree: Add SCO Audio IPC Andrei Emeltchenko
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

SCO API will be used when communicating with SCO Audio HAL.
---
 android/sco-ipc-api.txt | 36 ++++++++++++++++++++++++++++++++++++
 android/sco-msg.h       | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)
 create mode 100644 android/sco-ipc-api.txt
 create mode 100644 android/sco-msg.h

diff --git a/android/sco-ipc-api.txt b/android/sco-ipc-api.txt
new file mode 100644
index 0000000..75b2cba
--- /dev/null
+++ b/android/sco-ipc-api.txt
@@ -0,0 +1,36 @@
+Bluetooth SCO Audio Plugin
+==========================
+
+The SCO Audio Plugin communicate through abstract socket name
+"\0bluez_sco_socket".
+
+	.---Audio---.                             .--Android--.
+	|  Plugin   |                             |   Daemon  |
+	|           |          Command            |           |
+	|           | --------------------------> |           |
+	|           |                             |           |
+	|           | <-------------------------- |           |
+	|           |          Response           |           |
+	|           |                             |           |
+	|           |                             |           |
+	|           |                             |           |
+	'-----------'                             '-----------'
+
+
+	Audio HAL                               Daemon
+	----------------------------------------------------
+
+	call connect_sco()                    --> create SCO socket
+	return connect_sco()                  <-- return socket fd and mtu
+
+SCO Audio Service (ID 0)
+========================
+
+	Opcode 0x00 - Error response
+
+		Response parameters: Status (1 octet)
+
+	Opcode 0x01 - Connect Audio SCO command
+
+		Command parameters: <none>
+		Response parameters: MTU (2 octets)
diff --git a/android/sco-msg.h b/android/sco-msg.h
new file mode 100644
index 0000000..cd2f894
--- /dev/null
+++ b/android/sco-msg.h
@@ -0,0 +1,36 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+static const char BLUEZ_SCO_SK_PATH[] = "\0bluez_sco_socket";
+
+#define AUDIO_SERVICE_SCO_ID		1
+
+#define AUDIO_STATUS_SUCCESS		IPC_STATUS_SUCCESS
+#define AUDIO_STATUS_FAILED		0x01
+
+#define AUDIO_OP_STATUS			IPC_OP_STATUS
+
+#define AUDIO_OP_CONNECT_SCO		0x01
+struct audio_rsp_connect_sco {
+	uint16_t mtu;
+} __attribute__((packed));
-- 
1.8.3.2


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

* [PATCHv3 04/12] android/handsfree: Add SCO Audio IPC
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (2 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 03/12] android/audio: Add Audio SCO message API Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 05/12] android/hal-sco: Implement Audio IPC on Audio HAL Andrei Emeltchenko
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

If SCO Audio IPC gets connected it provides only one command:
connect_sco().
---
 android/handsfree.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 8202e53..96f0f6e 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -45,6 +45,7 @@
 #include "bluetooth.h"
 #include "src/log.h"
 #include "utils.h"
+#include "sco-msg.h"
 
 #define HSP_AG_CHANNEL 12
 #define HFP_AG_CHANNEL 13
@@ -156,7 +157,9 @@ static struct {
 static uint32_t hfp_ag_features = 0;
 
 static bdaddr_t adapter_addr;
+
 static struct ipc *hal_ipc = NULL;
+static struct ipc *audio_ipc = NULL;
 
 static uint32_t hfp_record_id = 0;
 static GIOChannel *hfp_server = NULL;
@@ -822,6 +825,8 @@ static gboolean sco_watch_cb(GIOChannel *chan, GIOCondition cond,
 	g_io_channel_unref(device.sco);
 	device.sco = NULL;
 
+	DBG("");
+
 	device.sco_watch = 0;
 
 	device_set_audio_state(HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTED);
@@ -887,6 +892,27 @@ 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 (audio_ipc) {
+		int fd = g_io_channel_unix_get_fd(chan);
+		GError *err = NULL;
+		uint16_t mtu = 48;
+		struct audio_rsp_connect_sco rsp;
+
+		if (!bt_io_get(chan, &err, BT_IO_OPT_MTU, &mtu,
+							BT_IO_OPT_INVALID)) {
+			error("Unable to get MTU: %s\n", err->message);
+			g_clear_error(&err);
+		}
+
+		DBG("fd %d mtu %u", fd, mtu);
+
+		rsp.mtu = mtu;
+
+		ipc_send_rsp_full(audio_ipc, AUDIO_SERVICE_SCO_ID,
+					AUDIO_OP_CONNECT_SCO, sizeof(rsp), &rsp,
+					fd);
+	}
 }
 
 static bool connect_sco(void)
@@ -904,7 +930,7 @@ static bool connect_sco(void)
 				device.negotiated_codec != CODEC_ID_CVSD)
 		voice_settings = BT_VOICE_TRANSPARENT;
 	else
-		voice_settings = BT_VOICE_CVSD_16BIT;
+		voice_settings = 0;
 
 	io = bt_io_connect(connect_sco_cb, NULL, NULL, &gerr,
 				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
@@ -2563,6 +2589,33 @@ static void disable_sco_server(void)
 	}
 }
 
+static void bt_audio_connect_sco(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	connect_audio();
+}
+
+static const struct ipc_handler audio_handlers[] = {
+	/* AUDIO_OP_CONNECT_SCO */
+	{ bt_audio_connect_sco, false, 0 }
+};
+
+static bool bt_audio_register(ipc_disconnect_cb disconnect)
+{
+	DBG("");
+
+	audio_ipc = ipc_init(BLUEZ_SCO_SK_PATH, sizeof(BLUEZ_SCO_SK_PATH),
+				AUDIO_SERVICE_SCO_ID, false, disconnect, NULL);
+	if (!audio_ipc)
+		return false;
+
+	ipc_register(audio_ipc, AUDIO_SERVICE_SCO_ID, audio_handlers,
+						G_N_ELEMENTS(audio_handlers));
+
+	return true;
+}
+
 bool bt_handsfree_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
 {
 	DBG("mode 0x%x", mode);
@@ -2597,6 +2650,9 @@ done:
 	hal_ipc = ipc;
 	ipc_register(hal_ipc, HAL_SERVICE_ID_HANDSFREE, cmd_handlers,
 						G_N_ELEMENTS(cmd_handlers));
+
+	bt_audio_register(NULL);
+
 	return true;
 }
 
-- 
1.8.3.2


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

* [PATCHv3 05/12] android/hal-sco: Implement Audio IPC on Audio HAL
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (3 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 04/12] android/handsfree: Add SCO Audio IPC Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 06/12] android/ipc: Use error printing error messages Andrei Emeltchenko
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

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

diff --git a/android/hal-sco.c b/android/hal-sco.c
index bc7d987..669389c 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -16,13 +16,20 @@
  */
 
 #include <errno.h>
+#include <pthread.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
 
 #include <hardware/audio.h>
 #include <hardware/hardware.h>
 
+#include "sco-msg.h"
+#include "ipc-common.h"
 #include "hal-log.h"
 
 #define AUDIO_STREAM_DEFAULT_RATE	44100
@@ -30,15 +37,24 @@
 
 #define OUT_BUFFER_SIZE			2560
 
+static int listen_sk = -1;
+static int audio_sk = -1;
+
+static pthread_t ipc_th = 0;
+static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 struct hsp_audio_config {
 	uint32_t rate;
 	uint32_t channels;
+	uint16_t mtu;
 	audio_format_t format;
 };
 
 struct hsp_stream_out {
 	struct audio_stream_out stream;
+
 	struct hsp_audio_config cfg;
+	int fd;
 };
 
 struct hsp_audio_dev {
@@ -46,13 +62,186 @@ struct hsp_audio_dev {
 	struct hsp_stream_out *out;
 };
 
+/* Audio IPC functions */
+
+static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
+			void *param, size_t *rsp_len, void *rsp, int *fd)
+{
+	ssize_t ret;
+	struct msghdr msg;
+	struct iovec iv[2];
+	struct ipc_hdr cmd;
+	char cmsgbuf[CMSG_SPACE(sizeof(int))];
+	struct ipc_status s;
+	size_t s_len = sizeof(s);
+
+	pthread_mutex_lock(&sk_mutex);
+
+	if (audio_sk < 0) {
+		error("audio: Invalid cmd socket passed to audio_ipc_cmd");
+		goto failed;
+	}
+
+	if (!rsp || !rsp_len) {
+		memset(&s, 0, s_len);
+		rsp_len = &s_len;
+		rsp = &s;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.service_id = service_id;
+	cmd.opcode = opcode;
+	cmd.len = len;
+
+	iv[0].iov_base = &cmd;
+	iv[0].iov_len = sizeof(cmd);
+
+	iv[1].iov_base = param;
+	iv[1].iov_len = len;
+
+	msg.msg_iov = iv;
+	msg.msg_iovlen = 2;
+
+	ret = sendmsg(audio_sk, &msg, 0);
+	if (ret < 0) {
+		error("audio: Sending command failed:%s", strerror(errno));
+		goto failed;
+	}
+
+	/* socket was shutdown */
+	if (ret == 0) {
+		error("audio: Command socket closed");
+		goto failed;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	memset(&cmd, 0, sizeof(cmd));
+
+	iv[0].iov_base = &cmd;
+	iv[0].iov_len = sizeof(cmd);
+
+	iv[1].iov_base = rsp;
+	iv[1].iov_len = *rsp_len;
+
+	msg.msg_iov = iv;
+	msg.msg_iovlen = 2;
+
+	if (fd) {
+		memset(cmsgbuf, 0, sizeof(cmsgbuf));
+		msg.msg_control = cmsgbuf;
+		msg.msg_controllen = sizeof(cmsgbuf);
+	}
+
+	ret = recvmsg(audio_sk, &msg, 0);
+	if (ret < 0) {
+		error("audio: Receiving command response failed:%s",
+							strerror(errno));
+		goto failed;
+	}
+
+	if (ret < (ssize_t) sizeof(cmd)) {
+		error("audio: Too small response received(%zd bytes)", ret);
+		goto failed;
+	}
+
+	if (cmd.service_id != service_id) {
+		error("audio: Invalid service id (%u vs %u)", cmd.service_id,
+								service_id);
+		goto failed;
+	}
+
+	if (ret != (ssize_t) (sizeof(cmd) + cmd.len)) {
+		error("audio: Malformed response received(%zd bytes)", ret);
+		goto failed;
+	}
+
+	if (cmd.opcode != opcode && cmd.opcode != AUDIO_OP_STATUS) {
+		error("audio: Invalid opcode received (%u vs %u)",
+						cmd.opcode, opcode);
+		goto failed;
+	}
+
+	if (cmd.opcode == AUDIO_OP_STATUS) {
+		struct ipc_status *s = rsp;
+
+		if (sizeof(*s) != cmd.len) {
+			error("audio: Invalid status length");
+			goto failed;
+		}
+
+		if (s->code == AUDIO_STATUS_SUCCESS) {
+			error("audio: Invalid success status response");
+			goto failed;
+		}
+
+		pthread_mutex_unlock(&sk_mutex);
+
+		return s->code;
+	}
+
+	pthread_mutex_unlock(&sk_mutex);
+
+	/* Receive auxiliary data in msg */
+	if (fd) {
+		struct cmsghdr *cmsg;
+
+		*fd = -1;
+
+		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+					cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+			if (cmsg->cmsg_level == SOL_SOCKET
+					&& cmsg->cmsg_type == SCM_RIGHTS) {
+				memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
+				break;
+			}
+		}
+
+		if (*fd < 0)
+			goto failed;
+	}
+
+	if (rsp_len)
+		*rsp_len = cmd.len;
+
+	return AUDIO_STATUS_SUCCESS;
+
+failed:
+	/* Some serious issue happen on IPC - recover */
+	shutdown(audio_sk, SHUT_RDWR);
+	pthread_mutex_unlock(&sk_mutex);
+
+	return AUDIO_STATUS_FAILED;
+}
+
+static int ipc_connect_sco(int *fd, uint16_t *mtu)
+{
+	struct audio_rsp_connect_sco rsp;
+	size_t rsp_len = sizeof(rsp);
+	int ret;
+
+	DBG("");
+
+	ret = audio_ipc_cmd(AUDIO_SERVICE_SCO_ID, AUDIO_OP_CONNECT_SCO, 0,
+						NULL, &rsp_len, &rsp, fd);
+
+	*mtu = rsp.mtu;
+
+	return ret;
+}
+
 /* Audio stream functions */
 
 static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 								size_t bytes)
 {
+	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
+
 	/* write data */
 
+	DBG("write to fd %d bytes %zu", out->fd, bytes);
+
 	return bytes;
 }
 
@@ -182,9 +371,18 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 {
 	struct hsp_audio_dev *adev = (struct hsp_audio_dev *) dev;
 	struct hsp_stream_out *out;
+	int fd = -1;
+	uint16_t mtu;
 
 	DBG("");
 
+	if (ipc_connect_sco(&fd, &mtu) != AUDIO_STATUS_SUCCESS) {
+		error("audio: cannot get fd");
+		return -EIO;
+	}
+
+	DBG("got sco fd %d mtu %u", fd, mtu);
+
 	out = calloc(1, sizeof(struct hsp_stream_out));
 	if (!out)
 		return -ENOMEM;
@@ -209,9 +407,11 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
 	out->cfg.channels = AUDIO_CHANNEL_OUT_MONO;
 	out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+	out->cfg.mtu = mtu;
 
 	*stream_out = &out->stream;
 	adev->out = out;
+	out->fd = fd;
 
 	return 0;
 }
@@ -219,9 +419,17 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 static void audio_close_output_stream(struct audio_hw_device *dev,
 					struct audio_stream_out *stream_out)
 {
-	DBG("");
+	struct hsp_audio_dev *hsp_dev = (struct hsp_audio_dev *) dev;
+
+	DBG("dev %p stream %p fd %d", dev, stream_out, hsp_dev->out->fd);
+
+	if (hsp_dev->out && hsp_dev->out->fd) {
+		close(hsp_dev->out->fd);
+		hsp_dev->out->fd = -1;
+	}
 
 	free(stream_out);
+	hsp_dev->out = NULL;
 }
 
 static int audio_set_parameters(struct audio_hw_device *dev,
@@ -325,10 +533,116 @@ static int audio_close(hw_device_t *device)
 	return 0;
 }
 
+static void *ipc_handler(void *data)
+{
+	bool done = false;
+	struct pollfd pfd;
+	int sk;
+
+	DBG("");
+
+	while (!done) {
+		DBG("Waiting for connection ...");
+
+		sk = accept(listen_sk, NULL, NULL);
+		if (sk < 0) {
+			int err = errno;
+
+			if (err == EINTR)
+				continue;
+
+			if (err != ECONNABORTED && err != EINVAL)
+				error("audio: Failed to accept socket: %d (%s)",
+							err, strerror(err));
+
+			break;
+		}
+
+		pthread_mutex_lock(&sk_mutex);
+		audio_sk = sk;
+		pthread_mutex_unlock(&sk_mutex);
+
+		DBG("Audio IPC: Connected");
+
+		memset(&pfd, 0, sizeof(pfd));
+		pfd.fd = audio_sk;
+		pfd.events = POLLHUP | POLLERR | POLLNVAL;
+
+		/* Check if socket is still alive. Empty while loop.*/
+		while (poll(&pfd, 1, -1) < 0 && errno == EINTR);
+
+		if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+			info("Audio HAL: Socket closed");
+
+			pthread_mutex_lock(&sk_mutex);
+			close(audio_sk);
+			audio_sk = -1;
+			pthread_mutex_unlock(&sk_mutex);
+		}
+	}
+
+	info("Closing Audio IPC thread");
+	return NULL;
+}
+
+static int audio_ipc_init(void)
+{
+	struct sockaddr_un addr;
+	int err;
+	int sk;
+
+	DBG("");
+
+	sk = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	if (sk < 0) {
+		err = -errno;
+		error("audio: Failed to create socket: %d (%s)", -err,
+								strerror(-err));
+		return err;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+
+	memcpy(addr.sun_path, BLUEZ_SCO_SK_PATH, sizeof(BLUEZ_SCO_SK_PATH));
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = -errno;
+		error("audio: Failed to bind socket: %d (%s)", -err,
+								strerror(-err));
+		goto failed;
+	}
+
+	if (listen(sk, 1) < 0) {
+		err = -errno;
+		error("audio: Failed to listen on the socket: %d (%s)", -err,
+								strerror(-err));
+		goto failed;
+	}
+
+	listen_sk = sk;
+
+	err = pthread_create(&ipc_th, NULL, ipc_handler, NULL);
+	if (err) {
+		err = -err;
+		ipc_th = 0;
+		error("audio: Failed to start Audio IPC thread: %d (%s)",
+							-err, strerror(-err));
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	close(sk);
+	return err;
+}
+
 static int audio_open(const hw_module_t *module, const char *name,
 							hw_device_t **device)
 {
 	struct hsp_audio_dev *adev;
+	int err;
 
 	DBG("");
 
@@ -338,6 +652,10 @@ static int audio_open(const hw_module_t *module, const char *name,
 		return -EINVAL;
 	}
 
+	err = audio_ipc_init();
+	if (err < 0)
+		return err;
+
 	adev = calloc(1, sizeof(struct hsp_audio_dev));
 	if (!adev)
 		return -ENOMEM;
-- 
1.8.3.2


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

* [PATCHv3 06/12] android/ipc: Use error printing error messages
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (4 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 05/12] android/hal-sco: Implement Audio IPC on Audio HAL Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 07/12] android/haltest: Add testinng for audio SCO HAL Andrei Emeltchenko
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

This helps to identify problem since DBG is not printed by default.
---
 android/ipc.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/android/ipc.c b/android/ipc.c
index 8cd34ea..89fff8d 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -96,31 +96,31 @@ static int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
 	const struct ipc_handler *handler;
 
 	if (len < (ssize_t) sizeof(*msg)) {
-		DBG("message too small (%zd bytes)", len);
+		error("message too small (%zd bytes)", len);
 		return -EBADMSG;
 	}
 
 	if (len != (ssize_t) (sizeof(*msg) + msg->len)) {
-		DBG("message malformed (%zd bytes)", len);
+		error("message malformed (%zd bytes)", len);
 		return -EBADMSG;
 	}
 
 	/* if service is valid */
 	if (msg->service_id > max_index) {
-		DBG("unknown service (0x%x)", msg->service_id);
+		error("unknown service (0x%x)", msg->service_id);
 		return -EOPNOTSUPP;
 	}
 
 	/* if service is registered */
 	if (!handlers[msg->service_id].handler) {
-		DBG("service not registered (0x%x)", msg->service_id);
+		error("service not registered (0x%x)", msg->service_id);
 		return -EOPNOTSUPP;
 	}
 
 	/* if opcode is valid */
 	if (msg->opcode == IPC_OP_STATUS ||
 			msg->opcode > handlers[msg->service_id].size) {
-		DBG("invalid opcode 0x%x for service 0x%x", msg->opcode,
+		error("invalid opcode 0x%x for service 0x%x", msg->opcode,
 							msg->service_id);
 		return -EOPNOTSUPP;
 	}
@@ -131,7 +131,7 @@ static int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
 	/* if payload size is valid */
 	if ((handler->var_len && handler->data_len > msg->len) ||
 			(!handler->var_len && handler->data_len != msg->len)) {
-		DBG("invalid size for opcode 0x%x service 0x%x",
+		error("invalid size for opcode 0x%x service 0x%x",
 						msg->opcode, msg->service_id);
 		return -EMSGSIZE;
 	}
-- 
1.8.3.2


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

* [PATCHv3 07/12] android/haltest: Add testinng for audio SCO HAL
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (5 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 06/12] android/ipc: Use error printing error messages Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 08/12] android/audio: Add resampler support Andrei Emeltchenko
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

Adds testing support for audio-sco HAL.
---
 android/Android.mk            |   1 +
 android/Makefile.am           |   1 +
 android/client/haltest.c      |   3 +
 android/client/if-audio-sco.c | 520 ++++++++++++++++++++++++++++++++++++++++++
 android/client/if-main.h      |   1 +
 5 files changed, 526 insertions(+)
 create mode 100644 android/client/if-audio-sco.c

diff --git a/android/Android.mk b/android/Android.mk
index b7b284d..2731e86 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -149,6 +149,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/client/history.c \
 	bluez/android/client/tabcompletion.c \
 	bluez/android/client/if-audio.c \
+	bluez/android/client/if-audio-sco.c \
 	bluez/android/client/if-av.c \
 	bluez/android/client/if-rc.c \
 	bluez/android/client/if-bt.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 990ce6b..5113d71 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -109,6 +109,7 @@ android_haltest_SOURCES = android/client/haltest.c \
 				android/client/if-hl.c \
 				android/client/if-sock.c \
 				android/client/if-audio.c \
+				android/client/if-audio-sco.c \
 				android/hardware/hardware.c \
 				android/hal-utils.h android/hal-utils.c
 
diff --git a/android/client/haltest.c b/android/client/haltest.c
index 5d05b75..0871dd7 100644
--- a/android/client/haltest.c
+++ b/android/client/haltest.c
@@ -32,6 +32,7 @@
 
 const struct interface *interfaces[] = {
 	&audio_if,
+	&sco_if,
 	&bluetooth_if,
 	&av_if,
 	&rc_if,
@@ -394,10 +395,12 @@ static void init(void)
 	const struct method *m;
 	const char *argv[4];
 	char init_audio[] = "audio init";
+	char init_audio_sco[] = "audio-sco init";
 	char init_bt[] = "bluetooth init";
 	uint32_t i;
 
 	process_line(init_audio);
+	process_line(init_audio_sco);
 	process_line(init_bt);
 
 	m = get_interface_method("bluetooth", "get_profile_interface");
diff --git a/android/client/if-audio-sco.c b/android/client/if-audio-sco.c
new file mode 100644
index 0000000..24e07cd
--- /dev/null
+++ b/android/client/if-audio-sco.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "if-main.h"
+#include "../hal-utils.h"
+#include "pthread.h"
+#include "unistd.h"
+#include <math.h>
+
+audio_hw_device_t *if_audio_sco = NULL;
+static struct audio_stream_out *stream_out = NULL;
+
+static size_t buffer_size = 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;
+
+enum state {
+	STATE_STOPPED,
+	STATE_STOPPING,
+	STATE_PLAYING,
+	STATE_SUSPENDED,
+	STATE_MAX
+};
+
+SINTMAP(audio_channel_mask_t, -1, "(AUDIO_CHANNEL_INVALID)")
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
+	DELEMENT(AUDIO_CHANNEL_OUT_BACK_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_BACK_RIGHT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_BACK_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_SIDE_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
+	DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
+	DELEMENT(AUDIO_CHANNEL_OUT_MONO),
+	DELEMENT(AUDIO_CHANNEL_OUT_STEREO),
+	DELEMENT(AUDIO_CHANNEL_OUT_QUAD),
+	DELEMENT(AUDIO_CHANNEL_OUT_SURROUND),
+	DELEMENT(AUDIO_CHANNEL_OUT_5POINT1),
+	DELEMENT(AUDIO_CHANNEL_OUT_7POINT1),
+	DELEMENT(AUDIO_CHANNEL_OUT_ALL),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
+	DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
+ENDMAP
+
+SINTMAP(audio_format_t, -1, "(AUDIO_FORMAT_INVALID)")
+	DELEMENT(AUDIO_FORMAT_DEFAULT),
+	DELEMENT(AUDIO_FORMAT_PCM),
+	DELEMENT(AUDIO_FORMAT_MP3),
+	DELEMENT(AUDIO_FORMAT_AMR_NB),
+	DELEMENT(AUDIO_FORMAT_AMR_WB),
+	DELEMENT(AUDIO_FORMAT_AAC),
+	DELEMENT(AUDIO_FORMAT_HE_AAC_V1),
+	DELEMENT(AUDIO_FORMAT_HE_AAC_V2),
+	DELEMENT(AUDIO_FORMAT_VORBIS),
+	DELEMENT(AUDIO_FORMAT_MAIN_MASK),
+	DELEMENT(AUDIO_FORMAT_SUB_MASK),
+	DELEMENT(AUDIO_FORMAT_PCM_16_BIT),
+	DELEMENT(AUDIO_FORMAT_PCM_8_BIT),
+	DELEMENT(AUDIO_FORMAT_PCM_32_BIT),
+	DELEMENT(AUDIO_FORMAT_PCM_8_24_BIT),
+ENDMAP
+
+static int current_state = STATE_STOPPED;
+
+#define SAMPLERATE 44100
+static short sample[SAMPLERATE];
+static uint16_t sample_pos;
+
+static void init_p(int argc, const char **argv)
+{
+	int err;
+	const hw_module_t *module;
+	audio_hw_device_t *device;
+
+	err = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, "hsp", &module);
+	if (err) {
+		haltest_error("hw_get_module_by_class returned %d\n", err);
+		return;
+	}
+
+	err = audio_hw_device_open(module, &device);
+	if (err) {
+		haltest_error("audio_hw_device_open returned %d\n", err);
+		return;
+	}
+
+	if_audio_sco = device;
+}
+
+static int feed_from_file(short *buffer, void *data)
+{
+	FILE *in = data;
+	return fread(buffer, buffer_size, 1, in);
+}
+
+static int feed_from_generator(short *buffer, void *data)
+{
+	size_t i = 0;
+	float volume = 0.5;
+	float *freq = data;
+	float f = 1;
+
+	if (freq)
+		f = *freq;
+
+	/* buffer_size is in bytes but we are using buffer of shorts (2 bytes)*/
+	for (i = 0; i < buffer_size / sizeof(*buffer) - 1;) {
+		if (sample_pos >= SAMPLERATE)
+			sample_pos = sample_pos % SAMPLERATE;
+
+		/* Use the same sample for both channels */
+		buffer[i++] = sample[sample_pos] * volume;
+		buffer[i++] = sample[sample_pos] * volume;
+
+		sample_pos += f;
+	}
+
+	return buffer_size;
+}
+
+static void prepare_sample(void)
+{
+	int x;
+	double s;
+
+	haltest_info("Preparing audio sample...\n");
+
+	for (x = 0; x < SAMPLERATE; x++) {
+		/* prepare sinusoidal 1Hz sample */
+		s = (2.0 * 3.14159) * ((double)x / SAMPLERATE);
+		s = sin(s);
+
+		/* remap <-1, 1> to signed 16bit PCM range */
+		sample[x] = s * 32767;
+	}
+
+	sample_pos = 0;
+}
+
+static void *playback_thread(void *data)
+{
+	int (*filbuff_cb) (short*, void*);
+	short buffer[buffer_size / sizeof(short)];
+	size_t len = 0;
+	ssize_t w_len = 0;
+	FILE *in = data;
+	void *cb_data = NULL;
+	float freq = 440.0;
+
+	/* Use file or fall back to generator */
+	if (in) {
+		filbuff_cb = feed_from_file;
+		cb_data = in;
+	} else {
+		prepare_sample();
+		filbuff_cb = feed_from_generator;
+		cb_data = &freq;
+	}
+
+	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);
+
+		pthread_mutex_lock(&outstream_mutex);
+		if (!stream_out) {
+			pthread_mutex_unlock(&outstream_mutex);
+			break;
+		}
+
+		w_len = stream_out->write(stream_out, buffer, buffer_size);
+		pthread_mutex_unlock(&outstream_mutex);
+	} while (len && w_len > 0);
+
+	if (in)
+		fclose(in);
+
+	pthread_mutex_lock(&state_mutex);
+	current_state = STATE_STOPPED;
+	pthread_mutex_unlock(&state_mutex);
+
+	haltest_info("Done playing.\n");
+
+	return NULL;
+}
+
+static void play_p(int argc, const char **argv)
+{
+	const char *fname = NULL;
+	FILE *in = NULL;
+
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	if (argc < 3) {
+		haltest_error("Invalid audio file path.\n");
+		haltest_info("Using sound generator.\n");
+	} else {
+		fname = argv[2];
+		in = fopen(fname, "r");
+
+		if (in == NULL) {
+			haltest_error("Cannot open file: %s\n", fname);
+			return;
+		}
+		haltest_info("Playing file: %s\n", fname);
+	}
+
+	if (buffer_size == 0) {
+		haltest_error("Invalid buffer size. Was stream_out opened?\n");
+		goto fail;
+	}
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state != STATE_STOPPED) {
+		haltest_error("Already playing or stream suspended!\n");
+		pthread_mutex_unlock(&state_mutex);
+		goto fail;
+	}
+	pthread_mutex_unlock(&state_mutex);
+
+	if (pthread_create(&play_thread, NULL, playback_thread, in) != 0) {
+		haltest_error("Cannot create playback thread!\n");
+		goto fail;
+	}
+
+	return;
+fail:
+	if (in)
+		fclose(in);
+}
+
+static void stop_p(int argc, const char **argv)
+{
+	pthread_mutex_lock(&state_mutex);
+	if (current_state == STATE_STOPPED || current_state == STATE_STOPPING) {
+		pthread_mutex_unlock(&state_mutex);
+		return;
+	}
+
+	current_state = STATE_STOPPING;
+	pthread_mutex_unlock(&state_mutex);
+
+	pthread_mutex_lock(&outstream_mutex);
+	stream_out->common.standby(&stream_out->common);
+	pthread_mutex_unlock(&outstream_mutex);
+
+	haltest_info("Ended %s\n", __func__);
+}
+
+static void open_output_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_output_stream(if_audio_sco,
+						0,
+						AUDIO_DEVICE_OUT_ALL_A2DP,
+						AUDIO_OUTPUT_FLAG_NONE,
+						NULL,
+						&stream_out);
+	if (err < 0) {
+		haltest_error("open output stream returned %d\n", err);
+		return;
+	}
+
+	buffer_size = stream_out->common.get_buffer_size(&stream_out->common);
+	if (buffer_size == 0)
+		haltest_error("Invalid buffer size received!\n");
+	else
+		haltest_info("Using buffer size: %zu\n", buffer_size);
+}
+
+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_audio_sco->close_output_stream(if_audio_sco, stream_out);
+
+	stream_out = NULL;
+	buffer_size = 0;
+}
+
+static void cleanup_p(int argc, const char **argv)
+{
+	int err;
+
+	RETURN_IF_NULL(if_audio_sco);
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state != STATE_STOPPED) {
+		pthread_mutex_unlock(&state_mutex);
+		close_output_stream_p(0, NULL);
+	} else {
+		pthread_mutex_unlock(&state_mutex);
+	}
+
+	err = audio_hw_device_close(if_audio_sco);
+	if (err < 0) {
+		haltest_error("audio_hw_device_close returned %d\n", err);
+		return;
+	}
+
+	if_audio_sco = NULL;
+}
+
+static void suspend_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state != STATE_PLAYING) {
+		pthread_mutex_unlock(&state_mutex);
+		return;
+	}
+	current_state = STATE_SUSPENDED;
+	pthread_mutex_unlock(&state_mutex);
+
+	pthread_mutex_lock(&outstream_mutex);
+	stream_out->common.standby(&stream_out->common);
+	pthread_mutex_unlock(&outstream_mutex);
+}
+
+static void resume_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	pthread_mutex_lock(&state_mutex);
+	if (current_state == STATE_SUSPENDED)
+		current_state = STATE_PLAYING;
+	pthread_mutex_unlock(&state_mutex);
+}
+
+static void get_latency_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	haltest_info("Output audio stream latency: %d\n",
+					stream_out->get_latency(stream_out));
+}
+
+static void get_buffer_size_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	haltest_info("Current output buffer size: %zu\n",
+		stream_out->common.get_buffer_size(&stream_out->common));
+}
+
+static void get_channels_p(int argc, const char **argv)
+{
+	audio_channel_mask_t channels;
+
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	channels = stream_out->common.get_channels(&stream_out->common);
+
+	haltest_info("Channels: %s\n", audio_channel_mask_t2str(channels));
+}
+
+static void get_format_p(int argc, const char **argv)
+{
+	audio_format_t format;
+
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	format = stream_out->common.get_format(&stream_out->common);
+
+	haltest_info("Format: %s\n", audio_format_t2str(format));
+}
+
+static void get_sample_rate_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	haltest_info("Current sample rate: %d\n",
+		stream_out->common.get_sample_rate(&stream_out->common));
+}
+
+static void get_parameters_p(int argc, const char **argv)
+{
+	const char *keystr;
+
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	if (argc < 3) {
+		haltest_info("No keys given.\n");
+		keystr = "";
+	} else {
+		keystr = argv[2];
+	}
+
+	haltest_info("Current parameters: %s\n",
+			stream_out->common.get_parameters(&stream_out->common,
+								keystr));
+}
+
+static void set_parameters_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	if (argc < 3) {
+		haltest_error("No key=value; pairs given.\n");
+		return;
+	}
+
+	stream_out->common.set_parameters(&stream_out->common, argv[2]);
+}
+
+static void set_sample_rate_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+	RETURN_IF_NULL(stream_out);
+
+	if (argc < 3)
+		return;
+
+	stream_out->common.set_sample_rate(&stream_out->common, atoi(argv[2]));
+}
+
+static void init_check_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_audio_sco);
+
+	haltest_info("Init check result: %d\n", if_audio_sco->init_check(if_audio_sco));
+}
+
+static struct method methods[] = {
+	STD_METHOD(init),
+	STD_METHOD(cleanup),
+	STD_METHOD(open_output_stream),
+	STD_METHOD(close_output_stream),
+	STD_METHODH(play, "<path to pcm file>"),
+	STD_METHOD(stop),
+	STD_METHOD(suspend),
+	STD_METHOD(resume),
+	STD_METHOD(get_latency),
+	STD_METHOD(get_buffer_size),
+	STD_METHOD(get_channels),
+	STD_METHOD(get_format),
+	STD_METHOD(get_sample_rate),
+	STD_METHODH(get_parameters, "<closing>"),
+	STD_METHODH(set_parameters, "<closing=value>"),
+	STD_METHODH(set_sample_rate, "<sample rate>"),
+	STD_METHOD(init_check),
+	END_METHOD
+};
+
+const struct interface sco_if = {
+	.name = "audio-sco",
+	.methods = methods
+};
diff --git a/android/client/if-main.h b/android/client/if-main.h
index ff6006c..88da0c7 100644
--- a/android/client/if-main.h
+++ b/android/client/if-main.h
@@ -68,6 +68,7 @@ struct interface {
 };
 
 extern const struct interface audio_if;
+extern const struct interface sco_if;
 extern const struct interface bluetooth_if;
 extern const struct interface av_if;
 extern const struct interface rc_if;
-- 
1.8.3.2


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

* [PATCHv3 08/12] android/audio: Add resampler support
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (6 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 07/12] android/haltest: Add testinng for audio SCO HAL Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 09/12] audio/haltest: Make audio_stream static Andrei Emeltchenko
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

The patch adds support for resampling audio in host and Android. There
are Android wrappers for SPEEXDSP library added to host.
---
 android/Android.mk              |   2 +
 android/Makefile.am             |   6 +-
 android/audio_utils/resampler.c | 265 ++++++++++++++++++++++++++++++++++++++++
 android/audio_utils/resampler.h | 109 +++++++++++++++++
 configure.ac                    |   7 ++
 5 files changed, 388 insertions(+), 1 deletion(-)
 create mode 100644 android/audio_utils/resampler.c
 create mode 100644 android/audio_utils/resampler.h

diff --git a/android/Android.mk b/android/Android.mk
index 2731e86..957473b 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -282,9 +282,11 @@ LOCAL_SRC_FILES := bluez/android/hal-sco.c
 LOCAL_C_INCLUDES = \
 	$(call include-path-for, system-core) \
 	$(call include-path-for, libhardware) \
+	$(call include-path-for, audio-utils) \
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	libaudioutils \
 
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
diff --git a/android/Makefile.am b/android/Makefile.am
index 5113d71..adfb9f4 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -176,9 +176,13 @@ android_audio_sco_default_la_SOURCES = android/audio-msg.h \
 					android/hardware/audio.h \
 					android/hardware/audio_effect.h \
 					android/hardware/hardware.h \
+					android/audio_utils/resampler.c \
+					android/audio_utils/resampler.h \
 					android/system/audio.h
 
-android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android -Wno-declaration-after-statement
+
+android_audio_sco_default_la_LIBADD = @SPEEXDSP_LIBS@
 
 android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
 					-no-undefined -lrt
diff --git a/android/audio_utils/resampler.c b/android/audio_utils/resampler.c
new file mode 100644
index 0000000..137e4d2
--- /dev/null
+++ b/android/audio_utils/resampler.c
@@ -0,0 +1,265 @@
+/*
+** Copyright 2011, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <system/audio.h>
+#include <audio_utils/resampler.h>
+#include <speex/speex_resampler.h>
+
+#include "hal-log.h"
+
+struct resampler {
+    struct resampler_itfe itfe;
+    SpeexResamplerState *speex_resampler;       // handle on speex resampler
+    struct resampler_buffer_provider *provider; // buffer provider installed by client
+    uint32_t in_sample_rate;                    // input sampling rate in Hz
+    uint32_t out_sample_rate;                   // output sampling rate in Hz
+    uint32_t channel_count;                     // number of channels (interleaved)
+    int16_t *in_buf;                            // input buffer
+    size_t in_buf_size;                         // input buffer size
+    size_t frames_in;                           // number of frames in input buffer
+    size_t frames_rq;                           // cached number of output frames
+    size_t frames_needed;                       // minimum number of input frames to produce
+                                                // frames_rq output frames
+    int32_t speex_delay_ns;                     // delay introduced by speex resampler in ns
+};
+
+
+//------------------------------------------------------------------------------
+// speex based resampler
+//------------------------------------------------------------------------------
+
+static void resampler_reset(struct resampler_itfe *resampler)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    rsmp->frames_in = 0;
+    rsmp->frames_rq = 0;
+
+    if (rsmp != NULL && rsmp->speex_resampler != NULL) {
+        speex_resampler_reset_mem(rsmp->speex_resampler);
+    }
+}
+
+static int32_t resampler_delay_ns(struct resampler_itfe *resampler)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate);
+    delay += rsmp->speex_delay_ns;
+
+    return delay;
+}
+
+// outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount
+// with the actual number of frames produced.
+static int resampler_resample_from_provider(struct resampler_itfe *resampler,
+                       int16_t *out,
+                       size_t *outFrameCount)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    if (rsmp == NULL || out == NULL || outFrameCount == NULL) {
+        return -EINVAL;
+    }
+    if (rsmp->provider == NULL) {
+        *outFrameCount = 0;
+        return -ENOSYS;
+    }
+
+    size_t framesRq = *outFrameCount;
+    // update and cache the number of frames needed at the input sampling rate to produce
+    // the number of frames requested at the output sampling rate
+    if (framesRq != rsmp->frames_rq) {
+        rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
+        rsmp->frames_rq = framesRq;
+    }
+
+    size_t framesWr = 0;
+    size_t inFrames = 0;
+    while (framesWr < framesRq) {
+        if (rsmp->frames_in < rsmp->frames_needed) {
+            // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
+            // least the number of frames needed to produce the number of frames requested at
+            // the output sampling rate
+            if (rsmp->in_buf_size < rsmp->frames_needed) {
+                rsmp->in_buf_size = rsmp->frames_needed;
+                rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
+                                        rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
+            }
+            struct resampler_buffer buf;
+            buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
+            rsmp->provider->get_next_buffer(rsmp->provider, &buf);
+            if (buf.raw == NULL) {
+                break;
+            }
+            memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
+                    buf.raw,
+                    buf.frame_count * rsmp->channel_count * sizeof(int16_t));
+            rsmp->frames_in += buf.frame_count;
+            rsmp->provider->release_buffer(rsmp->provider, &buf);
+        }
+
+        size_t outFrames = framesRq - framesWr;
+        inFrames = rsmp->frames_in;
+        if (rsmp->channel_count == 1) {
+            speex_resampler_process_int(rsmp->speex_resampler,
+                                        0,
+                                        rsmp->in_buf,
+                                        (void *) &inFrames,
+                                        out + framesWr,
+                                        (void *) &outFrames);
+        } else {
+            speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+                                        rsmp->in_buf,
+                                        (void *) &inFrames,
+                                        out + framesWr * rsmp->channel_count,
+                                        (void *) &outFrames);
+        }
+        framesWr += outFrames;
+        rsmp->frames_in -= inFrames;
+
+        if ((framesWr != framesRq) && (rsmp->frames_in != 0))
+            warn("ReSampler::resample() remaining %zd frames in and %zd out",
+                rsmp->frames_in, (framesRq - framesWr));
+    }
+    if (rsmp->frames_in) {
+        memmove(rsmp->in_buf,
+                rsmp->in_buf + inFrames * rsmp->channel_count,
+                rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
+    }
+    *outFrameCount = framesWr;
+
+    return 0;
+}
+
+static int resampler_resample_from_input(struct resampler_itfe *resampler,
+                                  int16_t *in,
+                                  size_t *inFrameCount,
+                                  int16_t *out,
+                                  size_t *outFrameCount)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    if (rsmp == NULL || in == NULL || inFrameCount == NULL ||
+            out == NULL || outFrameCount == NULL) {
+        return -EINVAL;
+    }
+    if (rsmp->provider != NULL) {
+        *outFrameCount = 0;
+        return -ENOSYS;
+    }
+
+    if (rsmp->channel_count == 1) {
+        speex_resampler_process_int(rsmp->speex_resampler,
+                                    0,
+                                    in,
+                                    (void *) inFrameCount,
+                                    out,
+                                    (void *) outFrameCount);
+    } else {
+        speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+                                                in,
+                                                (void *) inFrameCount,
+                                                out,
+                                                (void *) outFrameCount);
+    }
+
+    DBG("resampler_resample_from_input() DONE in %zd out %zd", *inFrameCount, *outFrameCount);
+
+    return 0;
+}
+
+int create_resampler(uint32_t inSampleRate,
+                    uint32_t outSampleRate,
+                    uint32_t channelCount,
+                    uint32_t quality,
+                    struct resampler_buffer_provider* provider,
+                    struct resampler_itfe **resampler)
+{
+    int error;
+    struct resampler *rsmp;
+
+    DBG("create_resampler() In SR %d Out SR %d channels %d",
+         inSampleRate, outSampleRate, channelCount);
+
+    if (resampler == NULL) {
+        return -EINVAL;
+    }
+
+    *resampler = NULL;
+
+    if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) {
+        return -EINVAL;
+    }
+
+    rsmp = (struct resampler *)calloc(1, sizeof(struct resampler));
+
+    rsmp->speex_resampler = speex_resampler_init(channelCount,
+                                      inSampleRate,
+                                      outSampleRate,
+                                      quality,
+                                      &error);
+    if (rsmp->speex_resampler == NULL) {
+        error("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error));
+        free(rsmp);
+        return -ENODEV;
+    }
+
+    rsmp->itfe.reset = resampler_reset;
+    rsmp->itfe.resample_from_provider = resampler_resample_from_provider;
+    rsmp->itfe.resample_from_input = resampler_resample_from_input;
+    rsmp->itfe.delay_ns = resampler_delay_ns;
+
+    rsmp->provider = provider;
+    rsmp->in_sample_rate = inSampleRate;
+    rsmp->out_sample_rate = outSampleRate;
+    rsmp->channel_count = channelCount;
+    rsmp->in_buf = NULL;
+    rsmp->in_buf_size = 0;
+
+    resampler_reset(&rsmp->itfe);
+
+    int frames = speex_resampler_get_input_latency(rsmp->speex_resampler);
+    rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate);
+    frames = speex_resampler_get_output_latency(rsmp->speex_resampler);
+    rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate);
+
+    *resampler = &rsmp->itfe;
+    DBG("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p",
+         rsmp, &rsmp->itfe, rsmp->speex_resampler);
+    return 0;
+}
+
+void release_resampler(struct resampler_itfe *resampler)
+{
+    struct resampler *rsmp = (struct resampler *)resampler;
+
+    if (rsmp == NULL) {
+        return;
+    }
+
+    free(rsmp->in_buf);
+
+    if (rsmp->speex_resampler != NULL) {
+        speex_resampler_destroy(rsmp->speex_resampler);
+    }
+    free(rsmp);
+}
diff --git a/android/audio_utils/resampler.h b/android/audio_utils/resampler.h
new file mode 100644
index 0000000..0c7046f
--- /dev/null
+++ b/android/audio_utils/resampler.h
@@ -0,0 +1,109 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_RESAMPLER_H
+#define ANDROID_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+
+#define RESAMPLER_QUALITY_MAX 10
+#define RESAMPLER_QUALITY_MIN 0
+#define RESAMPLER_QUALITY_DEFAULT 4
+#define RESAMPLER_QUALITY_VOIP 3
+#define RESAMPLER_QUALITY_DESKTOP 5
+
+struct resampler_buffer {
+    union {
+        void*       raw;
+        short*      i16;
+        int8_t*     i8;
+    };
+    size_t frame_count;
+};
+
+/* call back interface used by the resampler to get new data */
+struct resampler_buffer_provider
+{
+    /**
+     *  get a new buffer of data:
+     *   as input: buffer->frame_count is the number of frames requested
+     *   as output: buffer->frame_count is the number of frames returned
+     *              buffer->raw points to data returned
+     */
+    int (*get_next_buffer)(struct resampler_buffer_provider *provider,
+            struct resampler_buffer *buffer);
+    /**
+     *  release a consumed buffer of data:
+     *   as input: buffer->frame_count is the number of frames released
+     *             buffer->raw points to data released
+     */
+    void (*release_buffer)(struct resampler_buffer_provider *provider,
+            struct resampler_buffer *buffer);
+};
+
+/* resampler interface */
+struct resampler_itfe {
+    /**
+     * reset resampler state
+     */
+    void (*reset)(struct resampler_itfe *resampler);
+    /**
+     * resample input from buffer provider and output at most *outFrameCount to out buffer.
+     * *outFrameCount is updated with the actual number of frames produced.
+     */
+    int (*resample_from_provider)(struct resampler_itfe *resampler,
+                    int16_t *out,
+                    size_t *outFrameCount);
+    /**
+     * resample at most *inFrameCount frames from in buffer and output at most
+     * *outFrameCount to out buffer. *inFrameCount and *outFrameCount are updated respectively
+     * with the number of frames remaining in input and written to output.
+     */
+    int (*resample_from_input)(struct resampler_itfe *resampler,
+                    int16_t *in,
+                    size_t *inFrameCount,
+                    int16_t *out,
+                    size_t *outFrameCount);
+    /**
+     * return the latency introduced by the resampler in ns.
+     */
+    int32_t (*delay_ns)(struct resampler_itfe *resampler);
+};
+
+/**
+ * create a resampler according to input parameters passed.
+ * If resampler_buffer_provider is not NULL only resample_from_provider() can be called.
+ * If resampler_buffer_provider is NULL only resample_from_input() can be called.
+ */
+int create_resampler(uint32_t inSampleRate,
+          uint32_t outSampleRate,
+          uint32_t channelCount,
+          uint32_t quality,
+          struct resampler_buffer_provider *provider,
+          struct resampler_itfe **);
+
+/**
+ * release resampler resources.
+ */
+void release_resampler(struct resampler_itfe *);
+
+__END_DECLS
+
+#endif // ANDROID_RESAMPLER_H
diff --git a/configure.ac b/configure.ac
index 54a387f..e1a2288 100644
--- a/configure.ac
+++ b/configure.ac
@@ -259,6 +259,13 @@ if (test "${enable_android}" = "yes"); then
 	AC_SUBST(SBC_LIBS)
 fi
 
+if (test "${enable_android}" = "yes"); then
+	PKG_CHECK_MODULES(SPEEXDSP, speexdsp >= 1.2, dummy=yes,
+					AC_MSG_ERROR(SPEEXDSP library >= 1.2 is required))
+	AC_SUBST(SPEEXDSP_CFLAGS)
+	AC_SUBST(SPEEXDSP_LIBS)
+fi
+
 AC_DEFINE_UNQUOTED(ANDROID_STORAGEDIR, "${storagedir}/android",
 			[Directory for the Android daemon storage files])
 
-- 
1.8.3.2


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

* [PATCHv3 09/12] audio/haltest: Make audio_stream static
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (7 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 08/12] android/audio: Add resampler support Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 10/12] android/audio: Add downmix support to audio SCO HAL Andrei Emeltchenko
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/client/if-audio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/client/if-audio.c b/android/client/if-audio.c
index ede8533..6a48025 100644
--- a/android/client/if-audio.c
+++ b/android/client/if-audio.c
@@ -22,7 +22,7 @@
 #include <math.h>
 
 audio_hw_device_t *if_audio = NULL;
-struct audio_stream_out *stream_out = NULL;
+static struct audio_stream_out *stream_out = NULL;
 
 static size_t buffer_size = 0;
 static pthread_t play_thread = 0;
-- 
1.8.3.2


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

* [PATCHv3 10/12] android/audio: Add downmix support to audio SCO HAL
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (8 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 09/12] audio/haltest: Make audio_stream static Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 11/12] android/audio: Use resampler interface to resample SCO Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 12/12] android/audio: Add write to SCO Andrei Emeltchenko
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/hal-sco.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 44 insertions(+), 5 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 669389c..d55d34d 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -28,6 +28,7 @@
 #include <hardware/audio.h>
 #include <hardware/hardware.h>
 
+#include "../src/shared/util.h"
 #include "sco-msg.h"
 #include "ipc-common.h"
 #include "hal-log.h"
@@ -36,6 +37,7 @@
 #define AUDIO_STREAM_DEFAULT_FORMAT	AUDIO_FORMAT_PCM_16_BIT
 
 #define OUT_BUFFER_SIZE			2560
+#define OUT_STREAM_FRAMES		2560
 
 static int listen_sk = -1;
 static int audio_sk = -1;
@@ -46,6 +48,7 @@ static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
 struct hsp_audio_config {
 	uint32_t rate;
 	uint32_t channels;
+	uint32_t frame_num;
 	uint16_t mtu;
 	audio_format_t format;
 };
@@ -55,6 +58,8 @@ struct hsp_stream_out {
 
 	struct hsp_audio_config cfg;
 	int fd;
+
+	uint8_t *downmix_buf;
 };
 
 struct hsp_audio_dev {
@@ -233,15 +238,35 @@ static int ipc_connect_sco(int *fd, uint16_t *mtu)
 
 /* Audio stream functions */
 
+static void downmix_to_mono(struct hsp_stream_out *out, const uint8_t *buffer,
+							size_t frame_num)
+{
+	const int16_t *input = (const void *) buffer;
+	int16_t *output = (void *) out->downmix_buf;
+	size_t i;
+
+	for (i = 0; i < frame_num; i++) {
+		int16_t l = le16_to_cpu(get_unaligned(&input[i * 2]));
+		int16_t r = le16_to_cpu(get_unaligned(&input[i * 2 + 1]));
+
+		put_unaligned(cpu_to_le16((l + r) >> 1), &output[i]);
+	}
+}
+
 static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 								size_t bytes)
 {
 	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
-
-	/* write data */
+	size_t frame_num = bytes / audio_stream_frame_size(&out->stream.common);
 
 	DBG("write to fd %d bytes %zu", out->fd, bytes);
 
+	if (!out->downmix_buf) {
+		error("audio: downmix buffer not initialized");
+		return -1;
+	}
+
+	downmix_to_mono(out, buffer, frame_num);
 	return bytes;
 }
 
@@ -263,9 +288,13 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
 
 static size_t out_get_buffer_size(const struct audio_stream *stream)
 {
-	DBG("buf size %u", OUT_BUFFER_SIZE);
+	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
+	size_t size = audio_stream_frame_size(&out->stream.common) *
+							out->cfg.frame_num;
+
+	DBG("buf size %zd", size);
 
-	return OUT_BUFFER_SIZE;
+	return size;
 }
 
 static uint32_t out_get_channels(const struct audio_stream *stream)
@@ -407,8 +436,16 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
 	out->cfg.channels = AUDIO_CHANNEL_OUT_MONO;
 	out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+	out->cfg.frame_num = OUT_STREAM_FRAMES;
 	out->cfg.mtu = mtu;
 
+	out->downmix_buf = malloc(out_get_buffer_size(&out->stream.common));
+	if (!out->downmix_buf) {
+		free(out);
+		return -ENOMEM;
+	}
+
+	DBG("size %zd", out_get_buffer_size(&out->stream.common));
 	*stream_out = &out->stream;
 	adev->out = out;
 	out->fd = fd;
@@ -420,6 +457,7 @@ static void audio_close_output_stream(struct audio_hw_device *dev,
 					struct audio_stream_out *stream_out)
 {
 	struct hsp_audio_dev *hsp_dev = (struct hsp_audio_dev *) dev;
+	struct hsp_stream_out *out = (struct hsp_stream_out *) stream_out;
 
 	DBG("dev %p stream %p fd %d", dev, stream_out, hsp_dev->out->fd);
 
@@ -428,7 +466,8 @@ static void audio_close_output_stream(struct audio_hw_device *dev,
 		hsp_dev->out->fd = -1;
 	}
 
-	free(stream_out);
+	free(out->downmix_buf);
+	free(out);
 	hsp_dev->out = NULL;
 }
 
-- 
1.8.3.2


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

* [PATCHv3 11/12] android/audio: Use resampler interface to resample SCO
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (9 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 10/12] android/audio: Add downmix support to audio SCO HAL Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  2014-05-08  8:01 ` [PATCHv3 12/12] android/audio: Add write to SCO Andrei Emeltchenko
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

Resample Android audio from 44100 to 8000.
---
 android/hal-sco.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 105 insertions(+), 7 deletions(-)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index d55d34d..1ce7f15 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -27,6 +27,7 @@
 
 #include <hardware/audio.h>
 #include <hardware/hardware.h>
+#include <audio_utils/resampler.h>
 
 #include "../src/shared/util.h"
 #include "sco-msg.h"
@@ -34,6 +35,7 @@
 #include "hal-log.h"
 
 #define AUDIO_STREAM_DEFAULT_RATE	44100
+#define AUDIO_STREAM_SCO_RATE		8000
 #define AUDIO_STREAM_DEFAULT_FORMAT	AUDIO_FORMAT_PCM_16_BIT
 
 #define OUT_BUFFER_SIZE			2560
@@ -60,6 +62,10 @@ struct hsp_stream_out {
 	int fd;
 
 	uint8_t *downmix_buf;
+
+	struct resampler_itfe *resampler;
+	int16_t *resample_buf;
+	uint32_t resample_frame_num;
 };
 
 struct hsp_audio_dev {
@@ -67,6 +73,22 @@ struct hsp_audio_dev {
 	struct hsp_stream_out *out;
 };
 
+/*
+ * return the minimum frame numbers from resampling between BT stack's rate
+ * and audio flinger's. For output stream, 'output' shall be true, otherwise
+ * false for input streams at audio flinger side.
+ */
+static size_t get_resample_frame_num(uint32_t sco_rate, uint32_t rate,
+						size_t frame_num, bool output)
+{
+	size_t resample_frames_num = frame_num * sco_rate / rate + output;
+
+	DBG("resampler: sco_rate %d frame_num %zd rate %d resample frames %zd",
+				sco_rate, frame_num, rate, resample_frames_num);
+
+	return resample_frames_num;
+}
+
 /* Audio IPC functions */
 
 static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
@@ -258,6 +280,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 {
 	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
 	size_t frame_num = bytes / audio_stream_frame_size(&out->stream.common);
+	size_t output_frame_num = frame_num;
+	void *send_buf = out->downmix_buf;
+	size_t total;
 
 	DBG("write to fd %d bytes %zu", out->fd, bytes);
 
@@ -267,6 +292,34 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 	}
 
 	downmix_to_mono(out, buffer, frame_num);
+
+	if (out->resampler) {
+		int ret;
+
+		/* limit resampler's output within what resample buf can hold */
+		output_frame_num = out->resample_frame_num;
+
+		ret = out->resampler->resample_from_input(out->resampler,
+								send_buf,
+								&frame_num,
+								out->resample_buf,
+								&output_frame_num);
+		if (ret) {
+			error("Failed to resample frames: %zd input %zd (%s)",
+				frame_num, output_frame_num, strerror(ret));
+			return -1;
+		}
+
+		send_buf = out->resample_buf;
+
+		DBG("Resampled: frame_num %zd, output_frame_num %zd", 
+						frame_num, output_frame_num);
+	}
+
+	total = output_frame_num * sizeof(int16_t) * 1;
+
+	DBG("total %zd", total);
+
 	return bytes;
 }
 
@@ -299,19 +352,18 @@ static size_t out_get_buffer_size(const struct audio_stream *stream)
 
 static uint32_t out_get_channels(const struct audio_stream *stream)
 {
-	DBG("");
+	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
 
-	/* AudioFlinger can only provide stereo stream, so we return it here and
-	 * later we'll downmix this to mono in case codec requires it
-	 */
-	return AUDIO_CHANNEL_OUT_STEREO;
+	DBG("channels num: %u", popcount(out->cfg.channels));
+
+	return out->cfg.channels;
 }
 
 static audio_format_t out_get_format(const struct audio_stream *stream)
 {
 	struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
 
-	DBG("");
+	DBG("format: %u", out->cfg.format);
 
 	return out->cfg.format;
 }
@@ -401,6 +453,8 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	struct hsp_audio_dev *adev = (struct hsp_audio_dev *) dev;
 	struct hsp_stream_out *out;
 	int fd = -1;
+	int chan_num, ret;
+	size_t resample_size;
 	uint16_t mtu;
 
 	DBG("");
@@ -433,8 +487,9 @@ static int audio_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_MONO;
+	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;
@@ -446,11 +501,54 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
 	}
 
 	DBG("size %zd", out_get_buffer_size(&out->stream.common));
+
+	/* Channel numbers for resampler */
+	chan_num = 1;
+
+	ret = create_resampler(out->cfg.rate, AUDIO_STREAM_SCO_RATE, chan_num,
+						RESAMPLER_QUALITY_DEFAULT, NULL,
+						&out->resampler);
+	if (ret) {
+		error("Failed to create resampler (%s)", strerror(ret));
+		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);
+
+	if (!out->resample_frame_num) {
+		error("frame num is too small to resample, discard it");
+		goto failed;
+	}
+
+	resample_size = sizeof(int16_t) * chan_num * out->resample_frame_num;
+
+	out->resample_buf = malloc(resample_size);
+	if (!out->resample_buf) {
+		error("failed to allocate resample buffer for %u frames",
+						out->resample_frame_num);
+		goto failed;
+	}
+
+	DBG("resampler: frame num %u buf size %zd bytes", 
+					out->resample_frame_num, resample_size);
+
 	*stream_out = &out->stream;
 	adev->out = out;
 	out->fd = fd;
 
 	return 0;
+failed:
+	free(out->downmix_buf);
+	free(out);
+	stream_out = NULL;
+	adev->out = NULL;
+
+	return ret;
 }
 
 static void audio_close_output_stream(struct audio_hw_device *dev,
-- 
1.8.3.2


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

* [PATCHv3 12/12] android/audio: Add write to SCO
  2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
                   ` (10 preceding siblings ...)
  2014-05-08  8:01 ` [PATCHv3 11/12] android/audio: Use resampler interface to resample SCO Andrei Emeltchenko
@ 2014-05-08  8:01 ` Andrei Emeltchenko
  11 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:01 UTC (permalink / raw)
  To: linux-bluetooth

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

For synchronization interleave read() and write().
---
 android/hal-sco.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/android/hal-sco.c b/android/hal-sco.c
index 1ce7f15..c5dd712 100644
--- a/android/hal-sco.c
+++ b/android/hal-sco.c
@@ -41,6 +41,8 @@
 #define OUT_BUFFER_SIZE			2560
 #define OUT_STREAM_FRAMES		2560
 
+#define SOCKET_POLL_TIMEOUT_MS		500
+
 static int listen_sk = -1;
 static int audio_sk = -1;
 
@@ -275,6 +277,74 @@ static void downmix_to_mono(struct hsp_stream_out *out, const uint8_t *buffer,
 	}
 }
 
+static bool write_data(struct hsp_stream_out *out, const uint8_t *buffer,
+								size_t bytes)
+{
+	struct pollfd pfd;
+	size_t len, written = 0;
+	int ret;
+	uint16_t mtu = /* out->cfg.mtu */ 48;
+	uint8_t read_buf[mtu];
+	bool do_write = false;
+
+	pfd.fd = out->fd;
+	pfd.events = POLLOUT | POLLIN | POLLHUP | POLLNVAL;
+
+	while (bytes > written) {
+
+		/* poll for sending */
+		if (poll(&pfd, 1, SOCKET_POLL_TIMEOUT_MS) == 0) {
+			DBG("timeout fd %d", out->fd);
+			return false;
+		}
+
+		if (pfd.revents & (POLLHUP | POLLNVAL)) {
+			error("error fd %d, events 0x%x", out->fd, pfd.revents);
+			return false;
+		}
+
+		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;
+		}
+
+		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;
+			continue;
+		}
+
+		if (errno == EAGAIN) {
+			ret = errno;
+			warn("write failed (%d)", ret);
+			continue;
+		}
+
+		if (errno != EINTR) {
+			ret = errno;
+			error("write failed (%d) fd %d bytes %zd", ret, out->fd,
+									bytes);
+			return false;
+		}
+	}
+
+	DBG("written %zd bytes", bytes);
+
+	return true;
+}
+
 static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 								size_t bytes)
 {
@@ -320,6 +390,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
 
 	DBG("total %zd", total);
 
+	if (!write_data(out, send_buf, total))
+		return -1;
+
 	return bytes;
 }
 
-- 
1.8.3.2


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

* Re: [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling
  2014-05-08  8:01 ` [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling Andrei Emeltchenko
@ 2014-05-08  8:55   ` Andrei Emeltchenko
  2014-05-08  9:02     ` Andrei Emeltchenko
  2014-05-08  9:14     ` Szymon Janc
  0 siblings, 2 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  8:55 UTC (permalink / raw)
  To: linux-bluetooth

On Thu, May 08, 2014 at 11:01:32AM +0300, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> This adds audio HAL for handling SCO. Following needs to be added to
> audio_policy.conf:
> 
>   sco {
>     outputs {
>       sco {
>         ...
>         devices AUDIO_DEVICE_OUT_ALL_SCO
>         ...
>       }
>     }
> ---
>  android/Android.mk  |  23 ++++++
>  android/Makefile.am |  15 ++++
>  android/hal-sco.c   | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 249 insertions(+)
>  create mode 100644 android/hal-sco.c
> 
> diff --git a/android/Android.mk b/android/Android.mk
> index 638a042..b7b284d 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -271,6 +271,29 @@ LOCAL_MODULE := audio.a2dp.default
>  include $(BUILD_SHARED_LIBRARY)
>  
>  #
> +# SCO audio
> +#
> +
> +include $(CLEAR_VARS)
> +
> +LOCAL_SRC_FILES := bluez/android/hal-sco.c
> +
> +LOCAL_C_INCLUDES = \
> +	$(call include-path-for, system-core) \
> +	$(call include-path-for, libhardware) \
> +
> +LOCAL_SHARED_LIBRARIES := \
> +	libcutils \
> +
> +LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
> +
> +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
> +LOCAL_MODULE_TAGS := optional
> +LOCAL_MODULE := audio.sco.default

I changed hsp to sco, I think this is not a good idea here since hsp is
mentioned in audio_policy.conf

Best regards 
Andrei Emeltchenko 


> +
> +include $(BUILD_SHARED_LIBRARY)
> +
> +#
>  # l2cap-test
>  #
>  
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 5ab6411..990ce6b 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -169,6 +169,21 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
>  					android/hardware/hardware.h \
>  					android/system/audio.h
>  
> +android_audio_sco_default_la_SOURCES = android/audio-msg.h \
> +					android/hal-msg.h \
> +					android/hal-sco.c \
> +					android/hardware/audio.h \
> +					android/hardware/audio_effect.h \
> +					android/hardware/hardware.h \
> +					android/system/audio.h
> +
> +android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
> +
> +android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
> +					-no-undefined -lrt
> +
> +plugin_LTLIBRARIES += android/audio.sco.default.la
> +
>  unit_tests += android/test-ipc
>  
>  android_test_ipc_SOURCES = android/test-ipc.c \
> diff --git a/android/hal-sco.c b/android/hal-sco.c
> new file mode 100644
> index 0000000..c7ba504
> --- /dev/null
> +++ b/android/hal-sco.c
> @@ -0,0 +1,211 @@
> +/*
> + * Copyright (C) 2013 Intel Corporation
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *      http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + *
> + */
> +
> +#include <errno.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <hardware/audio.h>
> +#include <hardware/hardware.h>
> +
> +#include "hal-log.h"
> +
> +struct hsp_audio_dev {
> +	struct audio_hw_device dev;
> +	struct a2dp_stream_out *out;
> +};
> +
> +static int audio_open_output_stream(struct audio_hw_device *dev,
> +					audio_io_handle_t handle,
> +					audio_devices_t devices,
> +					audio_output_flags_t flags,
> +					struct audio_config *config,
> +					struct audio_stream_out **stream_out)
> +
> +{
> +	DBG("");
> +
> +	return -EINVAL;
> +}
> +
> +static void audio_close_output_stream(struct audio_hw_device *dev,
> +					struct audio_stream_out *stream_out)
> +{
> +	DBG("");
> +
> +	free(stream_out);
> +}
> +
> +static int audio_set_parameters(struct audio_hw_device *dev,
> +							const char *kvpairs)
> +{
> +	DBG("%s", kvpairs);
> +
> +	return 0;
> +}
> +
> +static char *audio_get_parameters(const struct audio_hw_device *dev,
> +							const char *keys)
> +{
> +	DBG("");
> +
> +	return strdup("");
> +}
> +
> +static int audio_init_check(const struct audio_hw_device *dev)
> +{
> +	DBG("");
> +
> +	return 0;
> +}
> +
> +static int audio_set_voice_volume(struct audio_hw_device *dev, float volume)
> +{
> +	DBG("%f", volume);
> +
> +	return 0;
> +}
> +
> +static int audio_set_master_volume(struct audio_hw_device *dev, float volume)
> +{
> +	DBG("%f", volume);
> +
> +	return 0;
> +}
> +
> +static int audio_set_mode(struct audio_hw_device *dev, int mode)
> +{
> +	DBG("");
> +
> +	return -ENOSYS;
> +}
> +
> +static int audio_set_mic_mute(struct audio_hw_device *dev, bool state)
> +{
> +	DBG("");
> +
> +	return -ENOSYS;
> +}
> +
> +static int audio_get_mic_mute(const struct audio_hw_device *dev, bool *state)
> +{
> +	DBG("");
> +
> +	return -ENOSYS;
> +}
> +
> +static size_t audio_get_input_buffer_size(const struct audio_hw_device *dev,
> +					const struct audio_config *config)
> +{
> +	DBG("");
> +
> +	return -ENOSYS;
> +}
> +
> +static int audio_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)
> +{
> +	DBG("");
> +
> +	return 0;
> +}
> +
> +static void audio_close_input_stream(struct audio_hw_device *dev,
> +					struct audio_stream_in *stream_in)
> +{
> +	DBG("");
> +
> +	free(stream_in);
> +}
> +
> +static int audio_dump(const audio_hw_device_t *device, int fd)
> +{
> +	DBG("");
> +
> +	return 0;
> +}
> +
> +static int audio_close(hw_device_t *device)
> +{
> +	DBG("");
> +
> +	free(device);
> +
> +	return 0;
> +}
> +
> +static int audio_open(const hw_module_t *module, const char *name,
> +							hw_device_t **device)
> +{
> +	struct hsp_audio_dev *adev;
> +
> +	DBG("");
> +
> +	if (strcmp(name, AUDIO_HARDWARE_INTERFACE)) {
> +		error("audio: interface %s not matching [%s]", name,
> +						AUDIO_HARDWARE_INTERFACE);
> +		return -EINVAL;
> +	}
> +
> +	adev = calloc(1, sizeof(struct hsp_audio_dev));
> +	if (!adev)
> +		return -ENOMEM;
> +
> +	adev->dev.common.tag = HARDWARE_DEVICE_TAG;
> +	adev->dev.common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
> +	adev->dev.common.module = (struct hw_module_t *) module;
> +	adev->dev.common.close = audio_close;
> +
> +	adev->dev.init_check = audio_init_check;
> +	adev->dev.set_voice_volume = audio_set_voice_volume;
> +	adev->dev.set_master_volume = audio_set_master_volume;
> +	adev->dev.set_mode = audio_set_mode;
> +	adev->dev.set_mic_mute = audio_set_mic_mute;
> +	adev->dev.get_mic_mute = audio_get_mic_mute;
> +	adev->dev.set_parameters = audio_set_parameters;
> +	adev->dev.get_parameters = audio_get_parameters;
> +	adev->dev.get_input_buffer_size = audio_get_input_buffer_size;
> +	adev->dev.open_output_stream = audio_open_output_stream;
> +	adev->dev.close_output_stream = audio_close_output_stream;
> +	adev->dev.open_input_stream = audio_open_input_stream;
> +	adev->dev.close_input_stream = audio_close_input_stream;
> +	adev->dev.dump = audio_dump;
> +
> +	*device = &adev->dev.common;
> +
> +	return 0;
> +}
> +
> +static struct hw_module_methods_t hal_module_methods = {
> +	.open = audio_open,
> +};
> +
> +struct audio_module HAL_MODULE_INFO_SYM = {
> +	.common = {
> +		.tag = HARDWARE_MODULE_TAG,
> +		.version_major = 1,
> +		.version_minor = 0,
> +		.id = AUDIO_HARDWARE_MODULE_ID,
> +		.name = "HSP Audio HW HAL",
> +		.author = "Intel Corporation",
> +		.methods = &hal_module_methods,
> +	},
> +};
> -- 
> 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

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

* Re: [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling
  2014-05-08  8:55   ` Andrei Emeltchenko
@ 2014-05-08  9:02     ` Andrei Emeltchenko
  2014-05-08  9:14     ` Szymon Janc
  1 sibling, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  9:02 UTC (permalink / raw)
  To: linux-bluetooth

On Thu, May 08, 2014 at 11:55:47AM +0300, Andrei Emeltchenko wrote:
> On Thu, May 08, 2014 at 11:01:32AM +0300, Andrei Emeltchenko wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > 
> > This adds audio HAL for handling SCO. Following needs to be added to
> > audio_policy.conf:
> > 
> >   sco {
> >     outputs {
> >       sco {
> >         ...
> >         devices AUDIO_DEVICE_OUT_ALL_SCO
> >         ...
> >       }
> >     }
> > ---
> >  android/Android.mk  |  23 ++++++
> >  android/Makefile.am |  15 ++++
> >  android/hal-sco.c   | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 249 insertions(+)
> >  create mode 100644 android/hal-sco.c
> > 
> > diff --git a/android/Android.mk b/android/Android.mk
> > index 638a042..b7b284d 100644
> > --- a/android/Android.mk
> > +++ b/android/Android.mk
> > @@ -271,6 +271,29 @@ LOCAL_MODULE := audio.a2dp.default
> >  include $(BUILD_SHARED_LIBRARY)
> >  
> >  #
> > +# SCO audio
> > +#
> > +
> > +include $(CLEAR_VARS)
> > +
> > +LOCAL_SRC_FILES := bluez/android/hal-sco.c
> > +
> > +LOCAL_C_INCLUDES = \
> > +	$(call include-path-for, system-core) \
> > +	$(call include-path-for, libhardware) \
> > +
> > +LOCAL_SHARED_LIBRARIES := \
> > +	libcutils \
> > +
> > +LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
> > +
> > +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
> > +LOCAL_MODULE_TAGS := optional
> > +LOCAL_MODULE := audio.sco.default
> 
> I changed hsp to sco, I think this is not a good idea here since hsp is
> mentioned in audio_policy.conf

Here:
https://github.com/android-ia/device_intel_mixins/blob/master/audio/hsw_alc282/audio_policy.conf

  hsp {
    outputs {
      hsp {
        sampling_rates 44100
        channel_masks AUDIO_CHANNEL_OUT_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_ALL_SCO
      }
    }
    inputs {
      hsp {
        sampling_rates 44100
        channel_masks AUDIO_CHANNEL_IN_MONO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET
      }
    }
  }


Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling
  2014-05-08  8:55   ` Andrei Emeltchenko
  2014-05-08  9:02     ` Andrei Emeltchenko
@ 2014-05-08  9:14     ` Szymon Janc
  2014-05-08  9:35       ` Andrei Emeltchenko
  1 sibling, 1 reply; 19+ messages in thread
From: Szymon Janc @ 2014-05-08  9:14 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth

Hi Andrei,

On Thursday 08 of May 2014 11:55:47 Andrei Emeltchenko wrote:
> On Thu, May 08, 2014 at 11:01:32AM +0300, Andrei Emeltchenko wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > 
> > This adds audio HAL for handling SCO. Following needs to be added to
> > audio_policy.conf:
> > 
> >   sco {
> >     outputs {
> >       sco {
> >         ...
> >         devices AUDIO_DEVICE_OUT_ALL_SCO
> >         ...
> >       }
> >     }
> > ---
> >  android/Android.mk  |  23 ++++++
> >  android/Makefile.am |  15 ++++
> >  android/hal-sco.c   | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 249 insertions(+)
> >  create mode 100644 android/hal-sco.c
> > 
> > diff --git a/android/Android.mk b/android/Android.mk
> > index 638a042..b7b284d 100644
> > --- a/android/Android.mk
> > +++ b/android/Android.mk
> > @@ -271,6 +271,29 @@ LOCAL_MODULE := audio.a2dp.default
> >  include $(BUILD_SHARED_LIBRARY)
> >  
> >  #
> > +# SCO audio
> > +#
> > +
> > +include $(CLEAR_VARS)
> > +
> > +LOCAL_SRC_FILES := bluez/android/hal-sco.c
> > +
> > +LOCAL_C_INCLUDES = \
> > +	$(call include-path-for, system-core) \
> > +	$(call include-path-for, libhardware) \
> > +
> > +LOCAL_SHARED_LIBRARIES := \
> > +	libcutils \
> > +
> > +LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
> > +
> > +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
> > +LOCAL_MODULE_TAGS := optional
> > +LOCAL_MODULE := audio.sco.default
> 
> I changed hsp to sco, I think this is not a good idea here since hsp is
> mentioned in audio_policy.conf

Different devices have different customizations in audio_policy.conf.
If one is integrating BlueZ he should provide proper audio_policy.conf anyway.

IMHO sco is better name here.

 
> Best regards 
> Andrei Emeltchenko 
> 
> 
> > +
> > +include $(BUILD_SHARED_LIBRARY)
> > +
> > +#
> >  # l2cap-test
> >  #
> >  
> > diff --git a/android/Makefile.am b/android/Makefile.am
> > index 5ab6411..990ce6b 100644
> > --- a/android/Makefile.am
> > +++ b/android/Makefile.am
> > @@ -169,6 +169,21 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
> >  					android/hardware/hardware.h \
> >  					android/system/audio.h
> >  
> > +android_audio_sco_default_la_SOURCES = android/audio-msg.h \
> > +					android/hal-msg.h \
> > +					android/hal-sco.c \
> > +					android/hardware/audio.h \
> > +					android/hardware/audio_effect.h \
> > +					android/hardware/hardware.h \
> > +					android/system/audio.h
> > +
> > +android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
> > +
> > +android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
> > +					-no-undefined -lrt
> > +
> > +plugin_LTLIBRARIES += android/audio.sco.default.la
> > +
> >  unit_tests += android/test-ipc
> >  
> >  android_test_ipc_SOURCES = android/test-ipc.c \
> > diff --git a/android/hal-sco.c b/android/hal-sco.c
> > new file mode 100644
> > index 0000000..c7ba504
> > --- /dev/null
> > +++ b/android/hal-sco.c
> > @@ -0,0 +1,211 @@
> > +/*
> > + * Copyright (C) 2013 Intel Corporation
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at
> > + *
> > + *      http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + *
> > + */
> > +
> > +#include <errno.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +
> > +#include <hardware/audio.h>
> > +#include <hardware/hardware.h>
> > +
> > +#include "hal-log.h"
> > +
> > +struct hsp_audio_dev {
> > +	struct audio_hw_device dev;
> > +	struct a2dp_stream_out *out;
> > +};
> > +
> > +static int audio_open_output_stream(struct audio_hw_device *dev,
> > +					audio_io_handle_t handle,
> > +					audio_devices_t devices,
> > +					audio_output_flags_t flags,
> > +					struct audio_config *config,
> > +					struct audio_stream_out **stream_out)
> > +
> > +{
> > +	DBG("");
> > +
> > +	return -EINVAL;
> > +}
> > +
> > +static void audio_close_output_stream(struct audio_hw_device *dev,
> > +					struct audio_stream_out *stream_out)
> > +{
> > +	DBG("");
> > +
> > +	free(stream_out);
> > +}
> > +
> > +static int audio_set_parameters(struct audio_hw_device *dev,
> > +							const char *kvpairs)
> > +{
> > +	DBG("%s", kvpairs);
> > +
> > +	return 0;
> > +}
> > +
> > +static char *audio_get_parameters(const struct audio_hw_device *dev,
> > +							const char *keys)
> > +{
> > +	DBG("");
> > +
> > +	return strdup("");
> > +}
> > +
> > +static int audio_init_check(const struct audio_hw_device *dev)
> > +{
> > +	DBG("");
> > +
> > +	return 0;
> > +}
> > +
> > +static int audio_set_voice_volume(struct audio_hw_device *dev, float volume)
> > +{
> > +	DBG("%f", volume);
> > +
> > +	return 0;
> > +}
> > +
> > +static int audio_set_master_volume(struct audio_hw_device *dev, float volume)
> > +{
> > +	DBG("%f", volume);
> > +
> > +	return 0;
> > +}
> > +
> > +static int audio_set_mode(struct audio_hw_device *dev, int mode)
> > +{
> > +	DBG("");
> > +
> > +	return -ENOSYS;
> > +}
> > +
> > +static int audio_set_mic_mute(struct audio_hw_device *dev, bool state)
> > +{
> > +	DBG("");
> > +
> > +	return -ENOSYS;
> > +}
> > +
> > +static int audio_get_mic_mute(const struct audio_hw_device *dev, bool *state)
> > +{
> > +	DBG("");
> > +
> > +	return -ENOSYS;
> > +}
> > +
> > +static size_t audio_get_input_buffer_size(const struct audio_hw_device *dev,
> > +					const struct audio_config *config)
> > +{
> > +	DBG("");
> > +
> > +	return -ENOSYS;
> > +}
> > +
> > +static int audio_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)
> > +{
> > +	DBG("");
> > +
> > +	return 0;
> > +}
> > +
> > +static void audio_close_input_stream(struct audio_hw_device *dev,
> > +					struct audio_stream_in *stream_in)
> > +{
> > +	DBG("");
> > +
> > +	free(stream_in);
> > +}
> > +
> > +static int audio_dump(const audio_hw_device_t *device, int fd)
> > +{
> > +	DBG("");
> > +
> > +	return 0;
> > +}
> > +
> > +static int audio_close(hw_device_t *device)
> > +{
> > +	DBG("");
> > +
> > +	free(device);
> > +
> > +	return 0;
> > +}
> > +
> > +static int audio_open(const hw_module_t *module, const char *name,
> > +							hw_device_t **device)
> > +{
> > +	struct hsp_audio_dev *adev;
> > +
> > +	DBG("");
> > +
> > +	if (strcmp(name, AUDIO_HARDWARE_INTERFACE)) {
> > +		error("audio: interface %s not matching [%s]", name,
> > +						AUDIO_HARDWARE_INTERFACE);
> > +		return -EINVAL;
> > +	}
> > +
> > +	adev = calloc(1, sizeof(struct hsp_audio_dev));
> > +	if (!adev)
> > +		return -ENOMEM;
> > +
> > +	adev->dev.common.tag = HARDWARE_DEVICE_TAG;
> > +	adev->dev.common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
> > +	adev->dev.common.module = (struct hw_module_t *) module;
> > +	adev->dev.common.close = audio_close;
> > +
> > +	adev->dev.init_check = audio_init_check;
> > +	adev->dev.set_voice_volume = audio_set_voice_volume;
> > +	adev->dev.set_master_volume = audio_set_master_volume;
> > +	adev->dev.set_mode = audio_set_mode;
> > +	adev->dev.set_mic_mute = audio_set_mic_mute;
> > +	adev->dev.get_mic_mute = audio_get_mic_mute;
> > +	adev->dev.set_parameters = audio_set_parameters;
> > +	adev->dev.get_parameters = audio_get_parameters;
> > +	adev->dev.get_input_buffer_size = audio_get_input_buffer_size;
> > +	adev->dev.open_output_stream = audio_open_output_stream;
> > +	adev->dev.close_output_stream = audio_close_output_stream;
> > +	adev->dev.open_input_stream = audio_open_input_stream;
> > +	adev->dev.close_input_stream = audio_close_input_stream;
> > +	adev->dev.dump = audio_dump;
> > +
> > +	*device = &adev->dev.common;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct hw_module_methods_t hal_module_methods = {
> > +	.open = audio_open,
> > +};
> > +
> > +struct audio_module HAL_MODULE_INFO_SYM = {
> > +	.common = {
> > +		.tag = HARDWARE_MODULE_TAG,
> > +		.version_major = 1,
> > +		.version_minor = 0,
> > +		.id = AUDIO_HARDWARE_MODULE_ID,
> > +		.name = "HSP Audio HW HAL",
> > +		.author = "Intel Corporation",
> > +		.methods = &hal_module_methods,
> > +	},
> > +};
> --
> 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

-- 
Best regards, 
Szymon Janc

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

* Re: [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling
  2014-05-08  9:14     ` Szymon Janc
@ 2014-05-08  9:35       ` Andrei Emeltchenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08  9:35 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

On Thu, May 08, 2014 at 11:14:12AM +0200, Szymon Janc wrote:
> Hi Andrei,
> 
> On Thursday 08 of May 2014 11:55:47 Andrei Emeltchenko wrote:
> > On Thu, May 08, 2014 at 11:01:32AM +0300, Andrei Emeltchenko wrote:
> > > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > > 
> > > This adds audio HAL for handling SCO. Following needs to be added to
> > > audio_policy.conf:
> > > 
> > >   sco {
> > >     outputs {
> > >       sco {
> > >         ...
> > >         devices AUDIO_DEVICE_OUT_ALL_SCO
> > >         ...
> > >       }
> > >     }
> > > ---
> > >  android/Android.mk  |  23 ++++++
> > >  android/Makefile.am |  15 ++++
> > >  android/hal-sco.c   | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 249 insertions(+)
> > >  create mode 100644 android/hal-sco.c
> > > 
> > > diff --git a/android/Android.mk b/android/Android.mk
> > > index 638a042..b7b284d 100644
> > > --- a/android/Android.mk
> > > +++ b/android/Android.mk
> > > @@ -271,6 +271,29 @@ LOCAL_MODULE := audio.a2dp.default
> > >  include $(BUILD_SHARED_LIBRARY)
> > >  
> > >  #
> > > +# SCO audio
> > > +#
> > > +
> > > +include $(CLEAR_VARS)
> > > +
> > > +LOCAL_SRC_FILES := bluez/android/hal-sco.c
> > > +
> > > +LOCAL_C_INCLUDES = \
> > > +	$(call include-path-for, system-core) \
> > > +	$(call include-path-for, libhardware) \
> > > +
> > > +LOCAL_SHARED_LIBRARIES := \
> > > +	libcutils \
> > > +
> > > +LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
> > > +
> > > +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
> > > +LOCAL_MODULE_TAGS := optional
> > > +LOCAL_MODULE := audio.sco.default
> > 
> > I changed hsp to sco, I think this is not a good idea here since hsp is
> > mentioned in audio_policy.conf
> 
> Different devices have different customizations in audio_policy.conf.
> If one is integrating BlueZ he should provide proper audio_policy.conf anyway.
> 
> IMHO sco is better name here.

My idea was to make as little changes as possible to the existing code.
There is always a better name ;)

Best regards 
Andrei Emeltchenko 

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

* Re: [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream()
  2014-05-08  8:01 ` [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream() Andrei Emeltchenko
@ 2014-05-08 11:24   ` Luiz Augusto von Dentz
  2014-05-08 11:50     ` Andrei Emeltchenko
  0 siblings, 1 reply; 19+ messages in thread
From: Luiz Augusto von Dentz @ 2014-05-08 11:24 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org

Hi Andrei,

On Thu, May 8, 2014 at 11:01 AM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Function adds audio_open_output_stream() and sets dummy callbacks.
> ---
>  android/hal-sco.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 176 insertions(+), 3 deletions(-)
>
> diff --git a/android/hal-sco.c b/android/hal-sco.c
> index c7ba504..bc7d987 100644
> --- a/android/hal-sco.c
> +++ b/android/hal-sco.c
> @@ -25,22 +25,195 @@
>
>  #include "hal-log.h"
>
> +#define AUDIO_STREAM_DEFAULT_RATE      44100
> +#define AUDIO_STREAM_DEFAULT_FORMAT    AUDIO_FORMAT_PCM_16_BIT
> +
> +#define OUT_BUFFER_SIZE                        2560
> +
> +struct hsp_audio_config {
> +       uint32_t rate;
> +       uint32_t channels;
> +       audio_format_t format;
> +};
> +
> +struct hsp_stream_out {
> +       struct audio_stream_out stream;
> +       struct hsp_audio_config cfg;
> +};
> +
>  struct hsp_audio_dev {
>         struct audio_hw_device dev;
> -       struct a2dp_stream_out *out;
> +       struct hsp_stream_out *out;
>  };

Please rename hsp to sco, also fix where you actually introduced
a2dp_stream_out.

Tip: you can use git rebase -i origin/master change the commit that
want to fix from pick to edit once you are done do git add and git
rebase --continue

> +/* Audio stream functions */
> +
> +static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
> +                                                               size_t bytes)
> +{
> +       /* write data */
> +
> +       return bytes;
> +}
> +
> +static uint32_t out_get_sample_rate(const struct audio_stream *stream)
> +{
> +       struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
> +
> +       DBG("rate %u", out->cfg.rate);
> +
> +       return out->cfg.rate;
> +}
> +
> +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
> +{
> +       DBG("rate %u", rate);
> +
> +       return 0;
> +}
> +
> +static size_t out_get_buffer_size(const struct audio_stream *stream)
> +{
> +       DBG("buf size %u", OUT_BUFFER_SIZE);
> +
> +       return OUT_BUFFER_SIZE;
> +}
> +
> +static uint32_t out_get_channels(const struct audio_stream *stream)
> +{
> +       DBG("");
> +
> +       /* AudioFlinger can only provide stereo stream, so we return it here and
> +        * later we'll downmix this to mono in case codec requires it
> +        */
> +       return AUDIO_CHANNEL_OUT_STEREO;
> +}
> +
> +static audio_format_t out_get_format(const struct audio_stream *stream)
> +{
> +       struct hsp_stream_out *out = (struct hsp_stream_out *) stream;
> +
> +       DBG("");
> +
> +       return out->cfg.format;
> +}
> +
> +static int out_set_format(struct audio_stream *stream, audio_format_t format)
> +{
> +       DBG("");
> +
> +       return -ENOSYS;
> +}
> +
> +static int out_standby(struct audio_stream *stream)
> +{
> +       DBG("");
> +
> +       return 0;
> +}
> +
> +static int out_dump(const struct audio_stream *stream, int fd)
> +{
> +       DBG("");
> +
> +       return -ENOSYS;
> +}
> +
> +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
> +{
> +       DBG("%s", kvpairs);
> +
> +       return 0;
> +}
> +
> +static char *out_get_parameters(const struct audio_stream *stream,
> +                                                       const char *keys)
> +{
> +       DBG("");
> +
> +       return strdup("");
> +}
> +
> +static uint32_t out_get_latency(const struct audio_stream_out *stream)
> +{
> +       DBG("");
> +
> +       return 0;
> +}
> +
> +static int out_set_volume(struct audio_stream_out *stream, float left,
> +                                                               float right)
> +{
> +       DBG("");
> +
> +       return -ENOSYS;
> +}
> +
> +static int out_get_render_position(const struct audio_stream_out *stream,
> +                                                       uint32_t *dsp_frames)
> +{
> +       DBG("");
> +
> +       return -ENOSYS;
> +}
> +
> +static int out_add_audio_effect(const struct audio_stream *stream,
> +                                                       effect_handle_t effect)
> +{
> +       DBG("");
> +
> +       return -ENOSYS;
> +}
> +
> +static int out_remove_audio_effect(const struct audio_stream *stream,
> +                                                       effect_handle_t effect)
> +{
> +       DBG("");
> +
> +       return -ENOSYS;
> +}
> +
>  static int audio_open_output_stream(struct audio_hw_device *dev,
>                                         audio_io_handle_t handle,
>                                         audio_devices_t devices,
>                                         audio_output_flags_t flags,
>                                         struct audio_config *config,
>                                         struct audio_stream_out **stream_out)
> -
>  {
> +       struct hsp_audio_dev *adev = (struct hsp_audio_dev *) dev;
> +       struct hsp_stream_out *out;
> +
>         DBG("");
>
> -       return -EINVAL;
> +       out = calloc(1, sizeof(struct hsp_stream_out));
> +       if (!out)
> +               return -ENOMEM;
> +
> +       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;
> +       out->stream.common.get_channels = out_get_channels;
> +       out->stream.common.get_format = out_get_format;
> +       out->stream.common.set_format = out_set_format;
> +       out->stream.common.standby = out_standby;
> +       out->stream.common.dump = out_dump;
> +       out->stream.common.set_parameters = out_set_parameters;
> +       out->stream.common.get_parameters = out_get_parameters;
> +       out->stream.common.add_audio_effect = out_add_audio_effect;
> +       out->stream.common.remove_audio_effect = out_remove_audio_effect;
> +       out->stream.get_latency = out_get_latency;
> +       out->stream.set_volume = out_set_volume;
> +       out->stream.write = out_write;
> +       out->stream.get_render_position = out_get_render_position;
> +
> +       out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
> +       out->cfg.channels = AUDIO_CHANNEL_OUT_MONO;
> +       out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
> +
> +       *stream_out = &out->stream;
> +       adev->out = out;
> +
> +       return 0;
>  }
>
>  static void audio_close_output_stream(struct audio_hw_device *dev,
> --
> 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: [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream()
  2014-05-08 11:24   ` Luiz Augusto von Dentz
@ 2014-05-08 11:50     ` Andrei Emeltchenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrei Emeltchenko @ 2014-05-08 11:50 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org

On Thu, May 08, 2014 at 02:24:15PM +0300, Luiz Augusto von Dentz wrote:
> Hi Andrei,
> 
> On Thu, May 8, 2014 at 11:01 AM, Andrei Emeltchenko
> <Andrei.Emeltchenko.news@gmail.com> wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > Function adds audio_open_output_stream() and sets dummy callbacks.
> > ---
> >  android/hal-sco.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 176 insertions(+), 3 deletions(-)
> >
> > diff --git a/android/hal-sco.c b/android/hal-sco.c
> > index c7ba504..bc7d987 100644
> > --- a/android/hal-sco.c
> > +++ b/android/hal-sco.c
> > @@ -25,22 +25,195 @@
> >
> >  #include "hal-log.h"
> >
> > +#define AUDIO_STREAM_DEFAULT_RATE      44100
> > +#define AUDIO_STREAM_DEFAULT_FORMAT    AUDIO_FORMAT_PCM_16_BIT
> > +
> > +#define OUT_BUFFER_SIZE                        2560
> > +
> > +struct hsp_audio_config {
> > +       uint32_t rate;
> > +       uint32_t channels;
> > +       audio_format_t format;
> > +};
> > +
> > +struct hsp_stream_out {
> > +       struct audio_stream_out stream;
> > +       struct hsp_audio_config cfg;
> > +};
> > +
> >  struct hsp_audio_dev {
> >         struct audio_hw_device dev;
> > -       struct a2dp_stream_out *out;
> > +       struct hsp_stream_out *out;
> >  };
> 
> Please rename hsp to sco, also fix where you actually introduced
> a2dp_stream_out.
> 
> Tip: you can use git rebase -i origin/master change the commit that
> want to fix from pick to edit once you are done do git add and git
> rebase --continue

This might be done with git filter-branch which renames it in all patches.

Best regards 
Andrei Emeltchenko 


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

end of thread, other threads:[~2014-05-08 11:50 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-08  8:01 [PATCHv3 00/12] SCO Audio interface for Android Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 01/12] android/hal-sco: Add audio HAL for SCO handling Andrei Emeltchenko
2014-05-08  8:55   ` Andrei Emeltchenko
2014-05-08  9:02     ` Andrei Emeltchenko
2014-05-08  9:14     ` Szymon Janc
2014-05-08  9:35       ` Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 02/12] android/hal-audio-hsp: Add open_output_stream() Andrei Emeltchenko
2014-05-08 11:24   ` Luiz Augusto von Dentz
2014-05-08 11:50     ` Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 03/12] android/audio: Add Audio SCO message API Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 04/12] android/handsfree: Add SCO Audio IPC Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 05/12] android/hal-sco: Implement Audio IPC on Audio HAL Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 06/12] android/ipc: Use error printing error messages Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 07/12] android/haltest: Add testinng for audio SCO HAL Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 08/12] android/audio: Add resampler support Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 09/12] audio/haltest: Make audio_stream static Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 10/12] android/audio: Add downmix support to audio SCO HAL Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 11/12] android/audio: Use resampler interface to resample SCO Andrei Emeltchenko
2014-05-08  8:01 ` [PATCHv3 12/12] android/audio: Add write to SCO Andrei Emeltchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox