summaryrefslogtreecommitdiff
authorLawrence Mok <lawrence.mok@amlogic.com>2012-11-21 01:22:49 (GMT)
committer Lawrence Mok <lawrence.mok@amlogic.com>2012-11-21 01:23:47 (GMT)
commit8a65406a63f49823071fba9dc5e37240de6c2141 (patch)
treecdee7722ba6a7b43684128569412e9680b2b01b6
parent1f52dbf27b1273c8f22a298a6bb7b4eb371a94d4 (diff)
downloadaudio-8a65406a63f49823071fba9dc5e37240de6c2141.zip
audio-8a65406a63f49823071fba9dc5e37240de6c2141.tar.gz
audio-8a65406a63f49823071fba9dc5e37240de6c2141.tar.bz2
moved from device/amlogic/g24ref/audio and changed
makefile to use new BOARD_ALSA_AUDIO config
Diffstat
-rw-r--r--Android.mk56
-rw-r--r--audio_hw.c2442
-rw-r--r--audio_policy.c358
-rw-r--r--m3codec_mixer_ctl.h43
-rw-r--r--rt5631_mixer_ctrl.h203
5 files changed, 3102 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..50cd668
--- a/dev/null
+++ b/Android.mk
@@ -0,0 +1,56 @@
+# Copyright (C) 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.
+
+ifeq ($(strip $(BOARD_ALSA_AUDIO)),tiny)
+
+ 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_MODULE := audio.primary.amlogic
+ LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+ LOCAL_SRC_FILES := audio_hw.c
+ LOCAL_C_INCLUDES += \
+ external/tinyalsa/include \
+ system/media/audio_utils/include \
+ system/media/audio_effects/include
+ LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libdl
+ LOCAL_MODULE_TAGS := optional
+
+#CONFIG_AML_CODEC
+ ifeq ($(BOARD_AUDIO_CODEC),rt5631)
+ LOCAL_CFLAGS += -DAML_AUDIO_RT5631
+ endif
+
+ include $(BUILD_SHARED_LIBRARY)
+
+# The stub audio policy HAL module that can be used as a skeleton for
+# new implementations.
+#include $(CLEAR_VARS)
+
+#LOCAL_MODULE := audio_policy.amlogic
+#LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+#LOCAL_SRC_FILES := audio_policy.c
+#LOCAL_SHARED_LIBRARIES := liblog libcutils
+#LOCAL_MODULE_TAGS := optional
+
+#include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/audio_hw.c b/audio_hw.c
new file mode 100644
index 0000000..43a742a
--- a/dev/null
+++ b/audio_hw.c
@@ -0,0 +1,2442 @@
+/*
+ * Copyright (C) 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_TAG "audio_hw_primary"
+//#define LOG_NDEBUG 0
+//#define LOG_NDEBUG_FUNCTION
+#ifdef LOG_NDEBUG_FUNCTION
+#define LOGFUNC(...) ((void)0)
+#else
+#define LOGFUNC(...) (ALOGD(__VA_ARGS__))
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <tinyalsa/asoundlib.h>
+#include <audio_utils/resampler.h>
+#include <audio_utils/echo_reference.h>
+#include <hardware/audio_effect.h>
+#include <audio_effects/effect_aec.h>
+
+#if defined(AML_AUDIO_RT5631)
+#include "rt5631_mixer_ctrl.h"
+#elif defined(AML_AUDIO_M3CODEC)
+#inclued "m3codec_mixer_ctl.h"
+#else
+struct route_setting
+{
+ char *ctl_name;
+ int intval;
+ char *strval;
+};
+struct route_setting mic_input[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};
+struct route_setting line_input[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};
+static struct route_setting output_headphone[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};static struct route_setting output_speaker[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};
+#endif
+
+/* ALSA cards for AML */
+#define CARD_AMLOGIC_BOARD 0
+#define CARD_AMLOGIC_USB 1
+#define CARD_AMLOGIC_DEFAULT CARD_AMLOGIC_BOARD
+/* ALSA ports for AML */
+#define PORT_MM 0
+/* number of frames per period */
+#define PERIOD_SIZE 1024
+/* number of periods for low power playback */
+#define PLAYBACK_PERIOD_COUNT 4
+/* number of periods for capture */
+#define CAPTURE_PERIOD_COUNT 4
+
+/* minimum sleep time in out_write() when write threshold is not reached */
+#define MIN_WRITE_SLEEP_US 5000
+
+#define RESAMPLER_BUFFER_FRAMES (PERIOD_SIZE * 6)
+#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
+
+#define DEFAULT_OUT_SAMPLING_RATE 48000
+
+/* sampling rate when using MM low power port */
+#define MM_LOW_POWER_SAMPLING_RATE 44100
+/* sampling rate when using MM full power port */
+#define MM_FULL_POWER_SAMPLING_RATE 48000
+/* sampling rate when using VX port for narrow band */
+#define VX_NB_SAMPLING_RATE 8000
+
+struct pcm_config pcm_config_out = {
+ .channels = 2,
+ .rate = MM_FULL_POWER_SAMPLING_RATE,
+ .period_size = PERIOD_SIZE,
+ .period_count = PLAYBACK_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+};
+
+struct pcm_config pcm_config_in = {
+ .channels = 2,
+ .rate = MM_FULL_POWER_SAMPLING_RATE,
+ .period_size = PERIOD_SIZE,
+ .period_count = PLAYBACK_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+};
+struct mixer_ctls{
+ struct mixer_ctl *master_playback_volume;
+ struct mixer_ctl *capture_volume;
+};
+
+struct aml_audio_device {
+ struct audio_hw_device hw_device;
+
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ struct mixer *mixer;
+ struct mixer_ctls mixer_ctls;
+ int mode;
+ int devices;
+ int in_call;
+ int cur_devices;
+ struct pcm *pcm_modem_dl;
+ struct pcm *pcm_modem_ul;
+ struct aml_stream_in *active_input;
+ struct aml_stream_out *active_output;
+
+ bool mic_mute;
+ struct echo_reference_itfe *echo_reference;
+ bool bluetooth_nrec;
+ bool low_power;
+
+ /* RIL */
+ //struct ril_handle ril;
+};
+
+struct aml_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;
+ struct resampler_itfe *resampler;
+ char *buffer;
+ int standby;
+ struct echo_reference_itfe *echo_reference;
+ struct aml_audio_device *dev;
+ int write_threshold;
+ bool low_power;
+};
+
+#define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */
+struct aml_stream_in {
+ struct audio_stream_in stream;
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ struct pcm_config config;
+ struct pcm *pcm;
+ int device;
+ struct resampler_itfe *resampler;
+ struct resampler_itfe *up_resampler;//shuai
+ struct resampler_buffer_provider buf_provider;
+ char *up_resampler_buffer;
+ struct resampler_buffer_provider up_buf_provider;
+ int16_t *buffer;
+ size_t frames_in;
+ unsigned int requested_rate;
+ int standby;
+ int source;
+ struct echo_reference_itfe *echo_reference;
+ bool need_echo_reference;
+ effect_handle_t preprocessors[MAX_PREPROCESSORS];
+ int num_preprocessors;
+ int16_t *proc_buf;
+ size_t proc_buf_size;
+ size_t proc_frames_in;
+ int16_t *ref_buf;
+ size_t ref_buf_size;
+ size_t ref_frames_in;
+ int read_status;
+ int voip_mode;
+
+ struct aml_audio_device *dev;
+};
+
+static char cache_buffer_bytes[64];
+static uint cached_len=0;
+static void select_output_device(struct aml_audio_device *adev);
+static void select_input_device(struct aml_audio_device *adev);
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume);
+static int do_input_standby(struct aml_stream_in *in);
+static int do_output_standby(struct aml_stream_out *out);
+
+/* The enable flag when 0 makes the assumption that enums are disabled by
+ * "Off" and integers/booleans by 0 */
+static int set_route_by_array(struct mixer *mixer, struct route_setting *route,
+ int enable)
+{
+ struct mixer_ctl *ctl;
+ unsigned int i, j;
+
+ /* Go through the route array and set each value */
+ i = 0;
+ while (route[i].ctl_name) {
+ ctl = mixer_get_ctl_by_name(mixer, route[i].ctl_name);
+ if (!ctl)
+ return -EINVAL;
+
+ //LOGFUNC("set_route_by_array().... index[%d] enable[%d] : ctl_name=%s, strval=%s, intval=%d",
+ // i, enable, route[i].ctl_name, route[i].strval,route[i].intval);
+ if (route[i].strval) {
+ if (enable)
+ mixer_ctl_set_enum_by_string(ctl, route[i].strval);
+ else
+ mixer_ctl_set_enum_by_string(ctl, "Off");
+ } else {
+ /* This ensures multiple (i.e. stereo) values are set jointly */
+ for (j = 0; j < mixer_ctl_get_num_values(ctl); j++) {
+ if (enable)
+ mixer_ctl_set_value(ctl, j, route[i].intval);
+ else
+ mixer_ctl_set_value(ctl, j, 0);
+ }
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+static void select_output_device(struct aml_audio_device *adev)
+{
+ LOGFUNC("%s(mode=%d, devices=%#x)", __FUNCTION__, adev->mode, adev->devices);
+ int headset_on;
+ int headphone_on;
+ int speaker_on;
+ adev->cur_devices = adev->devices;
+
+ headset_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ headphone_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ speaker_on = adev->devices & AUDIO_DEVICE_OUT_SPEAKER;
+ LOGFUNC("~~~~ %s : hs=%d , hp=%d, sp=%d", __func__, headset_on, headphone_on, speaker_on);
+ set_route_by_array(adev->mixer, output_headphone, headset_on | headphone_on);
+ set_route_by_array(adev->mixer, output_speaker, speaker_on);
+}
+
+static void select_input_device(struct aml_audio_device *adev)
+{
+ int mic_in = adev->devices & AUDIO_DEVICE_IN_BUILTIN_MIC;
+
+ LOGFUNC("~~~~ %s : devices(%#x), mic_in(%#x)", __func__, adev->devices, mic_in);
+
+ if (mic_in)
+ {
+ set_route_by_array(adev->mixer, mic_input, 1);
+ }
+ else
+ {
+ set_route_by_array(adev->mixer, line_input, 1);
+ }
+
+ return;
+}
+
+static void force_all_standby(struct aml_audio_device *adev)
+{
+ struct aml_stream_in *in;
+ struct aml_stream_out *out;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, adev);
+
+ if (adev->active_output) {
+ out = adev->active_output;
+ pthread_mutex_lock(&out->lock);
+ do_output_standby(out);
+ pthread_mutex_unlock(&out->lock);
+ }
+
+ if (adev->active_input) {
+ in = adev->active_input;
+ pthread_mutex_lock(&in->lock);
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ }
+}
+static void select_mode(struct aml_audio_device *adev)
+{
+ LOGFUNC("%s(devices=%#x)", __FUNCTION__, adev->devices);
+ return;
+ force_all_standby(adev);
+ /* force earpiece route for in call state if speaker is the
+ only currently selected route. This prevents having to tear
+ down the modem PCMs to change route from speaker to earpiece
+ after the ringtone is played, but doesn't cause a route
+ change if a headset or bt device is already connected. If
+ speaker is not the only thing active, just remove it from
+ the route. We'll assume it'll never be used initally during
+ a call. This works because we're sure that the audio policy
+ manager will update the output device after the audio mode
+ change, even if the device selection did not change. */
+ if ((adev->devices & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER)
+ adev->devices = AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_IN_BUILTIN_MIC;
+ else
+ adev->devices &= ~AUDIO_DEVICE_OUT_SPEAKER;
+
+ select_output_device(adev);
+ select_input_device(adev);
+ return;
+}
+
+/*
+ type : 0 -> playback, 1 -> capture
+*/
+#define MAX_CARD_NUM 2
+int get_external_card(int type)
+{
+ int card_num = 1; // start num, 0 is defualt sound card.
+
+ struct stat card_stat;
+ char fpath[256];
+ int ret;
+
+
+ while(card_num <= MAX_CARD_NUM)
+ {
+ snprintf(fpath, sizeof(fpath), "/proc/asound/card%d", card_num);
+
+ ret = stat(fpath, &card_stat);
+ //ALOGV("stat : %s : %d\n", fpath, ret);
+
+ if(ret < 0)
+ {
+ ret = -1;
+ }
+ else
+ {
+ snprintf(fpath, sizeof(fpath), "/dev/snd/pcmC%uD0%c", card_num,
+ type ? 'c' : 'p');
+
+ ret = stat(fpath, &card_stat);
+ //ALOGV("stat : %s : %d\n", fpath, ret);
+
+ if(ret == 0)
+ {
+ return card_num;
+ }
+
+ }
+
+ card_num++;
+ }
+
+ return ret;
+}
+
+static int check_output_stream(struct aml_stream_out *out)
+{
+ int ret = 0;
+ unsigned int card = CARD_AMLOGIC_DEFAULT;
+ unsigned int port = PORT_MM;
+ int ext_card;
+ LOGFUNC("*******%s*********", __FUNCTION__);
+
+ ext_card = get_external_card(0);
+ if(ext_card < 0)
+ {
+ card = CARD_AMLOGIC_DEFAULT;
+ }
+ else
+ {
+ card = ext_card;
+ }
+
+ out->config.start_threshold = PERIOD_SIZE * 2;
+ out->config.avail_min = 0;//SHORT_PERIOD_SIZE;
+ LOGFUNC("%s(out->config.rate=%d)", __FUNCTION__,out->config.rate);
+
+ /* this assumes routing is done previously */
+ out->pcm = pcm_open(card, port, PCM_OUT /*| PCM_MMAP | PCM_NOIRQ*/, &out->config);
+ if (!pcm_is_ready(out->pcm)) {
+ ALOGE("check_out_stream:cannot open pcm_out driver: %s", pcm_get_error(out->pcm));
+ pcm_close(out->pcm);
+ return -ENOMEM;
+ }
+
+ pcm_close(out->pcm);
+
+ return 0;
+}
+
+
+/* must be called with hw device and output stream mutexes locked */
+static int start_output_stream(struct aml_stream_out *out)
+{
+ struct aml_audio_device *adev = out->dev;
+ unsigned int card = CARD_AMLOGIC_DEFAULT;
+ unsigned int port = PORT_MM;
+ int ret;
+
+ adev->active_output = out;
+
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ /* FIXME: only works if only one output can be active at a time */
+ select_output_device(adev);
+ }
+ LOGFUNC("%s(adev->devices=%#x, adev->mode=%d)", __FUNCTION__, adev->devices, adev->mode);
+
+ card = CARD_AMLOGIC_BOARD;
+ port = PORT_MM;
+ LOGFUNC("------------open on board audio-------");
+ out->config.rate = MM_FULL_POWER_SAMPLING_RATE;
+ /* 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 = PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
+ out->config.avail_min = 0;//SHORT_PERIOD_SIZE;
+
+
+ if(out->config.rate!=DEFAULT_OUT_SAMPLING_RATE){
+
+ ret = create_resampler(DEFAULT_OUT_SAMPLING_RATE,
+ out->config.rate,
+ 2,
+ RESAMPLER_QUALITY_DEFAULT,
+ NULL,
+ &out->resampler);
+ if (ret != 0)
+ {
+ ALOGE("cannot create resampler for output");
+ return ENOMEM;
+ }
+ out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
+ if (out->buffer == NULL)
+ return ENOMEM;
+ }
+
+ ALOGV("channels=%d---format=%d---period_count%d---period_size%d---rate=%d---",
+ out->config.channels, out->config.format, out->config.period_count,
+ out->config.period_size, out->config.rate);
+ out->pcm = pcm_open(card, port, PCM_OUT /*| PCM_MMAP | PCM_NOIRQ*/, &(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;
+ return -ENOMEM;
+ }
+ if (adev->echo_reference != NULL)
+ out->echo_reference = adev->echo_reference;
+ if (out->resampler){
+ out->resampler->reset(out->resampler);
+ }
+
+ return 0;
+}
+
+static int check_input_parameters(uint32_t sample_rate, int format, int channel_count)
+{
+ LOGFUNC("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__, sample_rate, format, channel_count);
+
+ if (format != AUDIO_FORMAT_PCM_16_BIT)
+ return -EINVAL;
+
+ if ((channel_count < 1) || (channel_count > 2))
+ return -EINVAL;
+
+ switch(sample_rate) {
+ case 8000:
+ case 11025:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static size_t get_input_buffer_size(uint32_t sample_rate, int format, int channel_count)
+{
+ size_t size;
+ size_t device_rate;
+
+ LOGFUNC("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__, sample_rate, format, channel_count);
+
+ if (check_input_parameters(sample_rate, format, channel_count) != 0)
+ return 0;
+
+ /* take resampling into account and return the closest majoring
+ multiple of 16 frames, as audioflinger expects audio buffers to
+ be a multiple of 16 frames */
+ size = (pcm_config_in.period_size * sample_rate) / pcm_config_in.rate;
+ size = ((size + 15) / 16) * 16;
+
+ return size * channel_count * sizeof(short);
+}
+
+static void add_echo_reference(struct aml_stream_out *out,
+ struct echo_reference_itfe *reference)
+{
+ pthread_mutex_lock(&out->lock);
+ out->echo_reference = reference;
+ pthread_mutex_unlock(&out->lock);
+}
+
+static void remove_echo_reference(struct aml_stream_out *out,
+ struct echo_reference_itfe *reference)
+{
+ pthread_mutex_lock(&out->lock);
+ if (out->echo_reference == reference) {
+ /* stop writing to echo reference */
+ reference->write(reference, NULL);
+ out->echo_reference = NULL;
+ }
+ pthread_mutex_unlock(&out->lock);
+}
+
+static void put_echo_reference(struct aml_audio_device *adev,
+ struct echo_reference_itfe *reference)
+{
+ if (adev->echo_reference != NULL &&
+ reference == adev->echo_reference) {
+ if (adev->active_output != NULL)
+ remove_echo_reference(adev->active_output, reference);
+ release_echo_reference(reference);
+ adev->echo_reference = NULL;
+ }
+}
+
+static struct echo_reference_itfe *get_echo_reference(struct aml_audio_device *adev,
+ audio_format_t format,
+ uint32_t channel_count,
+ uint32_t sampling_rate)
+{
+ put_echo_reference(adev, adev->echo_reference);
+ if (adev->active_output != NULL) {
+ struct audio_stream *stream = &adev->active_output->stream.common;
+ uint32_t wr_channel_count = popcount(stream->get_channels(stream));
+ uint32_t wr_sampling_rate = stream->get_sample_rate(stream);
+
+ int status = create_echo_reference(AUDIO_FORMAT_PCM_16_BIT,
+ channel_count,
+ sampling_rate,
+ AUDIO_FORMAT_PCM_16_BIT,
+ wr_channel_count,
+ wr_sampling_rate,
+ &adev->echo_reference);
+ if (status == 0)
+ add_echo_reference(adev->active_output, adev->echo_reference);
+ }
+ return adev->echo_reference;
+}
+
+static int get_playback_delay(struct aml_stream_out *out,
+ size_t frames,
+ struct echo_reference_buffer *buffer)
+{
+
+ size_t kernel_frames;
+ int status;
+ status = pcm_get_htimestamp(out->pcm, &kernel_frames, &buffer->time_stamp);
+ if (status < 0) {
+ buffer->time_stamp.tv_sec = 0;
+ buffer->time_stamp.tv_nsec = 0;
+ buffer->delay_ns = 0;
+ ALOGV("get_playback_delay(): pcm_get_htimestamp error,"
+ "setting playbackTimestamp to 0");
+ return status;
+ }
+ kernel_frames = pcm_get_buffer_size(out->pcm) - kernel_frames;
+ ALOGV("~~pcm_get_buffer_size(out->pcm)=%d",pcm_get_buffer_size(out->pcm));
+ /* adjust render time stamp with delay added by current driver buffer.
+ * Add the duration of current frame as we want the render time of the last
+ * sample being written. */
+ buffer->delay_ns = (long)(((int64_t)(kernel_frames + frames)* 1000000000)/
+ DEFAULT_OUT_SAMPLING_RATE);
+
+ ALOGV("get_playback_delay time_stamp = [%ld].[%ld], delay_ns: [%d],"
+ "kernel_frames:[%d]",
+ buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns,
+ kernel_frames);
+ return 0;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ //struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ //return out->config.rate;
+ return DEFAULT_OUT_SAMPLING_RATE;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, rate);
+
+ return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+
+ LOGFUNC("%s(out->config.rate=%d)", __FUNCTION__, out->config.rate);
+
+ /* take resampling into account and 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 * DEFAULT_OUT_SAMPLING_RATE) / out->config.rate;
+ //size_t size = (PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * DEFAULT_OUT_SAMPLING_RATE) / out->config.rate;
+ size = ((size + 15) / 16) * 16;
+ return size * audio_stream_frame_size((struct audio_stream *)stream);
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+ //LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+
+ if (out->config.channels == 1) {
+ return AUDIO_CHANNEL_OUT_MONO;
+ } else {
+ return AUDIO_CHANNEL_OUT_STEREO;
+ }
+
+ // return AUDIO_CHANNEL_OUT_STEREO;
+ //return AUDIO_CHANNEL_OUT_STEREO;
+}
+/*
+static uint32_t out_get_channels(const struct audio_stream *stream)
+{
+ //LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+
+ if (out->config.channels == 1) {
+ return AUDIO_CHANNEL_OUT_MONO;
+ } else {
+ return AUDIO_CHANNEL_OUT_STEREO;
+ }
+
+ return AUDIO_CHANNEL_OUT_STEREO;
+}
+*/
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ // LOGFUNC("%s(%p)", __FUNCTION__, stream);
+
+ return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int out_set_format(struct audio_stream *stream, int format)
+{
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+
+ return 0;
+}
+
+/* must be called with hw device and output stream mutexes locked */
+static int do_output_standby(struct aml_stream_out *out)
+{
+ struct aml_audio_device *adev = out->dev;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, out);
+
+ if (!out->standby) {
+ ALOGV("~~~~ do_output_standby().... call pcm_close()");
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+
+ adev->active_output = 0;
+
+ /* if in call, don't turn off the output stage. This will
+ be done when the call is ended */
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ /* FIXME: only works if only one output can be active at a time */
+ set_route_by_array(adev->mixer, output_headphone, 0);
+ set_route_by_array(adev->mixer, output_speaker, 0);
+ }
+
+ /* stop writing to echo reference */
+ if (out->echo_reference != NULL) {
+ out->echo_reference->write(out->echo_reference, NULL);
+ out->echo_reference = NULL;
+ }
+
+ out->standby = 1;
+ }
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ int status;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+
+ 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)
+{
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, fd);
+ return 0;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ struct aml_audio_device *adev = out->dev;
+ struct aml_stream_in *in;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int ret, val = 0;
+ bool force_input_standby = false;
+
+ LOGFUNC("%s(kvpairs(%s), devices=%#x)", __FUNCTION__, kvpairs, adev->devices);
+ 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)) {
+ if (out == adev->active_output) {
+ do_output_standby(out);
+ /* a change in output device may change the microphone selection */
+ if (adev->active_input &&
+ adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ force_input_standby = true;
+ }
+ /* force standby if moving to/from HDMI */
+ if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
+ (adev->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
+ ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
+ (adev->devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)))
+ do_output_standby(out);
+ }
+ adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
+ adev->devices |= val;
+ select_output_device(adev);
+ }
+ pthread_mutex_unlock(&out->lock);
+ if (force_input_standby) {
+ in = adev->active_input;
+ pthread_mutex_lock(&in->lock);
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->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)
+{
+ //LOGFUNC("%s(%p, %s)", __FUNCTION__, stream, keys);
+ return strdup("");
+}
+
+#if 1
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ //LOGFUNC("%s(out->pcm=%p)", __FUNCTION__, out->pcm);
+ return (PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * 1000) / out->config.rate;
+}
+#else
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ LOGFUNC("%s(out->pcm=%p)", __FUNCTION__, out->pcm);
+
+ if(out->pcm){
+ size_t kernel_frames;
+ int status;
+ struct timespec tstamp;
+ LOGFUNC("%s(tstamp=%p)", __FUNCTION__, tstamp);
+
+ status = pcm_get_htimestamp(out->pcm, &kernel_frames, &tstamp);
+ if (status < 0) {
+ tstamp.tv_sec = 0;
+ tstamp.tv_nsec = 0;
+
+ ALOGE(...)("out_get_latency(): pcm_get_htimestamp error,");
+ //return status;
+ }
+ kernel_frames = pcm_get_buffer_size(out->pcm) - kernel_frames;
+ LOGFUNC("%s(latency=%d)", __FUNCTION__, kernel_frames);
+ return (kernel_frames * 1000) / out->config.rate;
+ }
+ return (PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * 1000) / out->config.rate;
+}
+#endif
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ return -ENOSYS;
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+ size_t bytes)
+{
+
+ int ret;
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ struct aml_audio_device *adev = out->dev;
+ size_t frame_size = audio_stream_frame_size(&out->stream.common);
+ size_t in_frames = bytes / frame_size;
+ size_t out_frames = RESAMPLER_BUFFER_SIZE / frame_size;
+ bool force_input_standby = false;
+ struct aml_stream_in *in;
+ bool low_power;
+ int kernel_frames;
+ void *buf;
+ char output_buffer_bytes[RESAMPLER_BUFFER_SIZE+128];
+ uint ouput_len;
+ char *data, *data_dst;
+ volatile char *data_src;
+ short *dataprint;
+ uint i, total_len;
+ //LOGFUNC("entring:%s(out->echo_reference=%p, in_frames=%d)", __FUNCTION__, out->echo_reference, in_frames);
+
+ /* 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;
+ /* a change in output device may change the microphone selection */
+ if (adev->active_input &&
+ adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
+ force_input_standby = true;
+ }
+ pthread_mutex_unlock(&adev->lock);
+#if 0
+FILE * fp=fopen("/data/audio_in","a+");
+ if(fp){
+ int flen=fwrite((char *)buffer,1,bytes,fp);
+ LOGFUNC("flen = %d---audio_in=%d ", flen, bytes);
+ fclose(fp);
+ }else{
+ LOGFUNC("could not open file: audio_in");
+}
+#endif
+ /* only use resampler if required */
+ if (out->config.rate != DEFAULT_OUT_SAMPLING_RATE) {
+ if (!out->resampler) {
+
+ ret = create_resampler(DEFAULT_OUT_SAMPLING_RATE,
+ out->config.rate,
+ 2,
+ RESAMPLER_QUALITY_DEFAULT,
+ NULL,
+ &out->resampler);
+ if (ret != 0)
+ goto exit;
+ out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
+ if (!out->buffer) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ }
+ out->resampler->resample_from_input(out->resampler,
+ (int16_t *)buffer,
+ &in_frames,
+ (int16_t *)out->buffer,
+ &out_frames);
+ buf = out->buffer;
+ } else {
+ out_frames = in_frames;
+ buf = (void *)buffer;
+ }
+ if (out->echo_reference != NULL) {
+ struct echo_reference_buffer b;
+ b.raw = (void *)buffer;
+ b.frame_count = in_frames;
+ get_playback_delay(out, out_frames, &b);
+ out->echo_reference->write(out->echo_reference, &b);
+ }
+
+#if 0
+ /* do not allow more than out->write_threshold frames in kernel pcm driver buffer */
+ do {
+ struct timespec time_stamp;
+ if (pcm_get_htimestamp(out->pcm, (unsigned int *)&kernel_frames, &time_stamp) < 0)
+ break;
+ kernel_frames = pcm_get_buffer_size(out->pcm) - kernel_frames;
+
+ if (kernel_frames > out->write_threshold) {
+ unsigned long time = (unsigned long)
+ (((int64_t)(kernel_frames - out->write_threshold) * 1000000) /
+ MM_FULL_POWER_SAMPLING_RATE);
+ //VX_NB_SAMPLING_RATE);
+ if (time < MIN_WRITE_SLEEP_US)
+ time = MIN_WRITE_SLEEP_US;
+ usleep(time);
+ }
+ } while (kernel_frames > out->write_threshold);
+#endif
+#if 0
+ FILE *fp1=fopen("/data/audio_out","a+");
+ if(fp){
+ int flen=fwrite((char *)buf,1,out_frames * frame_size,fp1);
+ LOGFUNC("flen = %d---outlen=%d ", flen, out_frames * frame_size);
+ fclose(fp);
+ }else{
+ LOGFUNC("could not open file:audio_out");
+ }
+#endif
+
+#if 1
+
+ if(out->config.rate != DEFAULT_OUT_SAMPLING_RATE) {
+ total_len = out_frames*frame_size + cached_len;
+
+
+ LOGFUNC("total_len(%d) = resampler_out_len(%d) + cached_len111(%d)", total_len, out_frames*frame_size, cached_len);
+
+ data_src = (char *)cache_buffer_bytes;
+ data_dst = (char *)output_buffer_bytes;
+
+
+
+ /*write_back data from cached_buffer*/
+ if(cached_len){
+ memcpy((void *)data_dst, (void *)data_src, cached_len);
+ data_dst += cached_len;
+ }
+
+ ouput_len = total_len &(~0x3f);
+ data = (char*)buf;
+
+ memcpy((void *)data_dst, (void *)data, ouput_len-cached_len);
+ data += (ouput_len-cached_len);
+ cached_len = total_len & 0x3f;
+ data_src = (char *)cache_buffer_bytes;
+
+ /*save data to cached_buffer*/
+ if(cached_len){
+ memcpy((void *)data_src, (void *)data, cached_len);
+ }
+
+ ret = pcm_write(out->pcm, (void *)output_buffer_bytes, ouput_len);
+
+ }else{
+ ret = pcm_write(out->pcm, (void *)buf, out_frames * frame_size);
+ //ret = pcm_mmap_write(out->pcm, (void *)buf, out_frames * frame_size);
+ }
+#endif
+
+ exit:
+ pthread_mutex_unlock(&out->lock);
+
+ if (ret != 0) {
+ usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
+ out_get_sample_rate(&stream->common));
+ }
+
+ if (force_input_standby) {
+ pthread_mutex_lock(&adev->lock);
+ if (adev->active_input) {
+ in = adev->active_input;
+ pthread_mutex_lock(&in->lock);
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ }
+ pthread_mutex_unlock(&adev->lock);
+ }
+ return bytes;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, stream, dsp_frames);
+ return -EINVAL;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, stream, effect);
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp)
+{
+ return -EINVAL;
+}
+
+/*
+static int out_set_voip_mode(struct audio_stream *stream, int mode)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+ ALOGE("call out_set_voip_mode old:%d, new:%d", out->voip_mode, mode);
+
+ if(out->voip_mode == mode)
+ return 0;
+ else if(mode == 0)
+ {
+ out->voip_mode = mode;
+ }
+ else
+ {
+ out->voip_mode = mode;
+
+ out_standby(stream);
+ }
+
+ return 0;
+}
+*/
+static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer* buffer);
+static void release_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer* buffer);
+
+
+/** audio_stream_in implementation **/
+
+/* must be called with hw device and input stream mutexes locked */
+static int start_input_stream(struct aml_stream_in *in)
+{
+ int ret = 0;
+ unsigned int card = CARD_AMLOGIC_DEFAULT;
+ unsigned int port = PORT_MM;
+
+ struct aml_audio_device *adev = in->dev;
+ LOGFUNC("%s(need_echo_reference=%d, channels=%d, rate=%d, requested_rate=%d, mode= %d)",
+ __FUNCTION__, in->need_echo_reference, in->config.channels, in->config.rate, in->requested_rate, adev->mode);
+ adev->active_input = in;
+
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ adev->devices &= ~AUDIO_DEVICE_IN_ALL;
+ adev->devices |= in->device;
+ select_input_device(adev);
+ }
+
+ ALOGV("%s(in->requested_rate=%d, in->config.rate=%d)",
+ __FUNCTION__, in->requested_rate, in->config.rate);
+
+ if (in->need_echo_reference && in->echo_reference == NULL) {
+ in->echo_reference = get_echo_reference(adev,
+ AUDIO_FORMAT_PCM_16_BIT,
+ in->config.channels,
+ VX_NB_SAMPLING_RATE);
+ //in->requested_rate);
+ LOGFUNC("%s(after get_echo_ref.... now in->echo_reference = %p)", __FUNCTION__, in->echo_reference);
+#if 1
+ if (in->echo_reference != NULL){
+ in->buf_provider.get_next_buffer = get_next_buffer;
+ in->buf_provider.release_buffer = release_buffer;
+ ret = create_resampler(in->config.rate,
+ VX_NB_SAMPLING_RATE,
+ in->config.channels,
+ RESAMPLER_QUALITY_DEFAULT,
+ &in->buf_provider,
+ &in->resampler);
+
+ if (ret != 0) {
+ ret = -EINVAL;
+ return ret;
+ }
+ ret = create_resampler(VX_NB_SAMPLING_RATE,
+ in->config.rate,
+ in->config.channels,
+ RESAMPLER_QUALITY_DEFAULT,
+ NULL,//&in->up_buf_provider,
+ &in->up_resampler);
+
+ if (ret != 0) {
+ ret = -EINVAL;
+ return ret;
+ }
+ in->up_resampler_buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
+ if (in->up_resampler_buffer == NULL)
+ return ENOMEM;
+ }
+#endif
+ }
+ /* this assumes routing is done previously */
+ in->pcm = pcm_open(card, port, PCM_IN, &in->config);
+ if (!pcm_is_ready(in->pcm)) {
+ ALOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ adev->active_input = NULL;
+ return -ENOMEM;
+ }
+ ALOGD("pcm_open in: card(%d), port(%d)", card, port);
+
+ /* if no supported sample rate is available, use the resampler */
+ if (in->resampler) {
+ in->resampler->reset(in->resampler);
+ in->frames_in = 0;
+ }
+ return 0;
+}
+
+static int check_input_stream(struct aml_stream_in *in)
+{
+ int ret = 0;
+ unsigned int card = CARD_AMLOGIC_BOARD;
+ unsigned int port = 0;
+ int ext_card;
+
+ ext_card = get_external_card(1);
+ if(ext_card < 0)
+ {
+ card = CARD_AMLOGIC_BOARD;
+ }
+ else
+ {
+ card = ext_card;
+ }
+
+ /* this assumes routing is done previously */
+ in->pcm = pcm_open(card, port, PCM_IN, &in->config);
+ if (!pcm_is_ready(in->pcm)) {
+ ALOGE("check_input_stream:cannot open pcm_in driver: %s", pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ return -ENOMEM;
+ }
+
+ pcm_close(in->pcm);
+
+ return 0;
+}
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ return in->requested_rate;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, rate);
+ return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ return get_input_buffer_size(in->config.rate,
+ AUDIO_FORMAT_PCM_16_BIT,
+ in->config.channels);
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ //LOGFUNC("%s(%p)", __FUNCTION__, stream);
+
+ if (in->config.channels == 1) {
+ return AUDIO_CHANNEL_IN_MONO;
+ } else {
+ return AUDIO_CHANNEL_IN_STEREO;
+ }
+ //return AUDIO_CHANNEL_IN_MONO;
+}
+/*
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ //LOGFUNC("%s(%p)", __FUNCTION__, stream);
+
+ if (in->config.channels == 1) {
+ return AUDIO_CHANNEL_IN_MONO;
+ } else {
+ return AUDIO_CHANNEL_IN_STEREO;
+ }
+}
+*/
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ //LOGFUNC("%s(%p)", __FUNCTION__, stream);
+ return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, format);
+ return 0;
+}
+
+/* must be called with hw device and input stream mutexes locked */
+static int do_input_standby(struct aml_stream_in *in)
+{
+ struct aml_audio_device *adev = in->dev;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, in);
+ if (!in->standby) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+
+ adev->active_input = 0;
+ if (adev->mode != AUDIO_MODE_IN_CALL) {
+ adev->devices &= ~AUDIO_DEVICE_IN_ALL;
+ select_input_device(adev);
+ }
+
+ if (in->echo_reference != NULL) {
+ /* stop reading from echo reference */
+ in->echo_reference->read(in->echo_reference, NULL);
+ put_echo_reference(adev, in->echo_reference);
+ in->echo_reference = NULL;
+ }
+
+ in->standby = 1;
+ }
+ return 0;
+}
+static int in_standby(struct audio_stream *stream)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ int status;
+ LOGFUNC("%s(%p)", __FUNCTION__, stream);
+
+ pthread_mutex_lock(&in->dev->lock);
+ pthread_mutex_lock(&in->lock);
+ status = do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ pthread_mutex_unlock(&in->dev->lock);
+ return status;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, stream, fd);
+ return 0;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ struct aml_audio_device *adev = in->dev;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int ret, val = 0;
+ bool do_standby = false;
+
+ LOGFUNC("%s(%p, %s)", __FUNCTION__, stream, kvpairs);
+ parms = str_parms_create_str(kvpairs);
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
+
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (ret >= 0) {
+ val = atoi(value);
+ /* no audio source uses val == 0 */
+ if ((in->source != val) && (val != 0)) {
+ in->source = val;
+ do_standby = true;
+ }
+ }
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ if ((in->device != val) && (val != 0)) {
+ in->device = val;
+ do_standby = true;
+ }
+ }
+
+ if (do_standby)
+ do_input_standby(in);
+ pthread_mutex_unlock(&in->lock);
+ pthread_mutex_unlock(&adev->lock);
+
+ str_parms_destroy(parms);
+ return ret;
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ //LOGFUNC("%s(%p, %s)", __FUNCTION__, stream, keys);
+ return strdup("");
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+ LOGFUNC("%s(%p, %f)", __FUNCTION__, stream, gain);
+ return 0;
+}
+
+static void get_capture_delay(struct aml_stream_in *in,
+ size_t frames,
+ struct echo_reference_buffer *buffer)
+{
+ /* read frames available in kernel driver buffer */
+ size_t kernel_frames;
+ struct timespec tstamp;
+ long buf_delay;
+ long rsmp_delay;
+ long kernel_delay;
+ long delay_ns;
+ int rsmp_mul = in->config.rate/VX_NB_SAMPLING_RATE;
+ if (pcm_get_htimestamp(in->pcm, &kernel_frames, &tstamp) < 0) {
+ buffer->time_stamp.tv_sec = 0;
+ buffer->time_stamp.tv_nsec = 0;
+ buffer->delay_ns = 0;
+ ALOGW("read get_capture_delay(): pcm_htimestamp error");
+ return;
+ }
+
+ /* read frames available in audio HAL input buffer
+ * add number of frames being read as we want the capture time of first sample
+ * in current buffer */
+ buf_delay = (long)(((int64_t)(in->frames_in + in->proc_frames_in * rsmp_mul) * 1000000000)
+ / in->config.rate);
+ /* add delay introduced by resampler */
+ rsmp_delay = 0;
+ if (in->resampler) {
+ rsmp_delay = in->resampler->delay_ns(in->resampler);
+ }
+
+ kernel_delay = (long)(((int64_t)kernel_frames * 1000000000) / in->config.rate);
+
+ delay_ns = kernel_delay + buf_delay + rsmp_delay;
+
+ buffer->time_stamp = tstamp;
+ buffer->delay_ns = delay_ns;
+ ALOGV("get_capture_delay time_stamp = [%ld].[%ld], delay_ns: [%d],"
+ " kernel_delay:[%ld], buf_delay:[%ld], rsmp_delay:[%ld], kernel_frames:[%d], "
+ "in->frames_in:[%d], in->proc_frames_in:[%d], frames:[%d]",
+ buffer->time_stamp.tv_sec , buffer->time_stamp.tv_nsec, buffer->delay_ns,
+ kernel_delay, buf_delay, rsmp_delay, kernel_frames,
+ in->frames_in, in->proc_frames_in, frames);
+
+}
+
+static int32_t update_echo_reference(struct aml_stream_in *in, size_t frames)
+{
+ struct echo_reference_buffer b;
+ b.delay_ns = 0;
+
+ ALOGV("update_echo_reference, frames = [%d], in->ref_frames_in = [%d], "
+ "b.frame_count = [%d]",
+ frames, in->ref_frames_in, frames - in->ref_frames_in);
+ if (in->ref_frames_in < frames) {
+ if (in->ref_buf_size < frames) {
+ in->ref_buf_size = frames;
+ in->ref_buf = (int16_t *)realloc(in->ref_buf,
+ in->ref_buf_size *
+ in->config.channels * sizeof(int16_t));
+ }
+
+ b.frame_count = frames - in->ref_frames_in;
+ b.raw = (void *)(in->ref_buf + in->ref_frames_in * in->config.channels);
+
+ get_capture_delay(in, frames, &b);
+ LOGFUNC("update_echo_reference return ::b.delay_ns=%d", b.delay_ns);
+
+ if (in->echo_reference->read(in->echo_reference, &b) == 0)
+ {
+ in->ref_frames_in += b.frame_count;
+ ALOGV("update_echo_reference: in->ref_frames_in:[%d], "
+ "in->ref_buf_size:[%d], frames:[%d], b.frame_count:[%d]",
+ in->ref_frames_in, in->ref_buf_size, frames, b.frame_count);
+ }
+ } else
+ ALOGW("update_echo_reference: NOT enough frames to read ref buffer");
+ return b.delay_ns;
+}
+
+static int set_preprocessor_param(effect_handle_t handle,
+ effect_param_t *param)
+{
+ uint32_t size = sizeof(int);
+ uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
+ param->vsize;
+
+ int status = (*handle)->command(handle,
+ EFFECT_CMD_SET_PARAM,
+ sizeof (effect_param_t) + psize,
+ param,
+ &size,
+ &param->status);
+ if (status == 0)
+ status = param->status;
+
+ return status;
+}
+
+static int set_preprocessor_echo_delay(effect_handle_t handle,
+ int32_t delay_us)
+{
+ uint32_t buf[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+ effect_param_t *param = (effect_param_t *)buf;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, handle, delay_us);
+
+ param->psize = sizeof(uint32_t);
+ param->vsize = sizeof(uint32_t);
+ *(uint32_t *)param->data = AEC_PARAM_ECHO_DELAY;
+ *((int32_t *)param->data + 1) = delay_us;
+
+ return set_preprocessor_param(handle, param);
+}
+
+static void push_echo_reference(struct aml_stream_in *in, size_t frames)
+{
+ /* read frames from echo reference buffer and update echo delay
+ * in->ref_frames_in is updated with frames available in in->ref_buf */
+ int32_t delay_us = update_echo_reference(in, frames)/1000;
+ int i;
+ audio_buffer_t buf;
+
+ if (in->ref_frames_in < frames)
+ frames = in->ref_frames_in;
+
+ buf.frameCount = frames;
+ buf.raw = in->ref_buf;
+
+ for (i = 0; i < in->num_preprocessors; i++) {
+ if ((*in->preprocessors[i])->process_reverse == NULL)
+ continue;
+
+ (*in->preprocessors[i])->process_reverse(in->preprocessors[i],
+ &buf,
+ NULL);
+ set_preprocessor_echo_delay(in->preprocessors[i], delay_us);
+ }
+
+ in->ref_frames_in -= buf.frameCount;
+ if (in->ref_frames_in) {
+ memcpy(in->ref_buf,
+ in->ref_buf + buf.frameCount * in->config.channels,
+ in->ref_frames_in * in->config.channels * sizeof(int16_t));
+ }
+}
+
+static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer* buffer)
+{
+ struct aml_stream_in *in;
+
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, buffer_provider, buffer);
+ if (buffer_provider == NULL || buffer == NULL)
+ return -EINVAL;
+
+ in = (struct aml_stream_in *)((char *)buffer_provider -
+ offsetof(struct aml_stream_in, buf_provider));
+
+ if (in->pcm == NULL) {
+ buffer->raw = NULL;
+ buffer->frame_count = 0;
+ in->read_status = -ENODEV;
+ return -ENODEV;
+ }
+
+ if (in->frames_in == 0) {
+ in->read_status = pcm_read(in->pcm,
+ (void*)in->buffer,
+ in->config.period_size *
+ audio_stream_frame_size(&in->stream.common));
+ if (in->read_status != 0) {
+ ALOGE("get_next_buffer() pcm_read error %d", in->read_status);
+ buffer->raw = NULL;
+ buffer->frame_count = 0;
+ return in->read_status;
+ }
+ in->frames_in = in->config.period_size;
+ }
+
+ buffer->frame_count = (buffer->frame_count > in->frames_in) ?
+ in->frames_in : buffer->frame_count;
+ buffer->i16 = in->buffer + (in->config.period_size - in->frames_in) *
+ in->config.channels;
+
+ return in->read_status;
+
+}
+
+static void release_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer* buffer)
+{
+ struct aml_stream_in *in;
+
+ //LOGFUNC("%s(%p, %p)", __FUNCTION__, buffer_provider, buffer);
+ if (buffer_provider == NULL || buffer == NULL)
+ return;
+
+ in = (struct aml_stream_in *)((char *)buffer_provider -
+ offsetof(struct aml_stream_in, buf_provider));
+
+ in->frames_in -= buffer->frame_count;
+}
+
+/* read_frames() reads frames from kernel driver, down samples to capture rate
+ * if necessary and output the number of frames requested to the buffer specified */
+static ssize_t read_frames(struct aml_stream_in *in, void *buffer, ssize_t frames)
+{
+ ssize_t frames_wr = 0;
+ //LOGFUNC("%s(in->resampler=%p, %ld)", __FUNCTION__, in->resampler, frames);
+ while (frames_wr < frames) {
+ size_t frames_rd = frames - frames_wr;
+ if (in->resampler != NULL) {
+ in->resampler->resample_from_provider(in->resampler,
+ (int16_t *)((char *)buffer +
+ frames_wr * audio_stream_frame_size(&in->stream.common)),
+ &frames_rd);
+ } else {
+ struct resampler_buffer buf = {
+ { raw : NULL, },
+ frame_count : frames_rd,
+ };
+ get_next_buffer(&in->buf_provider, &buf);
+ if (buf.raw != NULL) {
+ memcpy((char *)buffer +
+ frames_wr * audio_stream_frame_size(&in->stream.common),
+ buf.raw,
+ buf.frame_count * audio_stream_frame_size(&in->stream.common));
+ frames_rd = buf.frame_count;
+ }
+ release_buffer(&in->buf_provider, &buf);
+ }
+ /* in->read_status is updated by getNextBuffer() also called by
+ * in->resampler->resample_from_provider() */
+ if (in->read_status != 0)
+ return in->read_status;
+
+ frames_wr += frames_rd;
+ }
+ return frames_wr;
+}
+#if 0
+/* process_frames() reads frames from kernel driver (via read_frames()),
+ * calls the active audio pre processings and output the number of frames requested
+ * to the buffer specified */
+static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t frames)
+{
+ ssize_t frames_wr = 0;
+ audio_buffer_t in_buf;
+ audio_buffer_t out_buf;
+ int i;
+
+ //LOGFUNC("%s(%d, %p, %ld)", __FUNCTION__, in->num_preprocessors, buffer, frames);
+ while (frames_wr < frames) {
+ /* first reload enough frames at the end of process input buffer */
+ if (in->proc_frames_in < (size_t)frames) {
+ ssize_t frames_rd;
+
+ if (in->proc_buf_size < (size_t)frames) {
+ in->proc_buf_size = (size_t)frames;
+ in->proc_buf = (int16_t *)realloc(in->proc_buf,
+ in->proc_buf_size *
+ in->config.channels * sizeof(int16_t));
+ ALOGV("process_frames(): in->proc_buf %p size extended to %d frames",
+ in->proc_buf, in->proc_buf_size);
+ }
+ frames_rd = read_frames(in,
+ in->proc_buf +
+ in->proc_frames_in * in->config.channels,
+ frames - in->proc_frames_in);
+ if (frames_rd < 0) {
+ frames_wr = frames_rd;
+ break;
+ }
+ in->proc_frames_in += frames_rd;
+ }
+
+ if (in->echo_reference != NULL)
+ push_echo_reference(in, in->proc_frames_in);
+
+ /* in_buf.frameCount and out_buf.frameCount indicate respectively
+ * the maximum number of frames to be consumed and produced by process() */
+ in_buf.frameCount = in->proc_frames_in;
+ in_buf.s16 = in->proc_buf;
+ out_buf.frameCount = frames - frames_wr;
+ out_buf.s16 = (int16_t *)buffer + frames_wr * in->config.channels;
+
+ for (i = 0; i < in->num_preprocessors; i++)
+ (*in->preprocessors[i])->process(in->preprocessors[i],
+ &in_buf,
+ &out_buf);
+
+ /* process() has updated the number of frames consumed and produced in
+ * in_buf.frameCount and out_buf.frameCount respectively
+ * move remaining frames to the beginning of in->proc_buf */
+ in->proc_frames_in -= in_buf.frameCount;
+ if (in->proc_frames_in) {
+ memcpy(in->proc_buf,
+ in->proc_buf + in_buf.frameCount * in->config.channels,
+ in->proc_frames_in * in->config.channels * sizeof(int16_t));
+ }
+
+ /* if not enough frames were passed to process(), read more and retry. */
+ if (out_buf.frameCount == 0)
+ continue;
+
+ frames_wr += out_buf.frameCount;
+ }
+ return frames_wr;
+}
+#else
+/* process_frames() reads frames from kernel driver (via read_frames()),
+ * calls the active audio pre processings and output the number of frames requested
+ * to the buffer specified */
+static ssize_t process_frames(struct aml_stream_in *in, void* buffer, ssize_t frames)
+{
+ ssize_t frames_wr = 0;
+ ssize_t proc_frames;
+ audio_buffer_t in_buf;
+ audio_buffer_t proc_buf;
+ audio_buffer_t out_buf;
+ int i, resp_mul;
+ resp_mul = in->requested_rate/VX_NB_SAMPLING_RATE;
+
+ proc_frames = frames/resp_mul ;
+
+ //LOGFUNC("%s(%d, %ld, %ld)", __FUNCTION__, in->num_preprocessors, frames, proc_frames);
+ while (frames_wr < proc_frames) {
+ /* first reload enough frames at the end of process input buffer */
+ if (in->proc_frames_in < (size_t)proc_frames) {
+ ssize_t frames_rd;
+
+ if (in->proc_buf_size < (size_t)proc_frames) {
+ in->proc_buf_size = (size_t)proc_frames;
+ in->proc_buf = (int16_t *)realloc(in->proc_buf,
+ in->proc_buf_size *
+ in->config.channels * sizeof(int16_t));
+ ALOGV("process_frames(): in->proc_buf %p size extended to %d frames",
+ in->proc_buf, in->proc_buf_size);
+ }
+ frames_rd = read_frames(in,
+ in->proc_buf +
+ in->proc_frames_in * in->config.channels,
+ proc_frames - in->proc_frames_in);
+ if (frames_rd < 0) {
+ frames_wr = frames_rd;
+ break;
+ }
+ in->proc_frames_in += frames_rd;
+ }
+
+ if (in->echo_reference != NULL)
+ push_echo_reference(in, in->proc_frames_in);
+
+ /* in_buf.frameCount and out_buf.frameCount indicate respectively
+ * the maximum number of frames to be consumed and produced by process() */
+ in_buf.frameCount = in->proc_frames_in;
+ in_buf.s16 = in->proc_buf;
+ proc_buf.frameCount = proc_frames - frames_wr;
+ proc_buf.s16 = (int16_t *)in->up_resampler_buffer+ frames_wr * in->config.channels;
+ out_buf.frameCount = (proc_frames - frames_wr) * resp_mul;
+ out_buf.s16 = (int16_t *)buffer + resp_mul * frames_wr * in->config.channels;
+ ALOGV("first**in_buf.frameCount=%d***\n**proc_buf.frameCount=%d\n**out_buf.frameCount=%d***", in_buf.frameCount, proc_buf.frameCount, out_buf.frameCount);
+
+ for (i = 0; i < in->num_preprocessors; i++)
+ (*in->preprocessors[i])->process(in->preprocessors[i],
+ &in_buf,
+ &proc_buf);//&out_buf);
+ if (in->up_resampler != NULL) {
+ in->up_resampler->resample_from_input(in->up_resampler,
+ proc_buf.s16,
+ &(proc_buf.frameCount),
+ out_buf.s16,
+ &(out_buf.frameCount));
+ }
+ ALOGV("after**in_buf.frameCount=%d***\n**proc_buf.frameCount=%d\n**out_buf.frameCount=%d***", in_buf.frameCount, proc_buf.frameCount, out_buf.frameCount);
+
+ /* process() has updated the number of frames consumed and produced in
+ * in_buf.frameCount and out_buf.frameCount respectively
+ * move remaining frames to the beginning of in->proc_buf */
+ in->proc_frames_in -= in_buf.frameCount;
+ if (in->proc_frames_in) {
+ memcpy(in->proc_buf,
+ in->proc_buf + in_buf.frameCount * in->config.channels,
+ in->proc_frames_in * in->config.channels * sizeof(int16_t));
+ }
+
+ /* if not enough frames were passed to process(), read more and retry. */
+ if (out_buf.frameCount == 0)
+ continue;
+
+ frames_wr += out_buf.frameCount/resp_mul;//out_buf.frameCount * VX_NB_SAMPLING_RATE/in->requested_rate;
+ ALOGV("***last*****frames_wr=%ld***********", frames_wr);
+ }
+ return frames_wr;
+}
+#endif
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+ size_t bytes)
+{
+ int ret = 0;
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ struct aml_audio_device *adev = in->dev;
+ size_t frames_rq = bytes / audio_stream_frame_size(&stream->common);
+ //LOGFUNC("%s(in->num_preprocessors=%d, frames_rq=%d)", __FUNCTION__, in->num_preprocessors, frames_rq);
+ if(in->voip_mode)
+ {
+ int sleepTime;
+
+ sleepTime = 1000*bytes/(in->config.channels * in->config.rate*2);
+ usleep(sleepTime*1000);
+ return bytes;
+ }
+ /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
+ * on the input stream mutex - e.g. executing select_mode() while holding the hw device
+ * mutex
+ */
+ pthread_mutex_lock(&adev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (in->standby) {
+ ret = start_input_stream(in);
+ if (ret == 0)
+ in->standby = 0;
+ }
+ pthread_mutex_unlock(&adev->lock);
+
+ if (ret < 0)
+ goto exit;
+//////////////////////////////////////////////////////////////////
+ if (in->need_echo_reference && in->echo_reference == NULL) {
+ in->echo_reference = get_echo_reference(adev,
+ AUDIO_FORMAT_PCM_16_BIT,
+ in->config.channels,
+ VX_NB_SAMPLING_RATE);
+ //in->requested_rate);
+ LOGFUNC("%s(after get_echo_ref.... now in->echo_reference = %p)", __FUNCTION__, in->echo_reference);
+#if 1
+ if (in->echo_reference != NULL){
+ in->buf_provider.get_next_buffer = get_next_buffer;
+ in->buf_provider.release_buffer = release_buffer;
+ ret = create_resampler(in->config.rate,
+ VX_NB_SAMPLING_RATE,
+ in->config.channels,
+ RESAMPLER_QUALITY_DEFAULT,
+ &in->buf_provider,
+ &in->resampler);
+
+ if (ret != 0) {
+ ret = -EINVAL;
+ return ret;
+ }
+ ret = create_resampler(VX_NB_SAMPLING_RATE,
+ in->config.rate,
+ in->config.channels,
+ RESAMPLER_QUALITY_DEFAULT,
+ NULL,//&in->up_buf_provider,
+ &in->up_resampler);
+
+ if (ret != 0) {
+ ret = -EINVAL;
+ return ret;
+ }
+ in->up_resampler_buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */
+ if (in->up_resampler_buffer == NULL)
+ return ENOMEM;
+ }
+#endif
+ }
+
+/////////////////////////////////////////////////////////////////////
+ if (in->num_preprocessors != 0 && in->echo_reference != NULL)
+ //if (in->num_preprocessors != 0)
+ ret = process_frames(in, buffer, frames_rq);
+ else if (in->resampler != NULL)
+ ret = read_frames(in, buffer, frames_rq);
+ else
+ ret = pcm_read(in->pcm, buffer, bytes);
+
+ if (ret > 0)
+ ret = 0;
+
+ if (ret == 0 && adev->mic_mute){
+ LOGFUNC("%s(adev->mic_mute = %d)", __FUNCTION__, adev->mic_mute);
+ memset(buffer, 0, bytes);
+ }
+
+#if 0
+ FILE *dump_fp = NULL;
+
+ dump_fp = fopen("/data/dump_in.pcm", "a+");
+ if (dump_fp != NULL) {
+ fwrite(buffer, bytes, 1, dump_fp);
+ fclose(dump_fp);
+ }
+ else {
+ ALOGW("[Error] Can't write to /data/dump_in.pcm");
+ }
+#endif
+
+ exit:
+ if (ret < 0)
+ usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
+ in_get_sample_rate(&stream->common));
+
+ pthread_mutex_unlock(&in->lock);
+ 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)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ int status;
+ effect_descriptor_t desc;
+ LOGFUNC("*********%s", __FUNCTION__);
+
+ pthread_mutex_lock(&in->dev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (in->num_preprocessors >= MAX_PREPROCESSORS) {
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ status = (*effect)->get_descriptor(effect, &desc);
+ if (status != 0)
+ goto exit;
+
+ in->preprocessors[in->num_preprocessors++] = effect;
+
+ if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
+ in->need_echo_reference = true;
+ do_input_standby(in);
+ }
+
+exit:
+
+ pthread_mutex_unlock(&in->lock);
+ pthread_mutex_unlock(&in->dev->lock);
+ return status;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream,
+ effect_handle_t effect)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+ int i;
+ int status = -EINVAL;
+ bool found = false;
+ effect_descriptor_t desc;
+
+ pthread_mutex_lock(&in->dev->lock);
+ pthread_mutex_lock(&in->lock);
+ if (in->num_preprocessors <= 0) {
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ for (i = 0; i < in->num_preprocessors; i++) {
+ if (found) {
+ in->preprocessors[i - 1] = in->preprocessors[i];
+ continue;
+ }
+ if (in->preprocessors[i] == effect) {
+ in->preprocessors[i] = NULL;
+ status = 0;
+ found = true;
+ }
+ }
+
+ if (status != 0)
+ goto exit;
+
+ in->num_preprocessors--;
+
+ status = (*effect)->get_descriptor(effect, &desc);
+ if (status != 0)
+ goto exit;
+ if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
+ in->need_echo_reference = false;
+ do_input_standby(in);
+ }
+
+exit:
+
+ pthread_mutex_unlock(&in->lock);
+ pthread_mutex_unlock(&in->dev->lock);
+ return status;
+}
+/*
+static int in_set_voip_mode(struct audio_stream *stream, int mode)
+{
+ struct aml_stream_in *in= (struct aml_stream_in *)stream;
+ ALOGE("call in_set_voip_mode old:%d, new:%d", in->voip_mode, mode);
+
+ if(in->voip_mode == mode)
+ return 0;
+ else if(mode == 0)
+ {
+ in->voip_mode = mode;
+ }
+ else
+ {
+ in_standby(stream);
+
+ in->voip_mode = mode;
+ }
+
+ 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)
+{
+ struct aml_audio_device *ladev = (struct aml_audio_device *)dev;
+ struct aml_stream_out *out;
+ int channel_count = popcount(config->channel_mask);
+ int ret;
+
+ LOGFUNC("%s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d)", __FUNCTION__, devices,
+ config->format, channel_count, config->sample_rate);
+
+ out = (struct aml_stream_out *)calloc(1, sizeof(struct aml_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.common.set_voip_mode = out_set_voip_mode;
+ 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->config = pcm_config_out;
+
+ ret = check_output_stream(out);
+ if(ret < 0)
+ {
+ ALOGE("fail to open out stream, change channel count frome %d to %d", out->config.channels, channel_count);
+ out->config.channels = channel_count;
+ }
+
+ if(out->config.channels == 1)
+ {
+ config->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+ }
+ else if(out->config.channels == 2)
+ {
+ config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ }
+ else
+ {
+ ALOGE("Bad value of channel count : %d", out->config.channels);
+ }
+ out->dev = ladev;
+ out->standby = 1;
+
+ /* FIXME: when we support multiple output devices, we will want to
+ * do the following:
+ * adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
+ * adev->devices |= out->device;
+ * select_output_device(adev);
+ * This is because out_set_parameters() with a route is not
+ * guaranteed to be called after an output stream is opened.
+ */
+
+ 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);
+ LOGFUNC("%s(devices=0x%04x,format=%d, ch=0x%04x, SR=%d)", __FUNCTION__, devices,
+ config->format, config->channel_mask, config->sample_rate);
+
+ *stream_out = &out->stream;
+ return 0;
+
+err_open:
+ free(out);
+ *stream_out = NULL;
+ return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out *stream)
+{
+ struct aml_stream_out *out = (struct aml_stream_out *)stream;
+
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, stream);
+ out_standby(&stream->common);
+ if (out->buffer)
+ free(out->buffer);
+ if (out->resampler)
+ release_resampler(out->resampler);
+
+ free(stream);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+ LOGFUNC("%s(%p, %s)", __FUNCTION__, dev, kvpairs);
+
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int ret;
+
+ parms = str_parms_create_str(kvpairs);
+ ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
+ if (ret >= 0) {
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+ adev->low_power = false;
+ else
+ adev->low_power = true;
+ }
+
+ str_parms_destroy(parms);
+ return ret;
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ LOGFUNC("%s(%p, %s)", __FUNCTION__, dev, keys);
+ return strdup("");
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+ LOGFUNC("%s(%p)", __FUNCTION__, dev);
+ return 0;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+
+ //adev->voice_volume = volume;
+
+ LOGFUNC("%s(%p, %f)", __FUNCTION__, dev, volume);
+ //if (adev->mode == AUDIO_MODE_IN_CALL)
+ // ril_set_call_volume(&adev->ril, SOUND_TYPE_VOICE, volume);
+
+ return 0;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+ LOGFUNC("%s(%p, %f)", __FUNCTION__, dev, volume);
+ return -ENOSYS;
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev,
+ float *volume)
+{
+ return -ENOSYS;
+}
+
+static int adev_set_master_mute(struct audio_hw_device *dev, bool muted)
+{
+ return -ENOSYS;
+}
+
+static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted)
+{
+ return -ENOSYS;
+}
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, dev, mode);
+
+ pthread_mutex_lock(&adev->lock);
+ if (adev->mode != mode) {
+ adev->mode = mode;
+ select_mode(adev);
+ }
+ pthread_mutex_unlock(&adev->lock);
+
+ return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, dev, state);
+ adev->mic_mute = state;
+
+ return 0;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+ struct aml_audio_device *adev = (struct aml_audio_device *)dev;
+
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, state);
+ *state = adev->mic_mute;
+
+ return 0;
+
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
+{
+ size_t size;
+ int channel_count = popcount(config->channel_mask);
+
+ LOGFUNC("%s(%p, %d, %d, %d)", __FUNCTION__, dev, config->sample_rate,
+ config->format, channel_count);
+ if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
+ return 0;
+
+ return get_input_buffer_size(config->sample_rate,
+ config->format, channel_count);
+
+}
+
+static int adev_open_input_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ struct audio_stream_in **stream_in)
+{
+ struct aml_audio_device *ladev = (struct aml_audio_device *)dev;
+ struct aml_stream_in *in;
+ int ret;
+ int channel_count = popcount(config->channel_mask);
+ LOGFUNC("**********%s(%#x, %d, 0x%04x, %d)", __FUNCTION__,
+ devices, config->format, config->channel_mask, config->sample_rate);
+ if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
+ return -EINVAL;
+
+ in = (struct aml_stream_in *)calloc(1, sizeof(struct aml_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.common.set_voip_mode = in_set_voip_mode;
+ in->stream.set_gain = in_set_gain;
+ in->stream.read = in_read;
+ in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+ in->requested_rate = config->sample_rate;
+
+ memcpy(&in->config, &pcm_config_in, sizeof(pcm_config_in));
+ ret = check_input_stream(in);
+ if(ret < 0)
+ {
+ ALOGE("fail to open input stream, change channel count from %d to %d", in->config.channels, channel_count);
+ in->config.channels = channel_count;
+ }
+
+ if(in->config.channels == 1)
+ {
+ config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+ }
+ else if(in->config.channels == 2)
+ {
+ config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ }
+ else
+ {
+ ALOGE("Bad value of channel count : %d", in->config.channels);
+ }
+ in->buffer = malloc(in->config.period_size *
+ audio_stream_frame_size(&in->stream.common));
+ if (!in->buffer) {
+ ret = -ENOMEM;
+ goto err_open;
+ }
+
+ if (in->requested_rate != in->config.rate) {
+ LOGFUNC("%s(in->requested_rate=%d, in->config.rate=%d)",
+ __FUNCTION__, in->requested_rate, in->config.rate);
+ in->buf_provider.get_next_buffer = get_next_buffer;
+ in->buf_provider.release_buffer = release_buffer;
+ ret = create_resampler(in->config.rate,
+ in->requested_rate,
+ in->config.channels,
+ RESAMPLER_QUALITY_DEFAULT,
+ &in->buf_provider,
+ &in->resampler);
+
+ if (ret != 0) {
+ ret = -EINVAL;
+ goto err_open;
+ }
+ }
+
+ in->dev = ladev;
+ in->standby = 1;
+ in->device = devices;
+
+ *stream_in = &in->stream;
+ return 0;
+
+err_open:
+ if (in->resampler)
+ release_resampler(in->resampler);
+
+ free(in);
+ *stream_in = NULL;
+ return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream)
+{
+ struct aml_stream_in *in = (struct aml_stream_in *)stream;
+
+ LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, stream);
+ in_standby(&stream->common);
+
+ if (in->resampler) {
+ free(in->buffer);
+ release_resampler(in->resampler);
+ }
+ if (in->up_resampler) {
+ free(in->up_resampler_buffer);
+ release_resampler(in->up_resampler);
+ }
+ if (in->proc_buf)
+ free(in->proc_buf);
+ if (in->ref_buf)
+ free(in->ref_buf);
+
+ free(stream);
+
+ return;
+}
+
+static int adev_dump(const audio_hw_device_t *device, int fd)
+{
+ LOGFUNC("%s(%p, %d)", __FUNCTION__, device, fd);
+ return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+ struct aml_audio_device *adev = (struct aml_audio_device *)device;
+
+ LOGFUNC("%s(%p)", __FUNCTION__, device);
+ /* RIL */
+ //ril_close(&adev->ril);
+
+ mixer_close(adev->mixer);
+
+ free(device);
+ return 0;
+}
+
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return (/* OUT */
+ AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_ALL_SCO |
+ AUDIO_DEVICE_OUT_DEFAULT |
+ /* IN */
+ AUDIO_DEVICE_IN_COMMUNICATION |
+ AUDIO_DEVICE_IN_AMBIENT |
+ AUDIO_DEVICE_IN_BUILTIN_MIC |
+ AUDIO_DEVICE_IN_WIRED_HEADSET |
+ AUDIO_DEVICE_IN_AUX_DIGITAL |
+ AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_ALL_SCO |
+ AUDIO_DEVICE_IN_DEFAULT);
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct aml_audio_device *adev;
+ int ret;
+ LOGFUNC("%s(%p, %s, %p)", __FUNCTION__, module, name, device);
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+ return -EINVAL;
+
+ adev = calloc(1, sizeof(struct aml_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.get_supported_devices = adev_get_supported_devices;
+ 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->mixer = mixer_open(0);
+ if (!adev->mixer) {
+ free(adev);
+ ALOGE("Unable to open the mixer, aborting.");
+ return -EINVAL;
+ }
+
+#if 0
+{
+ struct mixer *mixer = adev->mixer;
+ struct mixer_ctl *ctl;
+ unsigned int i, j;
+ char name[128];
+
+ ALOGE("ctl_name... adev_open");
+
+ for(i = 0 ; i < mixer_get_num_ctls(mixer) ; i++) {
+ ctl = mixer_get_ctl(mixer, i);
+ if (ctl != NULL) {
+ j = mixer_ctl_get_name(ctl, name, 128);
+ ALOGE("ctl_name[%02d]: %s, type : %s", i, name, mixer_ctl_get_type_string(ctl));
+ if(mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_ENUM)
+ {
+ for(j=0; j<mixer_ctl_get_num_enums(ctl); j++)
+ {
+ mixer_ctl_get_enum_string(ctl, j, name, 128);
+ ALOGE("\t ENUM(%d) : %s", j, name);
+ }
+ }
+
+ }
+ else
+ ALOGE("ctl_name[%02d]: can not get control pointer", i);
+ }
+}
+#endif
+
+ /* Set the default route before the PCM stream is opened */
+ adev->mode = AUDIO_MODE_NORMAL;
+ adev->devices = AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_IN_BUILTIN_MIC;
+ select_output_device(adev);
+
+ *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 = "aml audio HW HAL",
+ .author = "amlogic, Corp.",
+ .methods = &hal_module_methods,
+ },
+};
diff --git a/audio_policy.c b/audio_policy.c
new file mode 100644
index 0000000..0f623b0
--- a/dev/null
+++ b/audio_policy.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 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_TAG "audio_policy_default"
+#define LOGFUNC(...) (LOGD(__VA_ARGS__))
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/log.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+
+struct default_ap_module {
+ struct audio_policy_module module;
+};
+
+struct default_ap_device {
+ struct audio_policy_device device;
+};
+
+struct default_audio_policy {
+ struct audio_policy policy;
+
+ struct audio_policy_service_ops *aps_ops;
+ void *service;
+};
+
+static int ap_set_device_connection_state(struct audio_policy *pol,
+ audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char *device_address)
+{
+ LOGFUNC("%s", __FUNCTION__);
+
+ return -ENOSYS;
+}
+
+static audio_policy_dev_state_t ap_get_device_connection_state(
+ const struct audio_policy *pol,
+ audio_devices_t device,
+ const char *device_address)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
+}
+
+static void ap_set_phone_state(struct audio_policy *pol, int state)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+static void ap_set_ringer_mode(struct audio_policy *pol, uint32_t mode,
+ uint32_t mask)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+static void ap_set_force_use(struct audio_policy *pol,
+ audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+ /* retreive current device category forced for a given usage */
+static audio_policy_forced_cfg_t ap_get_force_use(
+ const struct audio_policy *pol,
+ audio_policy_force_use_t usage)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return AUDIO_POLICY_FORCE_NONE;
+}
+
+/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE
+ * can still be muted. */
+static void ap_set_can_mute_enforced_audible(struct audio_policy *pol,
+ bool can_mute)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+static int ap_init_check(const struct audio_policy *pol)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return 0;
+}
+
+static audio_io_handle_t ap_get_output(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ uint32_t sampling_rate,
+ uint32_t format,
+ uint32_t channels,
+ audio_policy_output_flags_t flags)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return 0;
+}
+
+static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static void ap_release_output(struct audio_policy *pol,
+ audio_io_handle_t output)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+static audio_io_handle_t ap_get_input(struct audio_policy *pol, int inputSource,
+ uint32_t sampling_rate,
+ uint32_t format,
+ uint32_t channels,
+ audio_in_acoustics_t acoustics)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return 0;
+}
+
+static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+static void ap_init_stream_volume(struct audio_policy *pol,
+ audio_stream_type_t stream, int index_min,
+ int index_max)
+{
+ LOGFUNC("%s", __FUNCTION__);
+}
+
+static int ap_set_stream_volume_index(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static int ap_get_stream_volume_index(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return 0;
+}
+
+static uint32_t ap_get_devices_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return 0;
+}
+
+static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
+ struct effect_descriptor_s *desc)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return 0;
+}
+
+static int ap_register_effect(struct audio_policy *pol,
+ struct effect_descriptor_s *desc,
+ audio_io_handle_t output,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static int ap_unregister_effect(struct audio_policy *pol, int id)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static bool ap_is_stream_active(const struct audio_policy *pol, int stream,
+ uint32_t in_past_ms)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return false;
+}
+
+static int ap_dump(const struct audio_policy *pol, int fd)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ return -ENOSYS;
+}
+
+static int create_default_ap(const struct audio_policy_device *device,
+ struct audio_policy_service_ops *aps_ops,
+ void *service,
+ struct audio_policy **ap)
+{
+ struct default_ap_device *dev;
+ struct default_audio_policy *dap;
+ int ret;
+ LOGFUNC("%s", __FUNCTION__);
+
+ *ap = NULL;
+
+ if (!service || !aps_ops)
+ return -EINVAL;
+
+ dap = (struct default_audio_policy *)calloc(1, sizeof(*dap));
+ if (!dap)
+ return -ENOMEM;
+
+ dap->policy.set_device_connection_state = ap_set_device_connection_state;
+ dap->policy.get_device_connection_state = ap_get_device_connection_state;
+ dap->policy.set_phone_state = ap_set_phone_state;
+ dap->policy.set_ringer_mode = ap_set_ringer_mode;
+ dap->policy.set_force_use = ap_set_force_use;
+ dap->policy.get_force_use = ap_get_force_use;
+ dap->policy.set_can_mute_enforced_audible =
+ ap_set_can_mute_enforced_audible;
+ dap->policy.init_check = ap_init_check;
+ dap->policy.get_output = ap_get_output;
+ dap->policy.start_output = ap_start_output;
+ dap->policy.stop_output = ap_stop_output;
+ dap->policy.release_output = ap_release_output;
+ dap->policy.get_input = ap_get_input;
+ dap->policy.start_input = ap_start_input;
+ dap->policy.stop_input = ap_stop_input;
+ dap->policy.release_input = ap_release_input;
+ dap->policy.init_stream_volume = ap_init_stream_volume;
+ dap->policy.set_stream_volume_index = ap_set_stream_volume_index;
+ dap->policy.get_stream_volume_index = ap_get_stream_volume_index;
+ dap->policy.get_strategy_for_stream = ap_get_strategy_for_stream;
+ dap->policy.get_devices_for_stream = ap_get_devices_for_stream;
+ dap->policy.get_output_for_effect = ap_get_output_for_effect;
+ dap->policy.register_effect = ap_register_effect;
+ dap->policy.unregister_effect = ap_unregister_effect;
+ dap->policy.set_effect_enabled = ap_set_effect_enabled;
+ dap->policy.is_stream_active = ap_is_stream_active;
+ dap->policy.dump = ap_dump;
+
+ dap->service = service;
+ dap->aps_ops = aps_ops;
+
+ *ap = &dap->policy;
+ return 0;
+}
+
+static int destroy_default_ap(const struct audio_policy_device *ap_dev,
+ struct audio_policy *ap)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ free(ap);
+ return 0;
+}
+
+static int default_ap_dev_close(hw_device_t* device)
+{
+ LOGFUNC("%s", __FUNCTION__);
+ free(device);
+ return 0;
+}
+
+static int default_ap_dev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct default_ap_device *dev;
+ LOGFUNC("%s", __FUNCTION__);
+
+ *device = NULL;
+
+ if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
+ return -EINVAL;
+
+ dev = (struct default_ap_device *)calloc(1, sizeof(*dev));
+ if (!dev)
+ return -ENOMEM;
+
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = 0;
+ dev->device.common.module = (hw_module_t *)module;
+ dev->device.common.close = default_ap_dev_close;
+ dev->device.create_audio_policy = create_default_ap;
+ dev->device.destroy_audio_policy = destroy_default_ap;
+
+ *device = &dev->device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t default_ap_module_methods = {
+ .open = default_ap_dev_open,
+};
+
+struct default_ap_module HAL_MODULE_INFO_SYM = {
+ .module = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = AUDIO_POLICY_HARDWARE_MODULE_ID,
+ .name = "Aml-Test audio policy HAL",
+ .author = "The Android Open Source Project",
+ .methods = &default_ap_module_methods,
+ },
+ },
+};
diff --git a/m3codec_mixer_ctl.h b/m3codec_mixer_ctl.h
new file mode 100644
index 0000000..c4f3e33
--- a/dev/null
+++ b/m3codec_mixer_ctl.h
@@ -0,0 +1,43 @@
+/*
+ * m3codec_mixer_ctl.h -- AML_M3 Mixer control for Android ICS
+ *
+ * Copyright 2012 Amlogic Corp.
+ *
+ */
+
+#ifndef _M3CODEC_MIXER_CTL_H_
+#define _M3CODEC_MIXER_CTL_H_
+
+//Todo: add route controls
+struct route_setting
+{
+ char *ctl_name;
+ int intval;
+ char *strval;
+};
+struct route_setting mic_input[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};
+struct route_setting line_input[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};
+static struct route_setting output_headphone[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};static struct route_setting output_speaker[] =
+{
+ {
+ .ctl_name = NULL,
+ },
+};
+
+#endif //_M3CODEC_MIXER_CTL_H_
+
diff --git a/rt5631_mixer_ctrl.h b/rt5631_mixer_ctrl.h
new file mode 100644
index 0000000..5f8fc34
--- a/dev/null
+++ b/rt5631_mixer_ctrl.h
@@ -0,0 +1,203 @@
+/*
+ * rt5631_mixer_ctrl.h -- RT5631 Mixer control for Android ICS
+ *
+ * Copyright 2012 Amlogic Corp.
+ *
+ */
+
+#ifndef _RT5631_MIXER_CTRL_H_
+#define _RT5631_MIXER_CTRL_H_
+
+struct route_setting
+{
+ char *ctl_name;
+ int intval;
+ char *strval;
+};
+
+/* Mixer control names */
+/* INT type */
+#define MIXER_HP_PLAYBACK_VOLUME "HP Playback Volume"
+#define MIXER_SPK_PLAYBACK_VOLUME "Speaker Playback Volume"
+#define MIXER_MIC1_BOOST "MIC1 Boost"
+
+/* ENUM type */
+#define MIXER_JACK_FUNC_ENUM "Jack Function"
+#define MIXER_SPEAKER_FUNC_ENUM "Speaker Function"
+#define MIXER_R_HPVOL_MUX_ENUM "Right HPVOL Mux"
+#define MIXER_L_HPVOL_MUX_ENUM "Left HPVOL Mux"
+#define MIXER_R_SPKVOL_MUX_ENUM "Right SPKVOL Mux"
+#define MIXER_L_SPKVOL_MUX_ENUM "Left SPKVOL Mux"
+#define MIXER_SPKR_MUX_ENUM "SPOR Mux"
+#define MIXER_SPKL_MUX_ENUM "SPOL Mux"
+#define MIXER_HPL_MUX_ENUM "HPL Mux"
+#define MIXER_HPR_MUX_ENUM "HPR Mux"
+
+/* BOOL type */
+#define MIXER_HP_PLAYBACK_SWITCH "HP Playback Switch"
+#define MIXER_SPK_PLAYBACK_SWITCH "Speaker Playback Switch"
+#define MIXER_RECMIXL_MIC1_CAPTURE_SWITCH "RECMIXL Mixer MIC1_BST1 Capture Switch"
+#define MIXER_OUT_DACR_PLAYBACK_SWITCH "OUTMIXR Mixer DACR Playback Switch"
+#define MIXER_OUT_DACL_PLAYBACK_SWITCH "OUTMIXL Mixer DACL Playback Switch"
+#define MIXER_SPKMIX_DACR_PLAYBACK_SWITCH "SPKMIXR Mixer DACR Playback Switch"
+#define MIXER_SPKMIX_DACL_PLAYBACK_SWITCH "SPKMIXL Mixer DACL Playback Switch"
+#define MIXER_SPKRMIX_SPKVOLR_PLAYBACK_SWITCH "SPORMIX Mixer SPKVOLR Playback Switch"
+#define MIXER_SPKLMIX_SPKVOLL_PLAYBACK_SWITCH "SPOLMIX Mixer SPKVOLL Playback Switch"
+#define MIXER_SPKRMIX_SPKVOLL_PLAYBACK_SWITCH "SPORMIX Mixer SPKVOLL Playback Switch"
+#define MIXER_SPKLMIX_SPKVOLR_PLAYBACK_SWITCH "SPOLMIX Mixer SPKVOLR Playback Switch"
+
+/* Mixer control value */
+#define MIXER_JACK_SPEAKER "Speaker"
+#define MIXER_JACK_HEADPHONE "HeadPhone"
+#define MIXER_SPEAKER_ON "On"
+#define MIXER_SPEAKER_OFF "Off"
+#define MIXER_L_HPVOL_OUTMIX "OUTMIXL"
+#define MIXER_R_HPVOL_OUTMIX "OUTMIXR"
+#define MIXER_L_SPKVOL_OUTMIX "SPKMIXL"
+#define MIXER_R_SPKVOL_OUTMIX "SPKMIXR"
+#define MIXER_SPK_MUX_SPOL "SPOLMIX"
+#define MIXER_SPK_MUX_SPOR "SPORMIX"
+
+struct route_setting mic_input[] = {
+ {
+ .ctl_name = MIXER_RECMIXL_MIC1_CAPTURE_SWITCH,
+ .intval = 1
+ },
+ {
+ .ctl_name = MIXER_MIC1_BOOST,
+ .intval = 3
+ },
+ {
+ .ctl_name = NULL,
+ },
+};
+
+struct route_setting line_input[] = {
+ {
+ .ctl_name = NULL,
+ },
+};
+
+struct route_setting output_speaker[] = {
+ {
+ .ctl_name = MIXER_SPKMIX_DACR_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_SPKMIX_DACL_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_R_SPKVOL_MUX_ENUM,
+ .strval = MIXER_R_SPKVOL_OUTMIX,
+ },
+ {
+ .ctl_name = MIXER_L_SPKVOL_MUX_ENUM,
+ .strval = MIXER_L_SPKVOL_OUTMIX,
+ },
+ {
+ .ctl_name = MIXER_SPKLMIX_SPKVOLL_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_SPKRMIX_SPKVOLR_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+/* {
+ .ctl_name = MIXER_SPKRMIX_SPKVOLL_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_SPKLMIX_SPKVOLR_PLAYBACK_SWITCH,
+ .intval = 1,
+ },*/
+ {
+ .ctl_name = MIXER_SPKR_MUX_ENUM,
+ .strval = MIXER_SPK_MUX_SPOR,
+ },
+ {
+ .ctl_name = MIXER_SPKL_MUX_ENUM,
+ .strval = MIXER_SPK_MUX_SPOL,
+ },
+/* {
+ .ctl_name = MIXER_SPK_PLAYBACK_SWITCH,
+ .intval = 1,
+ },*/
+ {
+ .ctl_name = MIXER_SPK_PLAYBACK_VOLUME,
+ .intval = 33,
+ },
+ {
+ .ctl_name = NULL,
+ },
+};
+
+struct route_setting output_headphone[] = {
+ {
+ .ctl_name = MIXER_HPL_MUX_ENUM,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_HPR_MUX_ENUM,
+ .intval = 1,
+ },
+/* {
+ .ctl_name = MIXER_HP_PLAYBACK_SWITCH,
+ .intval = 1,
+ },*/
+ {
+ .ctl_name = MIXER_HP_PLAYBACK_VOLUME,
+ .intval = 31,
+ },
+ {
+ .ctl_name = NULL,
+ },
+ {
+ .ctl_name = NULL,
+ },
+};
+
+struct route_setting output_headset[] = {
+ {
+ .ctl_name = MIXER_R_HPVOL_MUX_ENUM,
+ .strval = MIXER_R_HPVOL_OUTMIX,
+ },
+ {
+ .ctl_name = MIXER_L_HPVOL_MUX_ENUM,
+ .strval = MIXER_L_HPVOL_OUTMIX,
+ },
+ {
+ .ctl_name = MIXER_OUT_DACR_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_OUT_DACL_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_HP_PLAYBACK_SWITCH,
+ .intval = 1,
+ },
+ {
+ .ctl_name = MIXER_HP_PLAYBACK_VOLUME,
+ .intval = 31,
+ },
+ {
+ .ctl_name = MIXER_JACK_FUNC_ENUM,
+ .strval = MIXER_JACK_HEADPHONE,
+ },
+ {
+ .ctl_name = MIXER_SPEAKER_FUNC_ENUM,
+ .strval = MIXER_SPEAKER_OFF,
+ },
+ {
+ .ctl_name = NULL,
+ },
+ {
+ .ctl_name = NULL,
+ },
+};
+
+
+#endif //_RT5631_MIXER_CTRL_H_
+