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

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

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