summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2020-11-27 16:33:10 +0100
committerDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2020-11-27 16:59:06 +0100
commit793fd4961605352ae711d0e40a1879864655204d (patch)
tree32dffdf27fc482f59ca4709cd4bbb5aec00c49ec
parentcabace3fafc736d0d42ac9c7e89073e77c0d839c (diff)
downloaddevice_samsung_midas-common-793fd4961605352ae711d0e40a1879864655204d.tar.gz
device_samsung_midas-common-793fd4961605352ae711d0e40a1879864655204d.tar.bz2
device_samsung_midas-common-793fd4961605352ae711d0e40a1879864655204d.zip
Import dragonboard audio library
The audio directory from the dragonboard git[1] is imported as-is from the following commit: bc02e153097048c72e86037920a19a286fb012ca bc02e15 Snap for 6191568 from 7f47f75eaf9d475bbcdd78343e9a40cf6d986874 to rvc-release For some reasons merely adding the following to midas.mk: PRODUCT_PACKAGES += audio.primary.exynos4 wasn't enough to get an audio.primary.exynos4.so library in the out/target/product/i9300 directory. Importing this audio library here fixes that. In addition, if we look at the audio library in audio being used in Replicant 6 for the GT-I9300[2], in audio/ we have calls to several functions related to the RIL, like ril_open, ril_close, ril_register_set_wb_amr_callback, ril_set_call_audio_path, and so on. Because of that we will most probably need to implement something similar to make audio work in calls, so it's probably best to fork that library anyway, at least for the GT-I9300. References: ----------- [1]https://android.googlesource.com/device/linaro/dragonboard [2]https://git.replicant.us/replicant/device_samsung_i9300.git Thanks to Joonas Kylmälä who identified that the dragonboard audio library worked out of the box on Android 11 for the Galaxy SIII 4G (GT-I9305). Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
-rw-r--r--audio/Android.mk41
-rw-r--r--audio/audio_hw.c691
2 files changed, 732 insertions, 0 deletions
diff --git a/audio/Android.mk b/audio/Android.mk
new file mode 100644
index 0000000..afa804f
--- /dev/null
+++ b/audio/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# The default audio HAL module, which is a stub, that is loaded if no other
+# device specific modules are present. The exact load order can be seen in
+# libhardware/hardware.c
+#
+# The format of the name is audio.<type>.<hardware/etc>.so where the only
+# required type is 'primary'. Other possibilites are 'a2dp', 'usb', etc.
+include $(CLEAR_VARS)
+
+LOCAL_HEADER_LIBRARIES += libhardware_headers
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/hw
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/hw
+LOCAL_VENDOR_MODULE := true
+
+LOCAL_SRC_FILES := audio_hw.c
+LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_C_INCLUDES += \
+ external/tinyalsa/include \
+ external/expat/lib \
+ system/media/audio_utils/include \
+ system/media/audio_effects/include
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
new file mode 100644
index 0000000..d601ea8
--- /dev/null
+++ b/audio/audio_hw.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2016 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_TAG "audio_hw_dragonboard"
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <sound/asound.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_utils/resampler.h>
+#include <audio_utils/echo_reference.h>
+#include <hardware/audio_effect.h>
+#include <hardware/audio_alsaops.h>
+#include <audio_effects/effect_aec.h>
+
+
+#define CARD_OUT 0
+#define PORT_CODEC 0
+/* Minimum granularity - Arbitrary but small value */
+#define CODEC_BASE_FRAME_COUNT 32
+
+/* number of base blocks in a short period (low latency) */
+#define PERIOD_MULTIPLIER 32 /* 21 ms */
+/* number of frames per short period (low latency) */
+#define PERIOD_SIZE (CODEC_BASE_FRAME_COUNT * PERIOD_MULTIPLIER)
+/* number of pseudo periods for low latency playback */
+#define PLAYBACK_PERIOD_COUNT 2
+#define PLAYBACK_PERIOD_START_THRESHOLD 2
+#define CODEC_SAMPLING_RATE 48000
+#define CHANNEL_STEREO 2
+#define MIN_WRITE_SLEEP_US 5000
+
+struct stub_stream_in {
+ struct audio_stream_in stream;
+};
+
+struct alsa_audio_device {
+ struct audio_hw_device hw_device;
+
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ int devices;
+ struct alsa_stream_in *active_input;
+ struct alsa_stream_out *active_output;
+ bool mic_mute;
+};
+
+struct alsa_stream_out {
+ struct audio_stream_out stream;
+
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ struct pcm_config config;
+ struct pcm *pcm;
+ bool unavailable;
+ int standby;
+ struct alsa_audio_device *dev;
+ int write_threshold;
+ unsigned int written;
+};
+
+
+/* must be called with hw device and output stream mutexes locked */
+static int start_output_stream(struct alsa_stream_out *out)
+{
+ struct alsa_audio_device *adev = out->dev;
+
+ if (out->unavailable)
+ return -ENODEV;
+
+ /* default to low power: will be corrected in out_write if necessary before first write to
+ * tinyalsa.
+ */
+ out->write_threshold = PLAYBACK_PERIOD_COUNT * PERIOD_SIZE;
+ out->config.start_threshold = PLAYBACK_PERIOD_START_THRESHOLD * PERIOD_SIZE;
+ out->config.avail_min = PERIOD_SIZE;
+
+ out->pcm = pcm_open(CARD_OUT, PORT_CODEC, PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC, &out->config);
+
+ if (!pcm_is_ready(out->pcm)) {
+ ALOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm));
+ pcm_close(out->pcm);
+ adev->active_output = NULL;
+ out->unavailable = true;
+ return -ENODEV;
+ }
+
+ adev->active_output = out;
+ return 0;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ return out->config.rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ ALOGV("out_set_sample_rate: %d", 0);
+ return -ENOSYS;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ ALOGV("out_get_buffer_size: %d", 4096);
+
+ /* return the closest majoring multiple of 16 frames, as
+ * audioflinger expects audio buffers to be a multiple of 16 frames */
+ size_t size = PERIOD_SIZE;
+ size = ((size + 15) / 16) * 16;
+ return size * audio_stream_out_frame_size((struct audio_stream_out *)stream);
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+ ALOGV("out_get_channels");
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ return audio_channel_out_mask_from_count(out->config.channels);
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ ALOGV("out_get_format");
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ return audio_format_from_pcm_format(out->config.format);
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ ALOGV("out_set_format: %d",format);
+ return -ENOSYS;
+}
+
+static int do_output_standby(struct alsa_stream_out *out)
+{
+ struct alsa_audio_device *adev = out->dev;
+
+ if (!out->standby) {
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+ adev->active_output = NULL;
+ out->standby = 1;
+ }
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ ALOGV("out_standby");
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ int status;
+
+ pthread_mutex_lock(&out->dev->lock);
+ pthread_mutex_lock(&out->lock);
+ status = do_output_standby(out);
+ pthread_mutex_unlock(&out->lock);
+ pthread_mutex_unlock(&out->dev->lock);
+ return status;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+ ALOGV("out_dump");
+ return 0;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ ALOGV("out_set_parameters");
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ struct alsa_audio_device *adev = out->dev;
+ struct str_parms *parms;
+ char value[32];
+ int ret, val = 0;
+
+ parms = str_parms_create_str(kvpairs);
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (((adev->devices & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0)) {
+ adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
+ adev->devices |= val;
+ }
+ pthread_mutex_unlock(&out->lock);
+ pthread_mutex_unlock(&adev->lock);
+ }
+
+ str_parms_destroy(parms);
+ return ret;
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ ALOGV("out_get_parameters");
+ return strdup("");
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ ALOGV("out_get_latency");
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ return (PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * 1000) / out->config.rate;
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ ALOGV("out_set_volume: Left:%f Right:%f", left, right);
+ return 0;
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+ size_t bytes)
+{
+ int ret;
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ struct alsa_audio_device *adev = out->dev;
+ size_t frame_size = audio_stream_out_frame_size(stream);
+ size_t out_frames = bytes / frame_size;
+
+ /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
+ * on the output stream mutex - e.g. executing select_mode() while holding the hw device
+ * mutex
+ */
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&out->lock);
+ if (out->standby) {
+ ret = start_output_stream(out);
+ if (ret != 0) {
+ pthread_mutex_unlock(&adev->lock);
+ goto exit;
+ }
+ out->standby = 0;
+ }
+
+ pthread_mutex_unlock(&adev->lock);
+
+ ret = pcm_mmap_write(out->pcm, buffer, out_frames * frame_size);
+ if (ret == 0) {
+ out->written += out_frames;
+ }
+exit:
+ pthread_mutex_unlock(&out->lock);
+
+ if (ret != 0) {
+ usleep((int64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
+ out_get_sample_rate(&stream->common));
+ }
+
+ return bytes;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ *dsp_frames = 0;
+ ALOGV("out_get_render_position: dsp_frames: %p", dsp_frames);
+ return -EINVAL;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+ uint64_t *frames, struct timespec *timestamp)
+{
+ struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
+ int ret = -1;
+
+ if (out->pcm) {
+ unsigned int avail;
+ if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
+ size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
+ int64_t signed_frames = out->written - kernel_buffer_size + avail;
+ if (signed_frames >= 0) {
+ *frames = signed_frames;
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ ALOGV("out_add_audio_effect: %p", effect);
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ ALOGV("out_remove_audio_effect: %p", effect);
+ return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp)
+{
+ *timestamp = 0;
+ ALOGV("out_get_next_write_timestamp: %ld", (long int)(*timestamp));
+ return -EINVAL;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ ALOGV("in_get_sample_rate");
+ return 8000;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ ALOGV("in_set_sample_rate: %d", rate);
+ return -ENOSYS;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ ALOGV("in_get_buffer_size: %d", 320);
+ return 320;
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+ ALOGV("in_get_channels: %d", AUDIO_CHANNEL_IN_MONO);
+ return AUDIO_CHANNEL_IN_MONO;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+ return 0;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+ return 0;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ return 0;
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ return strdup("");
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+ return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+ size_t bytes)
+{
+ ALOGV("in_read: bytes %zu", bytes);
+ /* XXX: fake timing for audio input */
+ usleep((int64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
+ in_get_sample_rate(&stream->common));
+ memset(buffer, 0, bytes);
+ return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+ return 0;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int adev_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,
+ const char *address __unused)
+{
+ ALOGV("adev_open_output_stream...");
+
+ struct alsa_audio_device *ladev = (struct alsa_audio_device *)dev;
+ struct alsa_stream_out *out;
+ struct pcm_params *params;
+ int ret = 0;
+
+ params = pcm_params_get(CARD_OUT, PORT_CODEC, PCM_OUT);
+ if (!params)
+ return -ENOSYS;
+
+ out = (struct alsa_stream_out *)calloc(1, sizeof(struct alsa_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->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+ out->stream.get_presentation_position = out_get_presentation_position;
+
+ out->config.channels = CHANNEL_STEREO;
+ out->config.rate = CODEC_SAMPLING_RATE;
+ out->config.format = PCM_FORMAT_S16_LE;
+ out->config.period_size = PERIOD_SIZE;
+ out->config.period_count = PLAYBACK_PERIOD_COUNT;
+
+ if (out->config.rate != config->sample_rate ||
+ audio_channel_count_from_out_mask(config->channel_mask) != CHANNEL_STEREO ||
+ out->config.format != pcm_format_from_audio_format(config->format) ) {
+ config->sample_rate = out->config.rate;
+ config->format = audio_format_from_pcm_format(out->config.format);
+ config->channel_mask = audio_channel_out_mask_from_count(CHANNEL_STEREO);
+ ret = -EINVAL;
+ }
+
+ ALOGI("adev_open_output_stream selects channels=%d rate=%d format=%d",
+ out->config.channels, out->config.rate, out->config.format);
+
+ out->dev = ladev;
+ out->standby = 1;
+ out->unavailable = false;
+
+ config->format = out_get_format(&out->stream.common);
+ config->channel_mask = out_get_channels(&out->stream.common);
+ config->sample_rate = out_get_sample_rate(&out->stream.common);
+
+ *stream_out = &out->stream;
+
+ /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
+ ret = 0;
+
+ return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out *stream)
+{
+ ALOGV("adev_close_output_stream...");
+ free(stream);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+ ALOGV("adev_set_parameters");
+ return -ENOSYS;
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ ALOGV("adev_get_parameters");
+ return strdup("");
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+ ALOGV("adev_init_check");
+ return 0;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+ ALOGV("adev_set_voice_volume: %f", volume);
+ return -ENOSYS;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+ ALOGV("adev_set_master_volume: %f", volume);
+ return -ENOSYS;
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float *volume)
+{
+ ALOGV("adev_get_master_volume: %f", *volume);
+ return -ENOSYS;
+}
+
+static int adev_set_master_mute(struct audio_hw_device *dev, bool muted)
+{
+ ALOGV("adev_set_master_mute: %d", muted);
+ return -ENOSYS;
+}
+
+static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted)
+{
+ ALOGV("adev_get_master_mute: %d", *muted);
+ return -ENOSYS;
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+ ALOGV("adev_set_mode: %d", mode);
+ return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+ ALOGV("adev_set_mic_mute: %d",state);
+ return -ENOSYS;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+ ALOGV("adev_get_mic_mute");
+ return -ENOSYS;
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
+{
+ ALOGV("adev_get_input_buffer_size: %d", 320);
+ return 320;
+}
+
+static int adev_open_input_stream(struct audio_hw_device __unused *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ struct audio_stream_in **stream_in,
+ audio_input_flags_t flags __unused,
+ const char *address __unused,
+ audio_source_t source __unused)
+{
+ struct stub_stream_in *in;
+
+ ALOGV("adev_open_input_stream...");
+
+ in = (struct stub_stream_in *)calloc(1, sizeof(struct stub_stream_in));
+ if (!in)
+ return -ENOMEM;
+
+ in->stream.common.get_sample_rate = in_get_sample_rate;
+ in->stream.common.set_sample_rate = in_set_sample_rate;
+ in->stream.common.get_buffer_size = in_get_buffer_size;
+ in->stream.common.get_channels = in_get_channels;
+ in->stream.common.get_format = in_get_format;
+ in->stream.common.set_format = in_set_format;
+ in->stream.common.standby = in_standby;
+ in->stream.common.dump = in_dump;
+ in->stream.common.set_parameters = in_set_parameters;
+ in->stream.common.get_parameters = in_get_parameters;
+ in->stream.common.add_audio_effect = in_add_audio_effect;
+ in->stream.common.remove_audio_effect = in_remove_audio_effect;
+ in->stream.set_gain = in_set_gain;
+ in->stream.read = in_read;
+ in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+ *stream_in = &in->stream;
+ return 0;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *in)
+{
+ ALOGV("adev_close_input_stream...");
+ return;
+}
+
+static int adev_dump(const audio_hw_device_t *device, int fd)
+{
+ ALOGV("adev_dump");
+ return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+ ALOGV("adev_close");
+ free(device);
+ return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct alsa_audio_device *adev;
+
+ ALOGV("adev_open: %s", name);
+
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+ return -EINVAL;
+
+ adev = calloc(1, sizeof(struct alsa_audio_device));
+ if (!adev)
+ return -ENOMEM;
+
+ adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
+ adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ adev->hw_device.common.module = (struct hw_module_t *) module;
+ adev->hw_device.common.close = adev_close;
+ adev->hw_device.init_check = adev_init_check;
+ adev->hw_device.set_voice_volume = adev_set_voice_volume;
+ adev->hw_device.set_master_volume = adev_set_master_volume;
+ adev->hw_device.get_master_volume = adev_get_master_volume;
+ adev->hw_device.set_master_mute = adev_set_master_mute;
+ adev->hw_device.get_master_mute = adev_get_master_mute;
+ adev->hw_device.set_mode = adev_set_mode;
+ adev->hw_device.set_mic_mute = adev_set_mic_mute;
+ adev->hw_device.get_mic_mute = adev_get_mic_mute;
+ adev->hw_device.set_parameters = adev_set_parameters;
+ adev->hw_device.get_parameters = adev_get_parameters;
+ adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
+ adev->hw_device.open_output_stream = adev_open_output_stream;
+ adev->hw_device.close_output_stream = adev_close_output_stream;
+ adev->hw_device.open_input_stream = adev_open_input_stream;
+ adev->hw_device.close_input_stream = adev_close_input_stream;
+ adev->hw_device.dump = adev_dump;
+
+ adev->devices = AUDIO_DEVICE_NONE;
+
+ *device = &adev->hw_device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+ .open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = AUDIO_HARDWARE_MODULE_ID,
+ .name = "Generic Audio HAL for dragonboards",
+ .author = "The Android Open Source Project",
+ .methods = &hal_module_methods,
+ },
+};