Merge commit 'android-4.4.1_r1' into HEAD
* commit 'android-4.4.1_r1':
hal: Fix the audio loss issue on codec back end
hal: Fix for Audio Route issue when sound path changes
audio: fix output flag test in open_output_stream
Conflicts:
hal/audio_hw.c
Change-Id: Ib470b143c37ca7719757d20f37253cb256c26343
diff --git a/Android.mk b/Android.mk
index 1228876..9bb3250 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,13 +1,21 @@
-ifneq ($(filter msm8960 msm8226 msm8x26 msm8974 msm8x74,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084,$(TARGET_BOARD_PLATFORM)),)
MY_LOCAL_PATH := $(call my-dir)
ifeq ($(BOARD_USES_LEGACY_ALSA_AUDIO),true)
include $(MY_LOCAL_PATH)/legacy/Android.mk
else
+ifneq ($(filter mpq8092,$(TARGET_BOARD_PLATFORM)),)
+include $(MY_LOCAL_PATH)/hal_mpq/Android.mk
+else
include $(MY_LOCAL_PATH)/hal/Android.mk
+endif
include $(MY_LOCAL_PATH)/voice_processing/Android.mk
+include $(MY_LOCAL_PATH)/mm-audio/Android.mk
+include $(MY_LOCAL_PATH)/policy_hal/Android.mk
include $(MY_LOCAL_PATH)/visualizer/Android.mk
+include $(MY_LOCAL_PATH)/audiod/Android.mk
+include $(MY_LOCAL_PATH)/post_proc/Android.mk
endif
endif
diff --git a/audiod/Android.mk b/audiod/Android.mk
new file mode 100644
index 0000000..8f25125
--- /dev/null
+++ b/audiod/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+include external/stlport/libstlport.mk
+
+LOCAL_SRC_FILES:= \
+ audiod_main.cpp \
+ AudioDaemon.cpp \
+
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libbinder \
+ libmedia \
+ libstlport
+
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_MODULE:= audiod
+LOCAL_MODULE_TAGS:= debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/audiod/AudioDaemon.cpp b/audiod/AudioDaemon.cpp
new file mode 100644
index 0000000..6c8d991
--- /dev/null
+++ b/audiod/AudioDaemon.cpp
@@ -0,0 +1,242 @@
+/* AudioDaemon.cpp
+Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
+
+#define LOG_TAG "AudioDaemon"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <media/AudioSystem.h>
+#include <sys/poll.h>
+
+#include "AudioDaemon.h"
+
+int bootup_complete = 0;
+
+namespace android {
+
+ AudioDaemon::AudioDaemon() : Thread(false) {
+ }
+
+ AudioDaemon::~AudioDaemon() {
+ putStateFDs(mSndCardFd);
+ }
+
+ void AudioDaemon::onFirstRef() {
+ ALOGV("Start audiod daemon");
+ run("AudioDaemon", PRIORITY_AUDIO);
+ }
+
+ void AudioDaemon::binderDied(const wp<IBinder>& who)
+ {
+ requestExit();
+ }
+
+ bool AudioDaemon::getStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
+ {
+ FILE *fp;
+ int fd;
+ char *ptr, *saveptr;
+ char buffer[128];
+ int line = 0;
+ String8 path;
+ int sndcard;
+ const char* cards = "/proc/asound/cards";
+
+ if ((fp = fopen(cards, "r")) == NULL) {
+ ALOGE("Cannot open %s file to get list of sound cars", cards);
+ return false;
+ }
+
+ sndcardFdPair.clear();
+ memset(buffer, 0x0, sizeof(buffer));
+ while ((fgets(buffer, sizeof(buffer), fp) != NULL)) {
+ if (line % 2)
+ continue;
+ ptr = strtok_r(buffer, " [", &saveptr);
+ if (ptr) {
+ path = "/proc/asound/card";
+ path += ptr;
+ path += "/state";
+ ALOGD("Opening sound card state : %s", path.string());
+ fd = open(path.string(), O_RDONLY);
+ if (fd == -1) {
+ ALOGE("Open %s failed : %s", path.string(), strerror(errno));
+ } else {
+ /* returns vector of pair<sndcard, fd> */
+ sndcard = atoi(ptr);
+ sndcardFdPair.push_back(std::make_pair(sndcard, fd));
+ }
+ }
+ line++;
+ }
+
+ ALOGV("%s: %d sound cards detected", __func__, sndcardFdPair.size());
+ fclose(fp);
+
+ return sndcardFdPair.size() > 0 ? true : false;
+ }
+
+ void AudioDaemon::putStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
+ {
+ unsigned int i;
+ for (i = 0; i < sndcardFdPair.size(); i++)
+ close(sndcardFdPair[i].second);
+ sndcardFdPair.clear();
+ }
+
+ status_t AudioDaemon::readyToRun() {
+
+ ALOGV("readyToRun: open snd card state node files");
+ return NO_ERROR;
+ }
+
+#define MAX_SLEEP_RETRY 100
+#define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */
+
+ bool AudioDaemon::threadLoop()
+ {
+ int max = -1;
+ unsigned int i;
+ bool ret = true;
+ snd_card_status cur_state = snd_card_offline;
+ struct pollfd *pfd = NULL;
+ char rd_buf[9];
+ unsigned int sleepRetry = 0;
+ bool audioInitDone = false;
+
+ ALOGV("Start threadLoop()");
+ while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) {
+ if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) {
+ ALOGE("Sleeping for 100 ms");
+ usleep(AUDIO_INIT_SLEEP_WAIT*1000);
+ sleepRetry++;
+ } else {
+ audioInitDone = true;
+ }
+ }
+
+ if (audioInitDone == false)
+ ALOGE("Sound Card is empty!!!");
+
+ pfd = new pollfd[mSndCardFd.size()];
+ bzero(pfd, sizeof(*pfd) * mSndCardFd.size());
+ for (i = 0; i < mSndCardFd.size(); i++) {
+ pfd[i].fd = mSndCardFd[i].second;
+ pfd[i].events = POLLPRI;
+ }
+
+ ALOGD("read for sound card state change before while");
+ for (i = 0; i < mSndCardFd.size(); i++) {
+ if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
+ ALOGE("Error receiving sound card state event (%s)", strerror(errno));
+ ret = false;
+ } else {
+ rd_buf[8] = '\0';
+ ALOGD("sound card state file content: %s before while",rd_buf);
+ lseek(pfd[i].fd, 0, SEEK_SET);
+
+ if (strstr(rd_buf, "OFFLINE")) {
+ ALOGE("put cur_state to offline");
+ cur_state = snd_card_offline;
+ } else if (strstr(rd_buf, "ONLINE")){
+ ALOGE("put cur_state to online");
+ cur_state = snd_card_online;
+ } else {
+ ALOGE("ERROR rd_buf %s", rd_buf);
+ }
+
+ ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state );
+ if (cur_state == snd_card_online && !bootup_complete) {
+ bootup_complete = 1;
+ ALOGE("sound card up is deteced before while");
+ ALOGE("bootup_complete set to 1");
+ }
+ }
+ }
+
+ while (1) {
+ ALOGD("poll() for sound card state change ");
+ if (poll(pfd, mSndCardFd.size(), -1) < 0) {
+ ALOGE("poll() failed (%s)", strerror(errno));
+ ret = false;
+ break;
+ }
+
+ ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size());
+ for (i = 0; i < mSndCardFd.size(); i++) {
+ if (pfd[i].revents & POLLPRI) {
+ if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
+ ALOGE("Error receiving sound card state event (%s)", strerror(errno));
+ ret = false;
+ } else {
+ rd_buf[8] = '\0';
+ ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete);
+ lseek(pfd[i].fd, 0, SEEK_SET);
+
+ if (strstr(rd_buf, "OFFLINE")) {
+ cur_state = snd_card_offline;
+ } else if (strstr(rd_buf, "ONLINE")){
+ cur_state = snd_card_online;
+ }
+
+ if (bootup_complete) {
+ ALOGV("bootup_complete, so NofityAudioSystem");
+ notifyAudioSystem(mSndCardFd[i].first, cur_state);
+ }
+
+ if (cur_state == snd_card_online && !bootup_complete) {
+ bootup_complete = 1;
+ }
+ }
+ }
+ }
+ }
+
+ putStateFDs(mSndCardFd);
+ delete [] pfd;
+
+ ALOGV("Exiting Poll ThreadLoop");
+ return ret;
+ }
+
+ void AudioDaemon::notifyAudioSystem(int snd_card, snd_card_status status) {
+
+ String8 str;
+ char buf[4] = {0,};
+
+ str = "SND_CARD_STATUS=";
+ snprintf(buf, sizeof(buf), "%d", snd_card);
+ str += buf;
+ if (status == snd_card_online)
+ str += ",ONLINE";
+ else
+ str += ",OFFLINE";
+ ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
+ AudioSystem::setParameters(0, str);
+ }
+}
diff --git a/audiod/AudioDaemon.h b/audiod/AudioDaemon.h
new file mode 100644
index 0000000..15c0cf1
--- /dev/null
+++ b/audiod/AudioDaemon.h
@@ -0,0 +1,67 @@
+/* AudioDaemon.h
+
+Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <vector>
+
+#include <utils/threads.h>
+#include <utils/String8.h>
+
+
+namespace android {
+
+enum snd_card_status { snd_card_online, snd_card_offline};
+
+class AudioDaemon:public Thread, public IBinder :: DeathRecipient
+{
+ /*Overrides*/
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ virtual void binderDied(const wp < IBinder > &who);
+
+ bool processUeventMessage();
+ void notifyAudioSystem(int snd_card, snd_card_status status);
+ int mUeventSock;
+ bool getStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair);
+ void putStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair);
+
+public:
+ AudioDaemon();
+ virtual ~AudioDaemon();
+
+private:
+ std::vector<std::pair<int,int> > mSndCardFd;
+};
+
+}
diff --git a/audiod/audiod_main.cpp b/audiod/audiod_main.cpp
new file mode 100644
index 0000000..50691fd
--- /dev/null
+++ b/audiod/audiod_main.cpp
@@ -0,0 +1,60 @@
+/* Copyright (C) 2007 The Android Open Source Project
+
+Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+
+Not a Contribution, Apache license notifications and license are retained
+for attribution purposes only.
+
+* 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 "AudioDaemonMain"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <cutils/properties.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+# include <sys/resource.h>
+#endif
+
+#include "AudioDaemon.h"
+
+using namespace android;
+
+// ---------------------------------------------------------------------------
+
+int main(int argc, char** argv)
+{
+#if defined(HAVE_PTHREADS)
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+#endif
+
+
+ ALOGV("Audio daemon starting sequence..");
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ sp<AudioDaemon> audioService = new AudioDaemon();
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/hal/Android.mk b/hal/Android.mk
index b5949da..d8a4733 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -7,15 +7,95 @@
LOCAL_ARM_MODE := arm
AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
-ifneq ($(filter msm8974 msm8226,$(TARGET_BOARD_PLATFORM)),)
+
+ifneq ($(filter msm8974 msm8226 msm8610 apq8084,$(TARGET_BOARD_PLATFORM)),)
# B-family platform uses msm8974 code base
AUDIO_PLATFORM = msm8974
+ MULTIPLE_HW_VARIANTS_ENABLED := true
+ifneq ($(filter msm8610,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_MSM8610
+endif
+ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_MSM8x26
+endif
+ifneq ($(filter apq8084,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_APQ8084
+endif
endif
LOCAL_SRC_FILES := \
audio_hw.c \
+ voice.c \
$(AUDIO_PLATFORM)/platform.c
+LOCAL_SRC_FILES += audio_extn/audio_extn.c
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true)
+ LOCAL_CFLAGS += -DANC_HEADSET_ENABLED
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true)
+ LOCAL_CFLAGS += -DAFE_PROXY_ENABLED
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true)
+ LOCAL_CFLAGS += -DFM_ENABLED
+ LOCAL_SRC_FILES += audio_extn/fm.c
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_USBAUDIO)),true)
+ LOCAL_CFLAGS += -DUSB_HEADSET_ENABLED
+ LOCAL_SRC_FILES += audio_extn/usb.c
+endif
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_HFP)),true)
+ LOCAL_CFLAGS += -DHFP_ENABLED
+ LOCAL_SRC_FILES += audio_extn/hfp.c
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_SSR)),true)
+ LOCAL_CFLAGS += -DSSR_ENABLED
+ LOCAL_SRC_FILES += audio_extn/ssr.c
+ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/surround_sound/
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_MULTI_VOICE_SESSIONS)),true)
+ LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED
+ LOCAL_SRC_FILES += voice_extn/voice_extn.c
+ LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true)
+ LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_VOIP)),true)
+ LOCAL_CFLAGS += -DCOMPRESS_VOIP_ENABLED
+ LOCAL_SRC_FILES += voice_extn/compress_voip.c
+endif
+endif
+
+ifneq ($(strip, $(AUDIO_FEATURE_DISABLED_SPKR_PROTECTION)),true)
+ifneq ($(filter msm8974,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS += -DSPKR_PROT_ENABLED
+ LOCAL_SRC_FILES += audio_extn/spkr_protection.c
+ LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+endif
+endif
+
+ifdef MULTIPLE_HW_VARIANTS_ENABLED
+ LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
+ LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_CAPTURE)),true)
+ LOCAL_CFLAGS += -DCOMPRESS_CAPTURE_ENABLED
+ LOCAL_SRC_FILES += audio_extn/compress_capture.c
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DS1_DOLBY_DDP)),true)
+ LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED
+ LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+endif
+
LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
@@ -24,15 +104,26 @@
libaudioroute \
libdl
-
LOCAL_C_INCLUDES += \
external/tinyalsa/include \
external/tinycompress/include \
$(call include-path-for, audio-route) \
$(call include-path-for, audio-effects) \
- $(LOCAL_PATH)/$(AUDIO_PLATFORM)
+ $(LOCAL_PATH)/$(AUDIO_PLATFORM) \
+ $(LOCAL_PATH)/audio_extn \
+ $(LOCAL_PATH)/voice_extn
-LOCAL_MODULE := audio.primary.$(AUDIO_PLATFORM)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true)
+ LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED
+ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-listen
+ LOCAL_SRC_FILES += audio_extn/listen.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true)
+ LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED
+endif
+
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
new file mode 100644
index 0000000..72e2f9c
--- /dev/null
+++ b/hal/audio_extn/audio_extn.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "audio_extn.h"
+
+#include "sound/compress_params.h"
+
+#define MAX_SLEEP_RETRY 100
+#define WIFI_INIT_WAIT_SLEEP 50
+
+struct audio_extn_module {
+ bool anc_enabled;
+ bool aanc_enabled;
+ uint32_t proxy_channel_num;
+};
+
+static struct audio_extn_module aextnmod = {
+ .anc_enabled = 0,
+ .aanc_enabled = 0,
+ .proxy_channel_num = 2,
+};
+
+#define AUDIO_PARAMETER_KEY_ANC "anc_enabled"
+#define AUDIO_PARAMETER_KEY_WFD "wfd_channel_cap"
+#define AUDIO_PARAMETER_CAN_OPEN_PROXY "can_open_proxy"
+#ifndef FM_ENABLED
+#define audio_extn_fm_set_parameters(adev, parms) (0)
+#else
+void audio_extn_fm_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+#endif
+#ifndef HFP_ENABLED
+void audio_extn_hfp_set_parameters(adev, parms) (0)
+#else
+void audio_extn_hfp_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+#endif
+#ifndef SSR_ENABLED
+#define audio_extn_ssr_get_parameters(query, reply) (0)
+#else
+void audio_extn_ssr_get_parameters(struct str_parms *query,
+
+ struct str_parms *reply);
+#endif
+
+#ifndef ANC_HEADSET_ENABLED
+#define audio_extn_set_anc_parameters(adev, parms) (0)
+#else
+bool audio_extn_get_anc_enabled(void)
+{
+ ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled);
+ return (aextnmod.anc_enabled ? true: false);
+}
+
+bool audio_extn_should_use_handset_anc(int in_channels)
+{
+ char prop_aanc[PROPERTY_VALUE_MAX] = "false";
+
+ property_get("persist.aanc.enable", prop_aanc, "0");
+ if (!strncmp("true", prop_aanc, 4)) {
+ ALOGD("%s: AANC enabled in the property", __func__);
+ aextnmod.aanc_enabled = 1;
+ }
+
+ return (aextnmod.aanc_enabled && aextnmod.anc_enabled
+ && (in_channels == 1));
+}
+
+bool audio_extn_should_use_fb_anc(void)
+{
+ char prop_anc[PROPERTY_VALUE_MAX] = "feedforward";
+
+ property_get("persist.headset.anc.type", prop_anc, "0");
+ if (!strncmp("feedback", prop_anc, sizeof("feedback"))) {
+ ALOGD("%s: FB ANC headset type enabled\n", __func__);
+ return true;
+ }
+ return false;
+}
+
+void audio_extn_set_anc_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ int ret;
+ char value[32] ={0};
+ struct listnode *node;
+ struct audio_usecase *usecase;
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_ANC, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if (strcmp(value, "true") == 0)
+ aextnmod.anc_enabled = true;
+ else
+ aextnmod.anc_enabled = false;
+ }
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK) {
+ if (usecase->stream.out->devices == \
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ usecase->stream.out->devices == \
+ AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ select_devices(adev, usecase->id);
+ ALOGV("%s: switching device", __func__);
+ break;
+ }
+ }
+ }
+
+ ALOGD("%s: anc_enabled:%d", __func__, aextnmod.anc_enabled);
+}
+#endif /* ANC_HEADSET_ENABLED */
+
+#ifndef AFE_PROXY_ENABLED
+#define audio_extn_set_afe_proxy_parameters(parms) (0)
+#define audio_extn_get_afe_proxy_parameters(query, reply) (0)
+#else
+int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev)
+{
+ int32_t ret = 0;
+ const char *channel_cnt_str = NULL;
+ struct mixer_ctl *ctl = NULL;
+ const char *mixer_ctl_name = "PROXY_RX Channels";
+
+
+ ALOGD("%s: entry", __func__);
+ /* use the existing channel count set by hardware params to
+ configure the back end for stereo as usb/a2dp would be
+ stereo by default */
+ ALOGD("%s: channels = %d", __func__,
+ aextnmod.proxy_channel_num);
+ switch (aextnmod.proxy_channel_num) {
+ case 8: channel_cnt_str = "Eight"; break;
+ case 7: channel_cnt_str = "Seven"; break;
+ case 6: channel_cnt_str = "Six"; break;
+ case 5: channel_cnt_str = "Five"; break;
+ case 4: channel_cnt_str = "Four"; break;
+ case 3: channel_cnt_str = "Three"; break;
+ default: channel_cnt_str = "Two"; break;
+ }
+
+ if(aextnmod.proxy_channel_num >= 2 && aextnmod.proxy_channel_num < 8) {
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ }
+ mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+
+ ALOGD("%s: exit", __func__);
+ return ret;
+}
+
+void audio_extn_set_afe_proxy_parameters(struct str_parms *parms)
+{
+ int ret, val;
+ char value[32]={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_WFD, value,
+ sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ aextnmod.proxy_channel_num = val;
+ ALOGD("%s: channel capability set to: %d", __func__,
+ aextnmod.proxy_channel_num);
+ }
+}
+
+int audio_extn_get_afe_proxy_parameters(struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret, val;
+ char value[32]={0};
+ char *str = NULL;
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_CAN_OPEN_PROXY, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if (audio_extn_usb_is_proxy_inuse())
+ val = 0;
+ else
+ val = 1;
+ str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val);
+ }
+
+ return 0;
+}
+#endif /* AFE_PROXY_ENABLED */
+
+void audio_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ audio_extn_set_anc_parameters(adev, parms);
+ audio_extn_set_afe_proxy_parameters(parms);
+ audio_extn_fm_set_parameters(adev, parms);
+ audio_extn_listen_set_parameters(adev, parms);
+ audio_extn_hfp_set_parameters(adev, parms);
+}
+
+void audio_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ audio_extn_get_afe_proxy_parameters(query, reply);
+ audio_extn_ssr_get_parameters(query, reply);
+
+ ALOGD("%s: returns %s", __func__, str_parms_to_str(reply));
+}
+
+#ifdef AUXPCM_BT_ENABLED
+int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
+ const char* mixer_xml_path,
+ const char* mixer_xml_path_auxpcm)
+{
+ char bt_soc[128];
+ bool wifi_init_complete = false;
+ int sleep_retry = 0;
+
+ while (!wifi_init_complete && sleep_retry < MAX_SLEEP_RETRY) {
+ property_get("qcom.bluetooth.soc", bt_soc, NULL);
+ if (strncmp(bt_soc, "unknown", sizeof("unknown"))) {
+ wifi_init_complete = true;
+ } else {
+ usleep(WIFI_INIT_WAIT_SLEEP*1000);
+ sleep_retry++;
+ }
+ }
+
+ if (!strncmp(bt_soc, "ath3k", sizeof("ath3k")))
+ adev->audio_route = audio_route_init(mixer_card, mixer_xml_path_auxpcm);
+ else
+ adev->audio_route = audio_route_init(mixer_card, mixer_xml_path);
+
+ return 0;
+}
+#endif /* AUXPCM_BT_ENABLED */
+
+
+#ifdef DS1_DOLBY_DDP_ENABLED
+
+bool audio_extn_dolby_is_supported_format(audio_format_t format)
+{
+ if (format == AUDIO_FORMAT_AC3 ||
+ format == AUDIO_FORMAT_EAC3)
+ return true;
+ else
+ return false;
+}
+
+int audio_extn_dolby_get_snd_codec_id(audio_format_t format)
+{
+ int id = 0;
+
+ switch (format) {
+ case AUDIO_FORMAT_AC3:
+ id = SND_AUDIOCODEC_AC3;
+ break;
+ case AUDIO_FORMAT_EAC3:
+ id = SND_AUDIOCODEC_EAC3;
+ break;
+ default:
+ ALOGE("%s: Unsupported audio format :%x", __func__, format);
+ }
+
+ return id;
+}
+
+int audio_extn_dolby_set_DMID(struct audio_device *adev)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "DS1 Security";
+ char c_dmid[128] = {0};
+ int i_dmid, ret;
+
+ property_get("dmid",c_dmid,"0");
+ i_dmid = atoi(c_dmid);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid);
+ ret = mixer_ctl_set_value(ctl, 0, i_dmid);
+
+ return ret;
+}
+#endif /* DS1_DOLBY_DDP_ENABLED */
+
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
new file mode 100644
index 0000000..e6db5c1
--- /dev/null
+++ b/hal/audio_extn/audio_extn.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_EXTN_H
+#define AUDIO_EXTN_H
+
+#include <cutils/str_parms.h>
+
+void audio_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+
+void audio_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply);
+
+#ifndef ANC_HEADSET_ENABLED
+#define audio_extn_get_anc_enabled() (0)
+#define audio_extn_should_use_fb_anc() (0)
+#define audio_extn_should_use_handset_anc(in_channels) (0)
+#else
+bool audio_extn_get_anc_enabled(void);
+bool audio_extn_should_use_fb_anc(void);
+bool audio_extn_should_use_handset_anc(int in_channels);
+#endif
+
+#ifndef AFE_PROXY_ENABLED
+#define audio_extn_set_afe_proxy_channel_mixer(adev) (0)
+#else
+int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev);
+#endif
+
+#ifndef USB_HEADSET_ENABLED
+#define audio_extn_usb_init(adev) (0)
+#define audio_extn_usb_deinit() (0)
+#define audio_extn_usb_start_playback(adev) (0)
+#define audio_extn_usb_stop_playback() (0)
+#define audio_extn_usb_start_capture(adev) (0)
+#define audio_extn_usb_stop_capture() (0)
+#define audio_extn_usb_set_proxy_sound_card(sndcard_idx) (0)
+#define audio_extn_usb_is_proxy_inuse() (0)
+#else
+void audio_extn_usb_init(void *adev);
+void audio_extn_usb_deinit();
+void audio_extn_usb_start_playback(void *adev);
+void audio_extn_usb_stop_playback();
+void audio_extn_usb_start_capture(void *adev);
+void audio_extn_usb_stop_capture();
+void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx);
+bool audio_extn_usb_is_proxy_inuse();
+#endif
+
+#ifndef SSR_ENABLED
+#define audio_extn_ssr_init(adev, in) (0)
+#define audio_extn_ssr_deinit() (0)
+#define audio_extn_ssr_update_enabled(adev) (0)
+#define audio_extn_ssr_get_enabled() (0)
+#define audio_extn_ssr_read(stream, buffer, bytes) (0)
+#else
+int32_t audio_extn_ssr_init(struct audio_device *adev,
+ struct stream_in *in);
+int32_t audio_extn_ssr_deinit();
+int32_t audio_extn_ssr_update_enabled(struct audio_device *adev);
+bool audio_extn_ssr_get_enabled();
+int32_t audio_extn_ssr_read(struct audio_stream_in *stream,
+ void *buffer, size_t bytes);
+#endif
+
+#ifndef HW_VARIANTS_ENABLED
+#define hw_info_init(snd_card_name) (0)
+#define hw_info_deinit(hw_info) (0)
+#define hw_info_append_hw_type(hw_info,\
+ snd_device, device_name) (0)
+#else
+void *hw_info_init(const char *snd_card_name);
+void hw_info_deinit(void *hw_info);
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+ char *device_name);
+#endif
+
+#ifndef AUDIO_LISTEN_ENABLED
+
+#define audio_extn_listen_init(adev, snd_card) (0)
+#define audio_extn_listen_deinit(adev) (0)
+#define audio_extn_listen_update_status(uc_info, event) (0)
+#define audio_extn_listen_set_parameters(adev, parms) (0)
+
+#else
+
+enum listen_event_type {
+ LISTEN_EVENT_SND_DEVICE_FREE,
+ LISTEN_EVENT_SND_DEVICE_BUSY
+};
+typedef enum listen_event_type listen_event_type_t;
+
+int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card);
+void audio_extn_listen_deinit(struct audio_device *adev);
+void audio_extn_listen_update_status(snd_device_t snd_device,
+ listen_event_type_t event);
+void audio_extn_listen_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+
+#endif /* AUDIO_LISTEN_ENABLED */
+
+#ifndef AUXPCM_BT_ENABLED
+#define audio_extn_read_xml(adev, MIXER_CARD, MIXER_XML_PATH, \
+ MIXER_XML_PATH_AUXPCM) (-ENOSYS)
+#else
+int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
+ const char* mixer_xml_path,
+ const char* mixer_xml_path_auxpcm);
+#endif /* AUXPCM_BT_ENABLED */
+#ifndef SPKR_PROT_ENABLED
+#define audio_extn_spkr_prot_init(adev) (0)
+#define audio_extn_spkr_prot_start_processing(snd_device) (-EINVAL)
+#define audio_extn_spkr_prot_stop_processing() (0)
+#define audio_extn_spkr_prot_is_enabled() (false)
+#else
+void audio_extn_spkr_prot_init(void *adev);
+int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
+void audio_extn_spkr_prot_stop_processing();
+bool audio_extn_spkr_prot_is_enabled();
+#endif
+
+#ifndef COMPRESS_CAPTURE_ENABLED
+#define audio_extn_compr_cap_init(adev,in) (0)
+#define audio_extn_compr_cap_enabled() (0)
+#define audio_extn_compr_cap_format_supported(format) (0)
+#define audio_extn_compr_cap_usecase_supported(usecase) (0)
+#define audio_extn_compr_cap_get_buffer_size(format) (0)
+#define audio_extn_compr_cap_read(in, buffer, bytes) (0)
+#define audio_extn_compr_cap_deinit() (0)
+#else
+void audio_extn_compr_cap_init(struct audio_device *adev,
+ struct stream_in *in);
+bool audio_extn_compr_cap_enabled();
+bool audio_extn_compr_cap_format_supported(audio_format_t format);
+bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase);
+size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format);
+size_t audio_extn_compr_cap_read(struct stream_in *in,
+ void *buffer, size_t bytes);
+void audio_extn_compr_cap_deinit();
+#endif
+
+#ifndef DS1_DOLBY_DDP_ENABLED
+#define audio_extn_dolby_is_supported_format(format) (0)
+#define audio_extn_dolby_get_snd_codec_id(format) (0)
+#define audio_extn_dolby_set_DMID(adev) (0)
+#else
+bool audio_extn_dolby_is_supported_format(audio_format_t format);
+int audio_extn_dolby_get_snd_codec_id(audio_format_t format);
+int audio_extn_dolby_set_DMID(struct audio_device *adev);
+#endif
+
+#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/compress_capture.c b/hal/audio_extn/compress_capture.c
new file mode 100644
index 0000000..f3db419
--- /dev/null
+++ b/hal/audio_extn/compress_capture.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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_compress"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+#include "sound/compress_params.h"
+#include "sound/compress_offload.h"
+
+#ifdef COMPRESS_CAPTURE_ENABLED
+
+#define COMPRESS_IN_CONFIG_CHANNELS 1
+#define COMPRESS_IN_CONFIG_PERIOD_SIZE 2048
+#define COMPRESS_IN_CONFIG_PERIOD_COUNT 16
+
+
+struct compress_in_module {
+ uint8_t *in_buf;
+};
+
+static struct compress_in_module c_in_mod = {
+ .in_buf = NULL,
+};
+
+
+void audio_extn_compr_cap_init(struct audio_device *adev,
+ struct stream_in *in)
+{
+ in->usecase = USECASE_AUDIO_RECORD_COMPRESS;
+ in->config.channels = COMPRESS_IN_CONFIG_CHANNELS;
+ in->config.period_size = COMPRESS_IN_CONFIG_PERIOD_SIZE;
+ in->config.period_count= COMPRESS_IN_CONFIG_PERIOD_COUNT;
+ in->config.format = AUDIO_FORMAT_AMR_WB;
+ c_in_mod.in_buf = (uint8_t*)calloc(1, in->config.period_size*2);
+}
+
+void audio_extn_compr_cap_deinit()
+{
+ if (c_in_mod.in_buf) {
+ free(c_in_mod.in_buf);
+ c_in_mod.in_buf = NULL;
+ }
+}
+
+bool audio_extn_compr_cap_enabled()
+{
+ char prop_value[PROPERTY_VALUE_MAX] = {0};
+ bool tunnel_encode = false;
+
+ property_get("tunnel.audio.encode",prop_value,"0");
+ if (!strncmp("true", prop_value, sizeof("true")))
+ return true;
+ else
+ return false;
+}
+
+bool audio_extn_compr_cap_format_supported(audio_format_t format)
+{
+ if (format == AUDIO_FORMAT_AMR_WB)
+ return true;
+ else
+ return false;
+}
+
+
+bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase)
+{
+ if (usecase == USECASE_AUDIO_RECORD_COMPRESS)
+ return true;
+ else
+ return false;
+}
+
+
+size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format)
+{
+ if (format == AUDIO_FORMAT_AMR_WB)
+ /*One AMR WB frame is 61 bytes. Return that to the caller.
+ The buffer size is not altered, that is still period size.*/
+ return AMR_WB_FRAMESIZE;
+ else
+ return 0;
+}
+
+size_t audio_extn_compr_cap_read(struct stream_in * in,
+ void *buffer, size_t bytes)
+{
+ int ret;
+ struct snd_compr_audio_info *header;
+ uint32_t c_in_header;
+ uint32_t c_in_buf_size;
+
+ c_in_buf_size = in->config.period_size*2;
+
+ if (in->pcm) {
+ ret = pcm_read(in->pcm, c_in_mod.in_buf, c_in_buf_size);
+ if (ret < 0) {
+ ALOGE("pcm_read() returned failure: %d", ret);
+ return ret;
+ } else {
+ header = (struct snd_compr_audio_info *) c_in_mod.in_buf;
+ c_in_header = sizeof(*header) + header->reserved[0];
+ if (header->frame_size > 0) {
+ if (c_in_header + header->frame_size > c_in_buf_size) {
+ ALOGW("AMR WB read buffer overflow.");
+ header->frame_size =
+ bytes - sizeof(*header) - header->reserved[0];
+ }
+ ALOGV("c_in_buf: %p, data offset: %p, header size: %u,"
+ "reserved[0]: %u frame_size: %d", c_in_mod.in_buf,
+ c_in_mod.in_buf + c_in_header,
+ sizeof(*header), header->reserved[0],
+ header->frame_size);
+ memcpy(buffer, c_in_mod.in_buf + c_in_header, header->frame_size);
+ } else {
+ ALOGE("pcm_read() with zero frame size");
+ ret = -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* COMPRESS_CAPTURE_ENABLED end */
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
new file mode 100644
index 0000000..eeba404
--- /dev/null
+++ b/hal/audio_extn/fm.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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_fm"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#ifdef FM_ENABLED
+#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
+#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume"
+
+static struct pcm_config pcm_config_fm = {
+ .channels = 2,
+ .rate = 48000,
+ .period_size = 256,
+ .period_count = 4,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+struct fm_module {
+ struct pcm *fm_pcm_rx;
+ struct pcm *fm_pcm_tx;
+ bool is_fm_running;
+ float fm_volume;
+};
+
+static struct fm_module fmmod = {
+ .fm_pcm_rx = NULL,
+ .fm_pcm_tx = NULL,
+ .fm_volume = 0,
+ .is_fm_running = 0,
+};
+
+static int32_t fm_set_volume(struct audio_device *adev, float value)
+{
+ int32_t vol, ret = 0;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Internal FM RX Volume";
+
+ ALOGV("%s: entry", __func__);
+ ALOGD("%s: (%f)\n", __func__, value);
+
+ if (value < 0.0) {
+ ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
+ value = 0.0;
+ } else if (value > 1.0) {
+ ALOGW("%s: (%f) Over 1.0, assuming 1.0\n", __func__, value);
+ value = 1.0;
+ }
+ vol = lrint((value * 0x2000) + 0.5);
+ fmmod.fm_volume = value;
+
+ if (!fmmod.is_fm_running) {
+ ALOGV("%s: FM not active, ignoring set_fm_volume call", __func__);
+ return -EIO;
+ }
+
+ ALOGD("%s: Setting FM volume to %d \n", __func__, vol);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ mixer_ctl_set_value(ctl, 0, vol);
+
+ ALOGV("%s: exit", __func__);
+ return ret;
+}
+
+static int32_t fm_stop(struct audio_device *adev)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter", __func__);
+ fmmod.is_fm_running = false;
+
+ /* 1. Close the PCM devices */
+ if (fmmod.fm_pcm_rx) {
+ pcm_close(fmmod.fm_pcm_rx);
+ fmmod.fm_pcm_rx = NULL;
+ }
+ if (fmmod.fm_pcm_tx) {
+ pcm_close(fmmod.fm_pcm_tx);
+ fmmod.fm_pcm_tx = NULL;
+ }
+
+ uc_info = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_FM);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, USECASE_VOICE_CALL);
+ return -EINVAL;
+ }
+
+ /* 2. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device, false);
+ disable_snd_device(adev, uc_info->in_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int32_t fm_start(struct audio_device *adev)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+ int32_t pcm_dev_rx_id, pcm_dev_tx_id;
+
+ ALOGD("%s: enter", __func__);
+
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = USECASE_AUDIO_PLAYBACK_FM;
+ uc_info->type = PCM_PLAYBACK;
+ uc_info->stream.out = adev->primary_output;
+ uc_info->devices = adev->primary_output->devices;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
+
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+ ret = -EIO;
+ goto exit;
+ }
+
+ ALOGV("%s: FM PCM devices (rx: %d tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+ ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_rx_id);
+ fmmod.fm_pcm_rx = pcm_open(SOUND_CARD,
+ pcm_dev_rx_id,
+ PCM_OUT, &pcm_config_fm);
+ if (fmmod.fm_pcm_rx && !pcm_is_ready(fmmod.fm_pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_rx));
+ ret = -EIO;
+ goto exit;
+ }
+
+ ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ fmmod.fm_pcm_tx = pcm_open(SOUND_CARD,
+ pcm_dev_tx_id,
+ PCM_IN, &pcm_config_fm);
+ if (fmmod.fm_pcm_tx && !pcm_is_ready(fmmod.fm_pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(fmmod.fm_pcm_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ pcm_start(fmmod.fm_pcm_rx);
+ pcm_start(fmmod.fm_pcm_tx);
+
+ fmmod.is_fm_running = true;
+ fm_set_volume(adev, fmmod.fm_volume);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return 0;
+
+exit:
+ fm_stop(adev);
+ ALOGE("%s: Problem in FM start: status(%d)", __func__, ret);
+ return ret;
+}
+
+void audio_extn_fm_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ int ret, val;
+ char value[32]={0};
+ float vol =0.0;
+
+ ALOGV("%s: enter", __func__);
+ if(fmmod.is_fm_running) {
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+ value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ if(val > 0)
+ select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+ }
+ }
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HANDLE_FM,
+ value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ ALOGD("%s: FM usecase", __func__);
+ if (val != 0) {
+ if(val & AUDIO_DEVICE_OUT_FM
+ && fmmod.is_fm_running == false)
+ fm_start(adev);
+ else if (!(val & AUDIO_DEVICE_OUT_FM)
+ && fmmod.is_fm_running == true)
+ fm_stop(adev);
+ }
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FM_VOLUME,
+ value, sizeof(value));
+ if (ret >= 0) {
+ if (sscanf(value, "%f", &vol) != 1){
+ ALOGE("%s: error in retrieving fm volume", __func__);
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGD("%s: set_fm_volume usecase", __func__);
+ fm_set_volume(adev, vol);
+ }
+
+exit:
+ ALOGV("%s: exit", __func__);
+}
+#endif /* FM_ENABLED end */
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
new file mode 100644
index 0000000..73824bd
--- /dev/null
+++ b/hal/audio_extn/hfp.c
@@ -0,0 +1,231 @@
+/* hfp.c
+Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
+
+#define LOG_TAG "audio_hw_hfp"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#ifdef HFP_ENABLED
+#define AUDIO_PARAMETER_HFP_ENABLE "hfp_enable"
+
+static int32_t audio_extn_start_hfp(struct audio_device *adev,
+ struct str_parms *parms);
+
+static int32_t audio_extn_stop_hfp(struct audio_device *adev);
+
+struct hfp_module {
+ struct pcm *hfp_sco_rx;
+ struct pcm *hfp_sco_tx;
+ struct pcm *hfp_pcm_rx;
+ struct pcm *hfp_pcm_tx;
+ bool is_hfp_running;
+ int hfp_volume;
+};
+
+static struct hfp_module hfpmod = {
+ .hfp_sco_rx = NULL,
+ .hfp_sco_tx = NULL,
+ .hfp_pcm_rx = NULL,
+ .hfp_pcm_tx = NULL,
+ .hfp_volume = 0,
+ .is_hfp_running = 0,
+};
+static struct pcm_config pcm_config_hfp = {
+ .channels = 1,
+ .rate = 8000,
+ .period_size = 240,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ int ret;
+ char value[32]={0};
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
+ sizeof(value));
+ if (ret >= 0) {
+ if(!strncmp(value,"true",sizeof(value)))
+ ret = audio_extn_start_hfp(adev,parms);
+ else
+ audio_extn_stop_hfp(adev);
+ }
+}
+
+static int32_t audio_extn_start_hfp(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+ int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
+
+ ALOGD("%s: enter", __func__);
+
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = USECASE_AUDIO_HFP_SCO;
+ uc_info->type = PCM_HFP_CALL;
+ uc_info->stream.out = adev->primary_output;
+ uc_info->devices = adev->primary_output->devices;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, USECASE_AUDIO_HFP_SCO);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
+ pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
+ pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
+ pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
+ ret = -EIO;
+ goto exit;
+ }
+
+ ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+ ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_rx_id);
+ hfpmod.hfp_sco_rx = pcm_open(SOUND_CARD,
+ pcm_dev_asm_rx_id,
+ PCM_OUT, &pcm_config_hfp);
+ if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ hfpmod.hfp_pcm_rx = pcm_open(SOUND_CARD,
+ pcm_dev_rx_id,
+ PCM_OUT, &pcm_config_hfp);
+ if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
+ ret = -EIO;
+ goto exit;
+ }
+ hfpmod.hfp_sco_tx = pcm_open(SOUND_CARD,
+ pcm_dev_asm_tx_id,
+ PCM_IN, &pcm_config_hfp);
+ if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ hfpmod.hfp_pcm_tx = pcm_open(SOUND_CARD,
+ pcm_dev_tx_id,
+ PCM_IN, &pcm_config_hfp);
+ if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ pcm_start(hfpmod.hfp_sco_rx);
+ pcm_start(hfpmod.hfp_sco_tx);
+ pcm_start(hfpmod.hfp_pcm_rx);
+ pcm_start(hfpmod.hfp_pcm_tx);
+
+
+ hfpmod.is_hfp_running = true;
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return 0;
+
+exit:
+ audio_extn_stop_hfp(adev);
+ ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int32_t audio_extn_stop_hfp(struct audio_device *adev)
+{
+ int32_t i, ret = 0;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter", __func__);
+ hfpmod.is_hfp_running = false;
+
+ /* 1. Close the PCM devices */
+ if (hfpmod.hfp_sco_rx) {
+ pcm_close(hfpmod.hfp_sco_rx);
+ hfpmod.hfp_sco_rx = NULL;
+ }
+ if (hfpmod.hfp_sco_tx) {
+ pcm_close(hfpmod.hfp_sco_tx);
+ hfpmod.hfp_sco_tx = NULL;
+ }
+ if (hfpmod.hfp_pcm_rx) {
+ pcm_close(hfpmod.hfp_pcm_rx);
+ hfpmod.hfp_pcm_rx = NULL;
+ }
+ if (hfpmod.hfp_pcm_tx) {
+ pcm_close(hfpmod.hfp_pcm_tx);
+ hfpmod.hfp_pcm_tx = NULL;
+ }
+
+ uc_info = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, USECASE_AUDIO_HFP_SCO);
+ return -EINVAL;
+ }
+
+ /* 2. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device, false);
+ disable_snd_device(adev, uc_info->in_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+#endif /*HFP_ENABLED*/
diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c
new file mode 100644
index 0000000..65c0ae6
--- /dev/null
+++ b/hal/audio_extn/listen.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "listen_hal_loader"
+/* #define LOG_NDEBUG 0 */
+/* #define LOG_NDDEBUG 0 */
+#include <stdbool.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#ifdef AUDIO_LISTEN_ENABLED
+#include <listen_types.h>
+#endif
+#include "audio_hw.h"
+#include "audio_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+#ifdef AUDIO_LISTEN_ENABLED
+
+#define LIB_LISTEN_LOADER "/vendor/lib/liblistenhardware.so"
+
+#define LISTEN_LOAD_SYMBOLS(dev, func_p, func_type, symbol) \
+{\
+ dev->func_p = (func_type)dlsym(dev->lib_handle,#symbol);\
+ if (dev->func_p == NULL) {\
+ ALOGE("%s: dlsym error %s for %s",\
+ __func__, dlerror(), #symbol);\
+ free(dev);\
+ dev = NULL;\
+ return -EINVAL;\
+ }\
+}
+
+
+typedef int (*create_listen_hw_t)(unsigned int snd_card,
+ struct audio_route *audio_route);
+typedef void (*destroy_listen_hw_t)();
+
+typedef int (*open_listen_session_t)(struct audio_hw_device *,
+ struct listen_session**);
+
+typedef int (*close_listen_session_t)(struct audio_hw_device *dev,
+ struct listen_session* handle);
+
+typedef int (*set_mad_observer_t)(struct audio_hw_device *dev,
+ listen_callback_t cb_func);
+
+typedef int (*listen_set_parameters_t)(struct audio_hw_device *dev,
+ const char *kv_pairs);
+typedef char* (*get_parameters_t)(const struct audio_hw_device *dev,
+ const char *keys);
+typedef void (*listen_notify_event_t)(event_type_t event_type);
+
+struct listen_audio_device {
+ void *lib_handle;
+ struct audio_device *adev;
+
+ create_listen_hw_t create_listen_hw;
+ destroy_listen_hw_t destroy_listen_hw;
+ open_listen_session_t open_listen_session;
+ close_listen_session_t close_listen_session;
+ set_mad_observer_t set_mad_observer;
+ listen_set_parameters_t listen_set_parameters;
+ get_parameters_t get_parameters;
+ listen_notify_event_t notify_event;
+};
+
+static struct listen_audio_device *listen_dev;
+
+void audio_extn_listen_update_status(snd_device_t snd_device,
+ listen_event_type_t event)
+{
+ if (!platform_listen_update_status(snd_device)) {
+ ALOGV("%s(): no need to notify listen. device = %s. Event = %u",
+ __func__, platform_get_snd_device_name(snd_device), event);
+ return;
+ }
+
+ if (listen_dev) {
+ ALOGI("%s(): %s listen. current active device = %s. Event = %u",
+ __func__,
+ (event == LISTEN_EVENT_SND_DEVICE_BUSY) ? "stop" : "start",
+ platform_get_snd_device_name(snd_device), event);
+
+ if (event == LISTEN_EVENT_SND_DEVICE_FREE)
+ listen_dev->notify_event(AUDIO_CAPTURE_INACTIVE);
+ else if (event == LISTEN_EVENT_SND_DEVICE_BUSY)
+ listen_dev->notify_event(AUDIO_CAPTURE_ACTIVE);
+ }
+}
+
+void audio_extn_listen_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ return;
+}
+
+int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card)
+{
+ int ret;
+ void *lib_handle;
+
+ ALOGI("%s: Enter", __func__);
+
+ lib_handle = dlopen(LIB_LISTEN_LOADER, RTLD_NOW);
+
+ if (lib_handle == NULL) {
+ ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, LIB_LISTEN_LOADER,
+ dlerror());
+ return -EINVAL;
+ } else {
+ ALOGI("%s: DLOPEN successful for %s", __func__, LIB_LISTEN_LOADER);
+
+ listen_dev = (struct listen_audio_device*)
+ calloc(1, sizeof(struct listen_audio_device));
+
+ listen_dev->lib_handle = lib_handle;
+ listen_dev->adev = adev;
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, create_listen_hw,
+ create_listen_hw_t, create_listen_hw);
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, destroy_listen_hw,
+ destroy_listen_hw_t, destroy_listen_hw);
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, open_listen_session,
+ open_listen_session_t, open_listen_session);
+
+ adev->device.open_listen_session = listen_dev->open_listen_session;
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, close_listen_session,
+ close_listen_session_t, close_listen_session);
+
+ adev->device.close_listen_session = listen_dev->close_listen_session;
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, set_mad_observer,
+ set_mad_observer_t, set_mad_observer);
+
+ adev->device.set_mad_observer = listen_dev->set_mad_observer;
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, listen_set_parameters,
+ listen_set_parameters_t, listen_hw_set_parameters);
+
+ adev->device.listen_set_parameters = listen_dev->listen_set_parameters;
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, get_parameters,
+ get_parameters_t, listen_hw_get_parameters);
+
+ LISTEN_LOAD_SYMBOLS(listen_dev, notify_event,
+ listen_notify_event_t, listen_hw_notify_event);
+
+ listen_dev->create_listen_hw(snd_card, adev->audio_route);
+ }
+ return 0;
+}
+
+void audio_extn_listen_deinit(struct audio_device *adev)
+{
+ ALOGI("%s: Enter", __func__);
+
+ if (listen_dev && (listen_dev->adev == adev) && listen_dev->lib_handle) {
+ listen_dev->destroy_listen_hw();
+ dlclose(listen_dev->lib_handle);
+ free(listen_dev);
+ listen_dev = NULL;
+ }
+}
+
+#endif /* AUDIO_LISTEN_ENABLED */
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
new file mode 100644
index 0000000..0fc790a
--- /dev/null
+++ b/hal/audio_extn/spkr_protection.c
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "audio_hw_spkr_prot"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <math.h>
+#include <cutils/properties.h>
+#include "audio_extn.h"
+#include <linux/msm_audio_acdb.h>
+
+#ifdef SPKR_PROT_ENABLED
+
+/*Range of spkr temparatures -30C to 80C*/
+#define MIN_SPKR_TEMP_Q6 (-30 * (1 << 6))
+#define MAX_SPKR_TEMP_Q6 (80 * (1 << 6))
+
+/*Set safe temp value to 40C*/
+#define SAFE_SPKR_TEMP 40
+#define SAFE_SPKR_TEMP_Q6 (SAFE_SPKR_TEMP * (1 << 6))
+
+/*Range of resistance values 2ohms to 40 ohms*/
+#define MIN_RESISTANCE_SPKR_Q24 (2 * (1 << 24))
+#define MAX_RESISTANCE_SPKR_Q24 (40 * (1 << 24))
+
+/*Path where the calibration file will be stored*/
+#define CALIB_FILE "/data/misc/audio/audio.cal"
+
+/*Time between retries for calibartion or intial wait time
+ after boot up*/
+#define WAIT_TIME_SPKR_CALIB (60 * 1000 * 1000)
+
+#define MIN_SPKR_IDLE_SEC (60 * 30)
+
+/*Once calibration is started sleep for 1 sec to allow
+ the calibration to kick off*/
+#define SLEEP_AFTER_CALIB_START (3000)
+
+/*If calibration is in progress wait for 200 msec before querying
+ for status again*/
+#define WAIT_FOR_GET_CALIB_STATUS (200 * 1000)
+
+/*Speaker states*/
+#define SPKR_NOT_CALIBRATED -1
+#define SPKR_CALIBRATED 1
+
+/*Speaker processing state*/
+#define SPKR_PROCESSING_IN_PROGRESS 1
+#define SPKR_PROCESSING_IN_IDLE 0
+
+/*Modes of Speaker Protection*/
+enum speaker_protection_mode {
+ SPKR_PROTECTION_DISABLED = -1,
+ SPKR_PROTECTION_MODE_PROCESSING = 0,
+ SPKR_PROTECTION_MODE_CALIBRATE = 1,
+};
+
+struct speaker_prot_session {
+ int spkr_prot_mode;
+ int spkr_processing_state;
+ int thermal_client_handle;
+ pthread_mutex_t mutex_spkr_prot;
+ pthread_t spkr_calibration_thread;
+ pthread_mutex_t spkr_prot_thermalsync_mutex;
+ pthread_cond_t spkr_prot_thermalsync;
+ int cancel_spkr_calib;
+ pthread_cond_t spkr_calib_cancel;
+ pthread_mutex_t spkr_calib_cancelack_mutex;
+ pthread_cond_t spkr_calibcancel_ack;
+ pthread_t speaker_prot_threadid;
+ void *thermal_handle;
+ void *adev_handle;
+ int spkr_prot_t0;
+ struct pcm *pcm_rx;
+ struct pcm *pcm_tx;
+ int (*client_register_callback)
+ (char *client_name, int (*callback)(int, void *, void *), void *data);
+ void (*thermal_client_unregister_callback)(int handle);
+ int (*thermal_client_request)(char *client_name, int req_data);
+ bool spkr_prot_enable;
+ bool spkr_in_use;
+ struct timespec spkr_last_time_used;
+};
+
+static struct pcm_config pcm_config_skr_prot = {
+ .channels = 2,
+ .rate = 48000,
+ .period_size = 256,
+ .period_count = 4,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+static struct speaker_prot_session handle;
+
+static void spkr_prot_set_spkrstatus(bool enable)
+{
+ struct timespec ts;
+ if (enable)
+ handle.spkr_in_use = true;
+ else {
+ handle.spkr_in_use = false;
+ clock_gettime(CLOCK_MONOTONIC, &handle.spkr_last_time_used);
+ }
+}
+
+static void spkr_prot_calib_cancel(void *adev)
+{
+ pthread_t threadid;
+ struct audio_usecase *uc_info;
+ int count = 0;
+ threadid = pthread_self();
+ ALOGV("%s: Entry", __func__);
+ if (pthread_equal(handle.speaker_prot_threadid, threadid) || !adev) {
+ ALOGE("%s: Invalid params", __func__);
+ return;
+ }
+ uc_info = get_usecase_from_list(adev, USECASE_AUDIO_SPKR_CALIB_RX);
+ if (uc_info) {
+ pthread_mutex_lock(&handle.mutex_spkr_prot);
+ pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex);
+ handle.cancel_spkr_calib = 1;
+ pthread_cond_signal(&handle.spkr_calib_cancel);
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ pthread_cond_wait(&handle.spkr_calibcancel_ack,
+ &handle.spkr_calib_cancelack_mutex);
+ pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex);
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ }
+ ALOGV("%s: Exit", __func__);
+}
+
+static bool is_speaker_in_use(unsigned long *sec)
+{
+ struct timespec temp;
+ if (!sec) {
+ ALOGE("%s: Invalid params", __func__);
+ return true;
+ }
+ if (handle.spkr_in_use) {
+ *sec = 0;
+ return true;
+ } else {
+ clock_gettime(CLOCK_MONOTONIC, &temp);
+ *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
+ return false;
+ }
+}
+
+
+static int spkr_calibrate(int t0)
+{
+ struct audio_device *adev = handle.adev_handle;
+ struct msm_spk_prot_cfg protCfg;
+ struct msm_spk_prot_status status;
+ bool cleanup = false, disable_rx = false, disable_tx = false;
+ int acdb_fd = -1;
+ struct audio_usecase *uc_info_rx = NULL, *uc_info_tx = NULL;
+ int32_t pcm_dev_rx_id = -1, pcm_dev_tx_id = -1;
+ struct timespec ts;
+
+ if (!adev) {
+ ALOGE("%s: Invalid params", __func__);
+ return -EINVAL;
+ }
+ if (!list_empty(&adev->usecase_list)) {
+ ALOGD("%s: Usecase present retry speaker protection", __func__);
+ return -EAGAIN;
+ }
+ acdb_fd = open("/dev/msm_acdb",O_RDWR | O_NONBLOCK);
+ if (acdb_fd < 0) {
+ ALOGE("%s: spkr_prot_thread open msm_acdb failed", __func__);
+ return -ENODEV;
+ } else {
+ protCfg.mode = MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS;
+ protCfg.t0 = t0;
+ if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) {
+ ALOGE("%s: spkr_prot_thread set failed AUDIO_SET_SPEAKER_PROT",
+ __func__);
+ status.status = -ENODEV;
+ goto exit;
+ }
+ }
+ uc_info_rx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info_rx->id = USECASE_AUDIO_SPKR_CALIB_RX;
+ uc_info_rx->type = PCM_PLAYBACK;
+ uc_info_rx->in_snd_device = SND_DEVICE_NONE;
+ uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED;
+ pthread_mutex_lock(&adev->lock);
+ disable_rx = true;
+ enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED, true);
+ enable_audio_route(adev, uc_info_rx, true);
+ pthread_mutex_unlock(&adev->lock);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info_rx->id, PCM_PLAYBACK);
+ ALOGV("%s: pcm device id %d", __func__, pcm_dev_rx_id);
+ if (pcm_dev_rx_id < 0) {
+ ALOGE("%s: Invalid pcm device for usecase (%d)",
+ __func__, uc_info_rx->id);
+ status.status = -ENODEV;
+ goto exit;
+ }
+ handle.pcm_rx = handle.pcm_tx = NULL;
+ handle.pcm_rx = pcm_open(SOUND_CARD, pcm_dev_rx_id,
+ PCM_OUT, &pcm_config_skr_prot);
+ if (handle.pcm_rx && !pcm_is_ready(handle.pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_rx));
+ status.status = -EIO;
+ goto exit;
+ }
+ uc_info_tx = (struct audio_usecase *)
+ calloc(1, sizeof(struct audio_usecase));
+ uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX;
+ uc_info_tx->type = PCM_CAPTURE;
+ uc_info_tx->in_snd_device = SND_DEVICE_NONE;
+ uc_info_tx->out_snd_device = SND_DEVICE_NONE;
+
+ pthread_mutex_lock(&adev->lock);
+ disable_tx = true;
+ enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true);
+ enable_audio_route(adev, uc_info_tx, true);
+ pthread_mutex_unlock(&adev->lock);
+
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
+ if (pcm_dev_tx_id < 0) {
+ ALOGE("%s: Invalid pcm device for usecase (%d)",
+ __func__, uc_info_tx->id);
+ status.status = -ENODEV;
+ goto exit;
+ }
+ handle.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id,
+ PCM_IN, &pcm_config_skr_prot);
+ if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx));
+ status.status = -EIO;
+ goto exit;
+ }
+ if (pcm_start(handle.pcm_rx) < 0) {
+ ALOGE("%s: pcm start for RX failed", __func__);
+ status.status = -EINVAL;
+ goto exit;
+ }
+ if (pcm_start(handle.pcm_tx) < 0) {
+ ALOGE("%s: pcm start for TX failed", __func__);
+ status.status = -EINVAL;
+ goto exit;
+ }
+ cleanup = true;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += (SLEEP_AFTER_CALIB_START/1000);
+ ts.tv_nsec = 0;
+ (void)pthread_cond_timedwait(&handle.spkr_calib_cancel,
+ &handle.mutex_spkr_prot, &ts);
+ ALOGD("%s: Speaker calibration done", __func__);
+ cleanup = true;
+ pthread_mutex_lock(&handle.spkr_calib_cancelack_mutex);
+ if (handle.cancel_spkr_calib) {
+ status.status = -EAGAIN;
+ goto exit;
+ }
+ if (acdb_fd > 0) {
+ status.status = -EINVAL;
+ while (!ioctl(acdb_fd, AUDIO_GET_SPEAKER_PROT,&status)) {
+ /*sleep for 200 ms to check for status check*/
+ if (!status.status) {
+ ALOGD("%s: spkr_prot_thread calib Success R0 %d",
+ __func__, status.r0);
+ FILE *fp;
+ fp = fopen(CALIB_FILE,"wb");
+ if (!fp) {
+ ALOGE("%s: spkr_prot_thread File open failed %s",
+ __func__, strerror(errno));
+ status.status = -ENODEV;
+ } else {
+ fwrite(&status.r0, sizeof(status.r0),1,fp);
+ fwrite(&protCfg.t0, sizeof(protCfg.t0),1,fp);
+ fclose(fp);
+ }
+ break;
+ } else if (status.status == -EAGAIN) {
+ ALOGD("%s: spkr_prot_thread try again", __func__);
+ usleep(WAIT_FOR_GET_CALIB_STATUS);
+ } else {
+ ALOGE("%s: spkr_prot_thread get failed status %d",
+ __func__, status.status);
+ break;
+ }
+ }
+exit:
+ if (handle.pcm_rx)
+ pcm_close(handle.pcm_rx);
+ handle.pcm_rx = NULL;
+ if (handle.pcm_tx)
+ pcm_close(handle.pcm_tx);
+ handle.pcm_tx = NULL;
+ pthread_mutex_lock(&adev->lock);
+ if (disable_rx) {
+ disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED, true);
+ disable_audio_route(adev, uc_info_rx, true);
+ }
+ if (disable_tx) {
+ disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true);
+ disable_audio_route(adev, uc_info_tx, true);
+ }
+ pthread_mutex_unlock(&adev->lock);
+
+ if (!status.status) {
+ protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
+ protCfg.r0 = status.r0;
+ if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg))
+ ALOGE("%s: spkr_prot_thread disable calib mode", __func__);
+ else
+ handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED;
+ } else {
+ protCfg.mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+ handle.spkr_prot_mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+ if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg))
+ ALOGE("%s: spkr_prot_thread disable calib mode failed", __func__);
+ }
+ if (acdb_fd > 0)
+ close(acdb_fd);
+ if (uc_info_rx) free(uc_info_rx);
+ if (uc_info_tx) free(uc_info_tx);
+ if (cleanup) {
+ if (handle.cancel_spkr_calib)
+ pthread_cond_signal(&handle.spkr_calibcancel_ack);
+ handle.cancel_spkr_calib = 0;
+ pthread_mutex_unlock(&handle.spkr_calib_cancelack_mutex);
+ }
+ }
+ return status.status;
+}
+
+static void* spkr_calibration_thread(void *context)
+{
+ unsigned long sec = 0;
+ int t0;
+ bool goahead = false;
+ struct msm_spk_prot_cfg protCfg;
+ FILE *fp;
+ int acdb_fd;
+ struct audio_device *adev = handle.adev_handle;
+
+ handle.speaker_prot_threadid = pthread_self();
+ ALOGD("spkr_prot_thread enable prot Entry");
+ acdb_fd = open("/dev/msm_acdb",O_RDWR | O_NONBLOCK);
+ if (acdb_fd > 0) {
+ /*Set processing mode with t0/r0*/
+ protCfg.mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+ if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) {
+ ALOGE("%s: spkr_prot_thread enable prot failed", __func__);
+ handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+ close(acdb_fd);
+ } else
+ handle.spkr_prot_mode = MSM_SPKR_PROT_NOT_CALIBRATED;
+ } else {
+ handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+ ALOGE("%s: Failed to open acdb node", __func__);
+ }
+ if (handle.spkr_prot_mode == MSM_SPKR_PROT_DISABLED) {
+ ALOGD("%s: Speaker protection disabled", __func__);
+ pthread_exit(0);
+ return NULL;
+ }
+
+ fp = fopen(CALIB_FILE,"rb");
+ if (fp) {
+ fread(&protCfg.r0,sizeof(protCfg.r0),1,fp);
+ ALOGD("%s: spkr_prot_thread r0 value %d", __func__, protCfg.r0);
+ fread(&protCfg.t0, sizeof(protCfg.t0), 1, fp);
+ ALOGD("%s: spkr_prot_thread t0 value %d", __func__, protCfg.t0);
+ fclose(fp);
+ /*Valid tempature range: -30C to 80C(in q6 format)
+ Valid Resistance range: 2 ohms to 40 ohms(in q24 format)*/
+ if (protCfg.t0 > MIN_SPKR_TEMP_Q6 &&
+ protCfg.t0 < MAX_SPKR_TEMP_Q6 &&
+ protCfg.r0 >= MIN_RESISTANCE_SPKR_Q24
+ && protCfg.r0 < MAX_RESISTANCE_SPKR_Q24) {
+ ALOGD("%s: Spkr calibrated", __func__);
+ protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
+ if (ioctl(acdb_fd, AUDIO_SET_SPEAKER_PROT, &protCfg)) {
+ ALOGE("%s: enable prot failed", __func__);
+ handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+ } else
+ handle.spkr_prot_mode = MSM_SPKR_PROT_CALIBRATED;
+ close(acdb_fd);
+ pthread_exit(0);
+ return NULL;
+ }
+ close(acdb_fd);
+ }
+
+ while (1) {
+ ALOGV("%s: start calibration", __func__);
+ if (!handle.thermal_client_request("spkr",1)) {
+ ALOGD("%s: wait for callback from thermal daemon", __func__);
+ pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex);
+ pthread_cond_wait(&handle.spkr_prot_thermalsync,
+ &handle.spkr_prot_thermalsync_mutex);
+ /*Convert temp into q6 format*/
+ t0 = (handle.spkr_prot_t0 * (1 << 6));
+ pthread_mutex_unlock(&handle.spkr_prot_thermalsync_mutex);
+ if (t0 < MIN_SPKR_TEMP_Q6 || t0 > MAX_SPKR_TEMP_Q6) {
+ ALOGE("%s: Calibration temparature error %d", __func__,
+ handle.spkr_prot_t0);
+ continue;
+ }
+ ALOGD("%s: Request t0 success value %d", __func__,
+ handle.spkr_prot_t0);
+ } else {
+ ALOGE("%s: Request t0 failed", __func__);
+ /*Assume safe value for temparature*/
+ t0 = SAFE_SPKR_TEMP_Q6;
+ }
+ goahead = false;
+ pthread_mutex_lock(&handle.mutex_spkr_prot);
+ if (is_speaker_in_use(&sec)) {
+ ALOGD("%s: Speaker in use retry calibration", __func__);
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ continue;
+ } else {
+ ALOGD("%s: speaker idle %ld", __func__, sec);
+ if (sec < MIN_SPKR_IDLE_SEC) {
+ ALOGD("%s: speaker idle is less retry", __func__);
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ continue;
+ }
+ goahead = true;
+ }
+ if (!list_empty(&adev->usecase_list))
+ goahead = false;
+ if (goahead) {
+ int status;
+ status = spkr_calibrate(t0);
+ if (status == -EAGAIN) {
+ ALOGE("%s: failed to calibrate try again %s",
+ __func__, strerror(status));
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ continue;
+ } else {
+ ALOGE("%s: calibrate status %s", __func__, strerror(status));
+ }
+ ALOGD("%s: spkr_prot_thread end calibration", __func__);
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ break;
+ }
+ }
+ if (handle.thermal_client_handle)
+ handle.thermal_client_unregister_callback(handle.thermal_client_handle);
+ handle.thermal_client_handle = 0;
+ if (handle.thermal_handle)
+ dlclose(handle.thermal_handle);
+ handle.thermal_handle = NULL;
+ pthread_exit(0);
+ return NULL;
+}
+
+static int thermal_client_callback(int temp, void *user_data, void *reserved)
+{
+ pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex);
+ ALOGD("%s: spkr_prot set t0 %d and signal", __func__, temp);
+ if (handle.spkr_prot_mode == MSM_SPKR_PROT_NOT_CALIBRATED)
+ handle.spkr_prot_t0 = temp;
+ pthread_cond_signal(&handle.spkr_prot_thermalsync);
+ pthread_mutex_unlock(&handle.spkr_prot_thermalsync_mutex);
+ return 0;
+}
+
+void audio_extn_spkr_prot_init(void *adev)
+{
+ char value[PROPERTY_VALUE_MAX];
+ ALOGD("%s: Initialize speaker protection module", __func__);
+ memset(&handle, 0, sizeof(handle));
+ if (!adev) {
+ ALOGE("%s: Invalid params", __func__);
+ return;
+ }
+ property_get("persist.speaker.prot.enable", value, "");
+ handle.spkr_prot_enable = false;
+ if (!strncmp("true", value, 4))
+ handle.spkr_prot_enable = true;
+ if (!handle.spkr_prot_enable) {
+ ALOGD("%s: Speaker protection disabled", __func__);
+ return;
+ }
+ handle.adev_handle = adev;
+ handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
+ handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
+ handle.spkr_prot_t0 = -1;
+ pthread_cond_init(&handle.spkr_prot_thermalsync, NULL);
+ pthread_cond_init(&handle.spkr_calib_cancel, NULL);
+ pthread_cond_init(&handle.spkr_calibcancel_ack, NULL);
+ pthread_mutex_init(&handle.mutex_spkr_prot, NULL);
+ pthread_mutex_init(&handle.spkr_calib_cancelack_mutex, NULL);
+ pthread_mutex_init(&handle.spkr_prot_thermalsync_mutex, NULL);
+ handle.thermal_handle = dlopen("/vendor/lib/libthermalclient.so",
+ RTLD_NOW);
+ if (!handle.thermal_handle) {
+ ALOGE("%s: DLOPEN for thermal client failed", __func__);
+ } else {
+ /*Query callback function symbol*/
+ handle.client_register_callback =
+ (int (*)(char *, int (*)(int, void *, void *),void *))
+ dlsym(handle.thermal_handle, "thermal_client_register_callback");
+ handle.thermal_client_unregister_callback =
+ (void (*)(int) )
+ dlsym(handle.thermal_handle, "thermal_client_unregister_callback");
+ if (!handle.client_register_callback ||
+ !handle.thermal_client_unregister_callback) {
+ ALOGE("%s: DLSYM thermal_client_register_callback failed", __func__);
+ } else {
+ /*Register callback function*/
+ handle.thermal_client_handle =
+ handle.client_register_callback("spkr", thermal_client_callback, NULL);
+ if (!handle.thermal_client_handle) {
+ ALOGE("%s: client_register_callback failed", __func__);
+ } else {
+ ALOGD("%s: spkr_prot client_register_callback success", __func__);
+ handle.thermal_client_request = (int (*)(char *, int))
+ dlsym(handle.thermal_handle, "thermal_client_request");
+ }
+ }
+ }
+ if (handle.thermal_client_request) {
+ ALOGD("%s: Create calibration thread", __func__);
+ (void)pthread_create(&handle.spkr_calibration_thread,
+ (const pthread_attr_t *) NULL, spkr_calibration_thread, &handle);
+ } else {
+ ALOGE("%s: thermal_client_request failed", __func__);
+ if (handle.thermal_client_handle)
+ handle.thermal_client_unregister_callback(handle.thermal_client_handle);
+ if (handle.thermal_handle)
+ dlclose(handle.thermal_handle);
+ handle.thermal_handle = NULL;
+ handle.spkr_prot_enable = false;
+ }
+}
+
+int audio_extn_spkr_prot_start_processing(snd_device_t snd_device)
+{
+ struct audio_usecase uc_info_tx;
+ struct audio_device *adev = handle.adev_handle;
+ int32_t pcm_dev_tx_id = -1, ret = 0;
+
+ ALOGV("%s: Entry", __func__);
+ /* cancel speaker calibration */
+ if (!adev) {
+ ALOGE("%s: Invalid params", __func__);
+ return -EINVAL;
+ }
+ spkr_prot_calib_cancel(adev);
+ spkr_prot_set_spkrstatus(true);
+ if (platform_send_audio_calibration(adev->platform,
+ SND_DEVICE_OUT_SPEAKER_PROTECTED) < 0) {
+ adev->snd_dev_ref_cnt[snd_device]--;
+ return -EINVAL;
+ }
+ ALOGV("%s: snd_device(%d: %s)", __func__, snd_device,
+ platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED));
+ audio_route_apply_path(adev->audio_route,
+ platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED));
+
+ pthread_mutex_lock(&handle.mutex_spkr_prot);
+ if (handle.spkr_processing_state == SPKR_PROCESSING_IN_IDLE) {
+ memset(&uc_info_tx, 0 , sizeof(uc_info_tx));
+ uc_info_tx.id = USECASE_AUDIO_SPKR_CALIB_TX;
+ uc_info_tx.type = PCM_CAPTURE;
+ uc_info_tx.in_snd_device = SND_DEVICE_NONE;
+ uc_info_tx.out_snd_device = SND_DEVICE_NONE;
+ handle.pcm_tx = NULL;
+
+ enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true);
+ enable_audio_route(adev, &uc_info_tx, true);
+
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx.id, PCM_CAPTURE);
+ if (pcm_dev_tx_id < 0) {
+ ALOGE("%s: Invalid pcm device for usecase (%d)",
+ __func__, uc_info_tx.id);
+ ret = -ENODEV;
+ goto exit;
+ }
+ handle.pcm_tx = pcm_open(SOUND_CARD, pcm_dev_tx_id,
+ PCM_IN, &pcm_config_skr_prot);
+ if (handle.pcm_tx && !pcm_is_ready(handle.pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(handle.pcm_tx));
+ ret = -EIO;
+ goto exit;
+ }
+ if (pcm_start(handle.pcm_tx) < 0) {
+ ALOGE("%s: pcm start for TX failed", __func__);
+ ret = -EINVAL;
+ }
+ }
+exit:
+ if (ret) {
+ if (handle.pcm_tx)
+ pcm_close(handle.pcm_tx);
+ handle.pcm_tx = NULL;
+ disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true);
+ disable_audio_route(adev, &uc_info_tx, true);
+ } else
+ handle.spkr_processing_state = SPKR_PROCESSING_IN_PROGRESS;
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ ALOGV("%s: Exit", __func__);
+ return ret;
+}
+
+void audio_extn_spkr_prot_stop_processing()
+{
+ struct audio_usecase uc_info_tx;
+ struct audio_device *adev = handle.adev_handle;
+ ALOGV("%s: Entry", __func__);
+ spkr_prot_set_spkrstatus(false);
+ pthread_mutex_lock(&handle.mutex_spkr_prot);
+ if (adev && handle.spkr_processing_state == SPKR_PROCESSING_IN_PROGRESS) {
+ memset(&uc_info_tx, 0 , sizeof(uc_info_tx));
+ uc_info_tx.id = USECASE_AUDIO_SPKR_CALIB_TX;
+ uc_info_tx.type = PCM_CAPTURE;
+ uc_info_tx.in_snd_device = SND_DEVICE_NONE;
+ uc_info_tx.out_snd_device = SND_DEVICE_NONE;
+ if (handle.pcm_tx)
+ pcm_close(handle.pcm_tx);
+ handle.pcm_tx = NULL;
+ disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK, true);
+ disable_audio_route(adev, &uc_info_tx, true);
+ }
+ handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
+ pthread_mutex_unlock(&handle.mutex_spkr_prot);
+ audio_route_reset_path(adev->audio_route,
+ platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_PROTECTED));
+ ALOGV("%s: Exit", __func__);
+}
+
+bool audio_extn_spkr_prot_is_enabled()
+{
+ return handle.spkr_prot_enable;
+}
+#endif /*SPKR_PROT_ENABLED*/
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
new file mode 100644
index 0000000..efd92ea
--- /dev/null
+++ b/hal/audio_extn/ssr.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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_ssr"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "surround_filters_interface.h"
+
+#ifdef SSR_ENABLED
+#define COEFF_ARRAY_SIZE 4
+#define FILT_SIZE ((512+1)* 6) /* # ((FFT bins)/2+1)*numOutputs */
+#define SSR_FRAME_SIZE 512
+#define SSR_INPUT_FRAME_SIZE (SSR_FRAME_SIZE * 4)
+#define SSR_OUTPUT_FRAME_SIZE (SSR_FRAME_SIZE * 6)
+#define SSR_CHANNEL_COUNT 4
+#define SSR_PERIOD_SIZE 256
+#define SSR_PERIOD_COUNT 8
+
+#define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm"
+#define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm"
+#define SURROUND_FILE_3R "/system/etc/surround_sound/filter3r.pcm"
+#define SURROUND_FILE_4R "/system/etc/surround_sound/filter4r.pcm"
+
+#define SURROUND_FILE_1I "/system/etc/surround_sound/filter1i.pcm"
+#define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm"
+#define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm"
+#define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm"
+#define AUDIO_PARAMETER_KEY_SSR "ssr"
+#define LIB_SURROUND_PROC "libsurround_proc.so"
+
+typedef int (*surround_filters_init_t)(void *, int, int, Word16 **,
+ Word16 **, int, int, int, Profiler *);
+typedef void (*surround_filters_release_t)(void *);
+typedef int (*surround_filters_set_channel_map_t)(void *, const int *);
+typedef void (*surround_filters_intl_process_t)(void *, Word16 *, Word16 *);
+
+struct ssr_module {
+ FILE *fp_4ch;
+ FILE *fp_6ch;
+ int16_t **real_coeffs;
+ int16_t **imag_coeffs;
+ void *surround_obj;
+
+ int16_t *surround_input_buffer;
+ int16_t *surround_output_buffer;
+ int surround_input_bufferIdx;
+ int surround_output_bufferIdx;
+ bool is_ssr_enabled;
+
+ void *surround_filters_handle;
+ surround_filters_init_t surround_filters_init;
+ surround_filters_release_t surround_filters_release;
+ surround_filters_set_channel_map_t surround_filters_set_channel_map;
+ surround_filters_intl_process_t surround_filters_intl_process;
+};
+
+static int32_t ssr_init_surround_sound_lib(unsigned long buffersize);
+static int32_t ssr_read_coeffs_from_file();
+
+static struct ssr_module ssrmod = {
+ .fp_4ch = NULL,
+ .fp_6ch= NULL,
+ .real_coeffs = NULL,
+ .imag_coeffs = NULL,
+ .surround_obj = NULL,
+ .surround_output_buffer = NULL,
+ .surround_input_buffer = NULL,
+ .surround_output_bufferIdx = 0,
+ .surround_input_bufferIdx= 0,
+ .is_ssr_enabled = 0,
+
+ .surround_filters_handle = NULL,
+ .surround_filters_init = NULL,
+ .surround_filters_release = NULL,
+ .surround_filters_set_channel_map = NULL,
+ .surround_filters_intl_process = NULL,
+};
+
+/* Use AAC/DTS channel mapping as default channel mapping: C,FL,FR,Ls,Rs,LFE */
+static const int chan_map[] = { 1, 2, 4, 3, 0, 5};
+
+/* Rotine to read coeffs from File and updates real and imaginary
+ coeff array member variable */
+static int32_t ssr_read_coeffs_from_file()
+{
+ FILE *flt1r;
+ FILE *flt2r;
+ FILE *flt3r;
+ FILE *flt4r;
+ FILE *flt1i;
+ FILE *flt2i;
+ FILE *flt3i;
+ FILE *flt4i;
+ int i;
+
+ if ( (flt1r = fopen(SURROUND_FILE_1R, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter co-efficient "
+ "file %s", __func__, SURROUND_FILE_1R);
+ return -EINVAL;
+ }
+
+ if ( (flt2r = fopen(SURROUND_FILE_2R, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_2R);
+ return -EINVAL;
+ }
+
+ if ( (flt3r = fopen(SURROUND_FILE_3R, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_3R);
+ return -EINVAL;
+ }
+
+ if ( (flt4r = fopen(SURROUND_FILE_4R, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_4R);
+ return -EINVAL;
+ }
+
+ if ( (flt1i = fopen(SURROUND_FILE_1I, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_1I);
+ return -EINVAL;
+ }
+
+ if ( (flt2i = fopen(SURROUND_FILE_2I, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_2I);
+ return -EINVAL;
+ }
+
+ if ( (flt3i = fopen(SURROUND_FILE_3I, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_3I);
+ return -EINVAL;
+ }
+
+ if ( (flt4i = fopen(SURROUND_FILE_4I, "rb")) == NULL ) {
+ ALOGE("%s: Cannot open filter "
+ "co-efficient file %s", __func__, SURROUND_FILE_4I);
+ return -EINVAL;
+ }
+ ALOGV("%s: readCoeffsFromFile all filter "
+ "files opened", __func__);
+
+ for (i=0; i<COEFF_ARRAY_SIZE; i++) {
+ ssrmod.real_coeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16));
+ }
+ for (i=0; i<COEFF_ARRAY_SIZE; i++) {
+ ssrmod.imag_coeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16));
+ }
+
+ /* Read real co-efficients */
+ if (NULL != ssrmod.real_coeffs[0]) {
+ fread(ssrmod.real_coeffs[0], sizeof(int16), FILT_SIZE, flt1r);
+ }
+ if (NULL != ssrmod.real_coeffs[0]) {
+ fread(ssrmod.real_coeffs[1], sizeof(int16), FILT_SIZE, flt2r);
+ }
+ if (NULL != ssrmod.real_coeffs[0]) {
+ fread(ssrmod.real_coeffs[2], sizeof(int16), FILT_SIZE, flt3r);
+ }
+ if (NULL != ssrmod.real_coeffs[0]) {
+ fread(ssrmod.real_coeffs[3], sizeof(int16), FILT_SIZE, flt4r);
+ }
+
+ /* read imaginary co-efficients */
+ if (NULL != ssrmod.imag_coeffs[0]) {
+ fread(ssrmod.imag_coeffs[0], sizeof(int16), FILT_SIZE, flt1i);
+ }
+ if (NULL != ssrmod.imag_coeffs[0]) {
+ fread(ssrmod.imag_coeffs[1], sizeof(int16), FILT_SIZE, flt2i);
+ }
+ if (NULL != ssrmod.imag_coeffs[0]) {
+ fread(ssrmod.imag_coeffs[2], sizeof(int16), FILT_SIZE, flt3i);
+ }
+ if (NULL != ssrmod.imag_coeffs[0]) {
+ fread(ssrmod.imag_coeffs[3], sizeof(int16), FILT_SIZE, flt4i);
+ }
+
+ fclose(flt1r);
+ fclose(flt2r);
+ fclose(flt3r);
+ fclose(flt4r);
+ fclose(flt1i);
+ fclose(flt2i);
+ fclose(flt3i);
+ fclose(flt4i);
+
+ return 0;
+}
+
+static int32_t ssr_init_surround_sound_lib(unsigned long buffersize)
+{
+ /* sub_woofer channel assignment: default as first
+ microphone input channel */
+ int sub_woofer = 0;
+ /* frequency upper bound for sub_woofer:
+ frequency=(low_freq-1)/FFT_SIZE*samplingRate, default as 4 */
+ int low_freq = 4;
+ /* frequency upper bound for spatial processing:
+ frequency=(high_freq-1)/FFT_SIZE*samplingRate, default as 100 */
+ int high_freq = 100;
+ int i, ret = 0;
+
+ ssrmod.surround_input_bufferIdx = 0;
+ ssrmod.surround_output_bufferIdx = 0;
+
+ if ( ssrmod.surround_obj ) {
+ ALOGE("%s: ola filter library is already initialized", __func__);
+ return 0;
+ }
+
+ /* Allocate memory for input buffer */
+ ssrmod.surround_input_buffer = (Word16 *) calloc(2 * SSR_INPUT_FRAME_SIZE,
+ sizeof(Word16));
+ if ( !ssrmod.surround_input_buffer ) {
+ ALOGE("%s: Memory allocation failure. Not able to allocate "
+ "memory for surroundInputBuffer", __func__);
+ goto init_fail;
+ }
+
+ /* Allocate memory for output buffer */
+ ssrmod.surround_output_buffer = (Word16 *) calloc(2 * SSR_OUTPUT_FRAME_SIZE,
+ sizeof(Word16));
+ if ( !ssrmod.surround_output_buffer ) {
+ ALOGE("%s: Memory allocation failure. Not able to "
+ "allocate memory for surroundOutputBuffer", __func__);
+ goto init_fail;
+ }
+
+ /* Allocate memory for real and imag coeffs array */
+ ssrmod.real_coeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
+ if ( !ssrmod.real_coeffs ) {
+ ALOGE("%s: Memory allocation failure during real "
+ "Coefficient array", __func__);
+ goto init_fail;
+ }
+
+ ssrmod.imag_coeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
+ if ( !ssrmod.imag_coeffs ) {
+ ALOGE("%s: Memory allocation failure during imaginary "
+ "Coefficient array", __func__);
+ goto init_fail;
+ }
+
+ if( ssr_read_coeffs_from_file() != 0) {
+ ALOGE("%s: Error while loading coeffs from file", __func__);
+ goto init_fail;
+ }
+
+ ssrmod.surround_filters_handle = dlopen(LIB_SURROUND_PROC, RTLD_NOW);
+ if (ssrmod.surround_filters_handle == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SURROUND_PROC);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SURROUND_PROC);
+ ssrmod.surround_filters_init = (surround_filters_init_t)
+ dlsym(ssrmod.surround_filters_handle, "surround_filters_init");
+
+ ssrmod.surround_filters_release = (surround_filters_release_t)
+ dlsym(ssrmod.surround_filters_handle, "surround_filters_release");
+
+ ssrmod.surround_filters_set_channel_map = (surround_filters_set_channel_map_t)
+ dlsym(ssrmod.surround_filters_handle, "surround_filters_set_channel_map");
+
+ ssrmod.surround_filters_intl_process = (surround_filters_intl_process_t)
+ dlsym(ssrmod.surround_filters_handle, "surround_filters_intl_process");
+
+ if (!ssrmod.surround_filters_init ||
+ !ssrmod.surround_filters_release ||
+ !ssrmod.surround_filters_set_channel_map ||
+ !ssrmod.surround_filters_intl_process){
+ ALOGW("%s: Could not find the one of the symbols from %s",
+ __func__, LIB_SURROUND_PROC);
+ goto init_fail;
+ }
+ }
+
+ /* calculate the size of data to allocate for surround_obj */
+ ret = ssrmod.surround_filters_init(NULL,
+ 6, // Num output channel
+ 4, // Num input channel
+ ssrmod.real_coeffs, // Coeffs hardcoded in header
+ ssrmod.imag_coeffs, // Coeffs hardcoded in header
+ sub_woofer,
+ low_freq,
+ high_freq,
+ NULL);
+
+ if ( ret > 0 ) {
+ ALOGV("%s: Allocating surroundObj size is %d", __func__, ret);
+ ssrmod.surround_obj = (void *)malloc(ret);
+ memset(ssrmod.surround_obj,0,ret);
+ if (NULL != ssrmod.surround_obj) {
+ /* initialize after allocating the memory for surround_obj */
+ ret = ssrmod.surround_filters_init(ssrmod.surround_obj,
+ 6,
+ 4,
+ ssrmod.real_coeffs,
+ ssrmod.imag_coeffs,
+ sub_woofer,
+ low_freq,
+ high_freq,
+ NULL);
+ if (0 != ret) {
+ ALOGE("%s: surround_filters_init failed with ret:%d",__func__, ret);
+ ssrmod.surround_filters_release(ssrmod.surround_obj);
+ goto init_fail;
+ }
+ } else {
+ ALOGE("%s: Allocationg surround_obj failed", __func__);
+ goto init_fail;
+ }
+ } else {
+ ALOGE("%s: surround_filters_init(surround_obj=Null) "
+ "failed with ret: %d", __func__, ret);
+ goto init_fail;
+ }
+
+ (void) ssrmod.surround_filters_set_channel_map(ssrmod.surround_obj, chan_map);
+
+ return 0;
+
+init_fail:
+ if (ssrmod.surround_obj) {
+ free(ssrmod.surround_obj);
+ ssrmod.surround_obj = NULL;
+ }
+ if (ssrmod.surround_output_buffer) {
+ free(ssrmod.surround_output_buffer);
+ ssrmod.surround_output_buffer = NULL;
+ }
+ if (ssrmod.surround_input_buffer) {
+ free(ssrmod.surround_input_buffer);
+ ssrmod.surround_input_buffer = NULL;
+ }
+ if (ssrmod.real_coeffs){
+ for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+ if (ssrmod.real_coeffs[i]) {
+ free(ssrmod.real_coeffs[i]);
+ ssrmod.real_coeffs[i] = NULL;
+ }
+ }
+ free(ssrmod.real_coeffs);
+ ssrmod.real_coeffs = NULL;
+ }
+ if (ssrmod.imag_coeffs){
+ for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+ if (ssrmod.imag_coeffs[i]) {
+ free(ssrmod.imag_coeffs[i]);
+ ssrmod.imag_coeffs[i] = NULL;
+ }
+ }
+ free(ssrmod.imag_coeffs);
+ ssrmod.imag_coeffs = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+int32_t audio_extn_ssr_update_enabled(struct audio_device *adev)
+{
+ char ssr_enabled[PROPERTY_VALUE_MAX] = "false";
+
+ property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
+ if (!strncmp("true", ssr_enabled, 4)) {
+ ALOGD("%s: surround sound recording is supported", __func__);
+ ssrmod.is_ssr_enabled = true;
+ } else {
+ ALOGD("%s: surround sound recording is not supported", __func__);
+ ssrmod.is_ssr_enabled = false;
+ }
+ return 0;
+}
+
+bool audio_extn_ssr_get_enabled()
+{
+ ALOGV("%s: is_ssr_enabled:%d", __func__, ssrmod.is_ssr_enabled);
+ return (ssrmod.is_ssr_enabled ? true: false);
+}
+
+int32_t audio_extn_ssr_init(struct audio_device *adev,
+ struct stream_in *in)
+{
+ uint32_t ret;
+ char c_multi_ch_dump[128] = {0};
+ uint32_t buffer_size;
+
+ ALOGD("%s: ssr case ", __func__);
+ in->config.channels = SSR_CHANNEL_COUNT;
+ in->config.period_size = SSR_PERIOD_SIZE;
+ in->config.period_count = SSR_PERIOD_COUNT;
+
+ buffer_size = (SSR_PERIOD_SIZE)*(SSR_PERIOD_COUNT);
+ ALOGD("%s: buffer_size: %d", __func__, buffer_size);
+
+ ret = ssr_init_surround_sound_lib(buffer_size);
+ if (0 != ret) {
+ ALOGE("%s: initSurroundSoundLibrary failed: %d "
+ "handle->bufferSize:%d", __func__, ret, buffer_size);
+ return ret;
+ }
+
+ property_get("ssr.pcmdump",c_multi_ch_dump,"0");
+ if (0 == strncmp("true",c_multi_ch_dump, sizeof("ssr.dump-pcm"))) {
+ /* Remember to change file system permission of data(e.g. chmod 777 data/),
+ otherwise, fopen may fail */
+ if ( !ssrmod.fp_4ch)
+ ssrmod.fp_4ch = fopen("/data/media/0/4ch_ssr.pcm", "wb");
+ if ( !ssrmod.fp_6ch)
+ ssrmod.fp_6ch = fopen("/data/media/0/6ch_ssr.pcm", "wb");
+ if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch))
+ ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",
+ __func__, ssrmod.fp_4ch, ssrmod.fp_6ch);
+ }
+
+ return 0;
+}
+
+int32_t audio_extn_ssr_deinit()
+{
+ int i;
+
+ if (ssrmod.surround_obj) {
+ ALOGD("%s: entry", __func__);
+ ssrmod.surround_filters_release(ssrmod.surround_obj);
+ if (ssrmod.surround_obj)
+ free(ssrmod.surround_obj);
+ ssrmod.surround_obj = NULL;
+ if (ssrmod.real_coeffs){
+ for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+ if (ssrmod.real_coeffs[i]) {
+ free(ssrmod.real_coeffs[i]);
+ ssrmod.real_coeffs[i] = NULL;
+ }
+ }
+ free(ssrmod.real_coeffs);
+ ssrmod.real_coeffs = NULL;
+ }
+ if (ssrmod.imag_coeffs){
+ for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
+ if (ssrmod.imag_coeffs[i]) {
+ free(ssrmod.imag_coeffs[i]);
+ ssrmod.imag_coeffs[i] = NULL;
+ }
+ }
+ free(ssrmod.imag_coeffs);
+ ssrmod.imag_coeffs = NULL;
+ }
+ if (ssrmod.surround_output_buffer){
+ free(ssrmod.surround_output_buffer);
+ ssrmod.surround_output_buffer = NULL;
+ }
+ if (ssrmod.surround_input_buffer) {
+ free(ssrmod.surround_input_buffer);
+ ssrmod.surround_input_buffer = NULL;
+ }
+
+ if ( ssrmod.fp_4ch ) fclose(ssrmod.fp_4ch);
+ if ( ssrmod.fp_6ch ) fclose(ssrmod.fp_6ch);
+ }
+
+ if(ssrmod.surround_filters_handle)
+ {
+ dlclose(ssrmod.surround_filters_handle);
+ ssrmod.surround_filters_handle = NULL;
+ }
+ ALOGD("%s: exit", __func__);
+
+ return 0;
+}
+
+int32_t audio_extn_ssr_read(struct audio_stream_in *stream,
+ void *buffer, size_t bytes)
+{
+ int processed = 0;
+ int processed_pending;
+ void *buffer_start = buffer;
+ unsigned period_bytes;
+ unsigned period_samples;
+ int read_pending, n;
+ size_t read_bytes = 0;
+ int samples = bytes >> 1;
+
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+
+ period_bytes = in->config.period_size;
+ ALOGD("%s: period_size: %d", __func__, in->config.period_size);
+ period_samples = period_bytes >> 1;
+
+ if (!ssrmod.surround_obj)
+ return -ENOMEM;
+
+ do {
+ if (ssrmod.surround_output_bufferIdx > 0) {
+ ALOGV("%s: copy processed output "
+ "to buffer, surround_output_bufferIdx = %d",
+ __func__, ssrmod.surround_output_bufferIdx);
+ /* Copy processed output to buffer */
+ processed_pending = ssrmod.surround_output_bufferIdx;
+ if (processed_pending > (samples - processed)) {
+ processed_pending = (samples - processed);
+ }
+ memcpy(buffer, ssrmod.surround_output_buffer, processed_pending * sizeof(Word16));
+ buffer = (char*)buffer + processed_pending * sizeof(Word16);
+ processed += processed_pending;
+ if (ssrmod.surround_output_bufferIdx > processed_pending) {
+ /* Shift leftover samples to beginning of the buffer */
+ memcpy(&ssrmod.surround_output_buffer[0],
+ &ssrmod.surround_output_buffer[processed_pending],
+ (ssrmod.surround_output_bufferIdx - processed_pending) * sizeof(Word16));
+ }
+ ssrmod.surround_output_bufferIdx -= processed_pending;
+ }
+
+ if (processed >= samples) {
+ ALOGV("%s: done processing buffer, "
+ "processed = %d", __func__, processed);
+ /* Done processing this buffer */
+ break;
+ }
+
+ /* Fill input buffer until there is enough to process */
+ read_pending = SSR_INPUT_FRAME_SIZE - ssrmod.surround_input_bufferIdx;
+ read_bytes = ssrmod.surround_input_bufferIdx;
+ while (in->pcm && read_pending > 0) {
+ n = pcm_read(in->pcm, &ssrmod.surround_input_buffer[read_bytes],
+ period_bytes);
+ ALOGV("%s: pcm_read() returned n = %d buffer:%p size:%d", __func__,
+ n, &ssrmod.surround_input_buffer[read_bytes], period_bytes);
+ if (n && n != -EAGAIN) {
+ /* Recovery part of pcm_read. TODO:split recovery */
+ return (ssize_t)n;
+ }
+ else if (n < 0) {
+ /* Recovery is part of pcm_write. TODO split is later */
+ return (ssize_t)n;
+ }
+ else {
+ read_pending -= period_samples;
+ read_bytes += period_samples;
+ }
+ }
+
+
+ if (ssrmod.fp_4ch) {
+ fwrite( ssrmod.surround_input_buffer, 1,
+ SSR_INPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_4ch);
+ }
+
+ /* apply ssr libs to conver 4ch to 6ch */
+ ssrmod.surround_filters_intl_process(ssrmod.surround_obj,
+ &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx],
+ (Word16 *)ssrmod.surround_input_buffer);
+
+ /* Shift leftover samples to beginning of input buffer */
+ if (read_pending < 0) {
+ memcpy(&ssrmod.surround_input_buffer[0],
+ &ssrmod.surround_input_buffer[SSR_INPUT_FRAME_SIZE],
+ (-read_pending) * sizeof(Word16));
+ }
+ ssrmod.surround_input_bufferIdx = -read_pending;
+
+ if (ssrmod.fp_6ch) {
+ fwrite( &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx],
+ 1, SSR_OUTPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_6ch);
+ }
+
+ ssrmod.surround_output_bufferIdx += SSR_OUTPUT_FRAME_SIZE;
+ ALOGV("%s: do_while loop: processed=%d, samples=%d\n", __func__, processed, samples);
+ } while (in->pcm && processed < samples);
+ read_bytes = processed * sizeof(Word16);
+ buffer = buffer_start;
+
+ return 0;
+}
+
+void audio_extn_ssr_get_parameters(struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret, val;
+ char value[32]={0};
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SSR, value, sizeof(value));
+
+ if (ret >= 0) {
+ memcpy(value, "true", 4);
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SSR, value);
+ }
+}
+#endif /* SSR_ENABLED */
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
new file mode 100644
index 0000000..88af9be
--- /dev/null
+++ b/hal/audio_extn/usb.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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_usb"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <system/audio.h>
+#include <tinyalsa/asoundlib.h>
+
+#ifdef USB_HEADSET_ENABLED
+#define USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE 512
+#define USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT 8
+#define USB_DEFAULT_OUTPUT_SAMPLING_RATE 48000
+
+#define USB_PROXY_DEFAULT_SAMPLING_RATE 48000
+#define USB_PROXY_OPEN_RETRY_COUNT 100
+#define USB_PROXY_OPEN_WAIT_TIME 20
+#define USB_PROXY_PERIOD_SIZE 3072
+#define USB_PROXY_RATE_8000 8000
+#define USB_PROXY_RATE_16000 16000
+#define USB_PROXY_RATE_48000 48000
+#define USB_PERIOD_SIZE 2048
+#define USB_BUFF_SIZE 2048
+#define AFE_PROXY_PERIOD_COUNT 32
+#define AFE_PROXY_PLAYBACK_DEVICE 8
+#define AFE_PROXY_CAPTURE_DEVICE 7
+
+struct usb_module {
+ uint32_t usb_card;
+ uint32_t proxy_card;
+ uint32_t usb_device_id;
+ uint32_t proxy_device_id;
+
+ int32_t channels_playback;
+ int32_t sample_rate_playback;
+ int32_t channels_record;
+ int32_t sample_rate_record;
+
+ bool is_playback_running;
+ bool is_record_running;
+
+ pthread_t usb_playback_thr;
+ pthread_t usb_record_thr;
+ pthread_mutex_t usb_playback_lock;
+ pthread_mutex_t usb_record_lock;
+
+ struct pcm *proxy_pcm_playback_handle;
+ struct pcm *usb_pcm_playback_handle;
+ struct pcm *proxy_pcm_record_handle;
+ struct pcm *usb_pcm_record_handle;
+ struct audio_device *adev;
+};
+
+static struct usb_module *usbmod = NULL;
+static pthread_once_t alloc_usbmod_once_ctl = PTHREAD_ONCE_INIT;
+
+struct pcm_config pcm_config_usbmod = {
+ .channels = 2,
+ .rate = USB_DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+ .period_count = USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+ .stop_threshold = INT_MAX,
+ .avail_min = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+static void usb_alloc()
+{
+ usbmod = calloc(1, sizeof(struct usb_module));
+}
+
+static int usb_get_numof_rates(char *rates_str)
+{
+ int i, size = 0;
+ char *next_sr_string, *temp_ptr;
+ next_sr_string = strtok_r(rates_str, " ,", &temp_ptr);
+
+ if (next_sr_string == NULL) {
+ ALOGE("%s: get_numof_rates: could not find rates string", __func__);
+ return (int)NULL;
+ }
+
+ for (i = 1; next_sr_string != NULL; i++) {
+ size ++;
+ next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+ }
+ return size;
+}
+
+static int usb_get_capability(char *type, int32_t *channels,
+ int32_t *sample_rate)
+{
+ ALOGD("%s: for %s", __func__, type);
+ long unsigned file_size;
+ FILE *fp;
+ char *buffer;
+ int32_t err = 1;
+ int32_t size = 0;
+ int32_t fd, i, channels_playback;
+ char *read_buf, *str_start, *channel_start, *rates_str, *rates_str_for_val,
+ *rates_str_start, *next_sr_str, *test, *next_sr_string, *temp_ptr;
+ struct stat st;
+ int *rates_supported;
+ char path[128];
+
+ memset(&st, 0x0, sizeof(struct stat));
+ *sample_rate = 0;
+ snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
+ usbmod->usb_card);
+
+ fd = open(path, O_RDONLY);
+ if (fd <0) {
+ ALOGE("%s: error failed to open config file %s error: %d\n",
+ __func__, path, errno);
+ close(fd);
+ return -EINVAL;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ ALOGE("%s: error failed to stat %s error %d\n",
+ __func__, path, errno);
+ close(fd);
+ return -EINVAL;
+ }
+
+ file_size = st.st_size;
+
+ read_buf = (char *)calloc(1, USB_BUFF_SIZE);
+ err = read(fd, read_buf, USB_BUFF_SIZE);
+ str_start = strstr(read_buf, type);
+ if (str_start == NULL) {
+ ALOGE("%s: error %s section not found in usb config file",
+ __func__, type);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ channel_start = strstr(str_start, "Channels:");
+ if (channel_start == NULL) {
+ ALOGE("%s: error could not find Channels information", __func__);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ channel_start = strstr(channel_start, " ");
+ if (channel_start == NULL) {
+ ALOGE("%s: error channel section not found in usb config file",
+ __func__);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ channels_playback = atoi(channel_start);
+ if (channels_playback == 1) {
+ *channels = 1;
+ } else {
+ *channels = 2;
+ }
+
+ ALOGD("%s: channels supported by device: %d", __func__, *channels);
+ rates_str_start = strstr(str_start, "Rates:");
+ if (rates_str_start == NULL) {
+ ALOGE("%s: error cant find rates information", __func__);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ rates_str_start = strstr(rates_str_start, " ");
+ if (rates_str_start == NULL) {
+ ALOGE("%s: error channel section not found in usb config file",
+ __func__);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ char *target = strchr(rates_str_start, '\n');
+ if (target == NULL) {
+ ALOGE("%s: error end of line not found", __func__);
+ close(fd);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ size = target - rates_str_start;
+ if ((rates_str = (char *)malloc(size + 1)) == NULL) {
+ ALOGE("%s: error unable to allocate memory to hold sample rate strings",
+ __func__);
+ close(fd);
+ free(read_buf);
+ return -ENOMEM;
+ }
+
+ if ((rates_str_for_val = (char *)malloc(size + 1)) == NULL) {
+ ALOGE("%s: error unable to allocate memory to hold sample rate string",
+ __func__);
+ close(fd);
+ free(rates_str);
+ free(read_buf);
+ return -ENOMEM;
+ }
+
+ memcpy(rates_str, rates_str_start, size);
+ memcpy(rates_str_for_val, rates_str_start, size);
+ rates_str[size] = '\0';
+ rates_str_for_val[size] = '\0';
+
+ size = usb_get_numof_rates(rates_str);
+ if (!size) {
+ ALOGE("%s: error could not get rate size, returning", __func__);
+ close(fd);
+ free(rates_str_for_val);
+ free(rates_str);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ rates_supported = (int *)malloc(sizeof(int) * size);
+ next_sr_string = strtok_r(rates_str_for_val, " ,", &temp_ptr);
+ if (next_sr_string == NULL) {
+ ALOGE("%s: error could not get first rate val", __func__);
+ close(fd);
+ free(rates_str_for_val);
+ free(rates_str);
+ free(rates_supported);
+ free(read_buf);
+ return -EINVAL;
+ }
+
+ rates_supported[0] = atoi(next_sr_string);
+ ALOGD("%s: rates_supported[0] for playback: %d",
+ __func__, rates_supported[0]);
+ for (i = 1; i<size; i++) {
+ next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+ rates_supported[i] = atoi(next_sr_string);
+ ALOGD("rates_supported[%d] for playback: %d",i, rates_supported[i]);
+ }
+
+ for (i = 0; i<size; i++) {
+ if ((rates_supported[i] > *sample_rate) &&
+ (rates_supported[i] <= 48000)) {
+ /* Sample Rate should be one of the proxy supported rates only
+ This is because proxy port is used to read from/write to DSP */
+ if ((rates_supported[i] == USB_PROXY_RATE_8000) ||
+ (rates_supported[i] == USB_PROXY_RATE_16000) ||
+ (rates_supported[i] == USB_PROXY_RATE_48000)) {
+ *sample_rate = rates_supported[i];
+ }
+ }
+ }
+ ALOGD("%s: sample_rate: %d", __func__, *sample_rate);
+
+ close(fd);
+ free(rates_str_for_val);
+ free(rates_str);
+ free(rates_supported);
+ free(read_buf);
+ return 0;
+}
+
+static int32_t usb_playback_entry(void *adev)
+{
+ unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0};
+ int32_t ret, bytes, proxy_open_retry_count;
+
+ ALOGD("%s: entry", __func__);
+ /* update audio device pointer */
+ usbmod->adev = (struct audio_device*)adev;
+ proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT;
+
+ /* get capabilities */
+ pthread_mutex_lock(&usbmod->usb_playback_lock);
+ ret = usb_get_capability((char *)"Playback:",
+ &usbmod->channels_playback, &usbmod->sample_rate_playback);
+ if (ret) {
+ ALOGE("%s: could not get playback capabilities from usb device",
+ __func__);
+ pthread_mutex_unlock(&usbmod->usb_playback_lock);
+ return -EINVAL;
+ }
+ /* update config for usb
+ 1 pcm frame(sample)= 4 bytes since two channels*/
+ pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4;
+ pcm_config_usbmod.channels = usbmod->channels_playback;
+ pcm_config_usbmod.rate = usbmod->sample_rate_playback;
+ ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__,
+ pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+ pcm_config_usbmod.rate);
+
+ usbmod->usb_pcm_playback_handle = pcm_open(usbmod->usb_card, \
+ usbmod->usb_device_id, PCM_OUT |
+ PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod);
+
+ if ((usbmod->usb_pcm_playback_handle \
+ && !pcm_is_ready(usbmod->usb_pcm_playback_handle))
+ || (!usbmod->is_playback_running)) {
+ ALOGE("%s: failed: %s", __func__,
+ pcm_get_error(usbmod->usb_pcm_playback_handle));
+ pcm_close(usbmod->usb_pcm_playback_handle);
+ usbmod->usb_pcm_playback_handle = NULL;
+ pthread_mutex_unlock(&usbmod->usb_playback_lock);
+ return -ENOMEM;
+ }
+ ALOGD("%s: USB configured for playback", __func__);
+
+ /* update config for proxy*/
+ pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/3;
+ pcm_config_usbmod.rate = usbmod->sample_rate_playback;
+ pcm_config_usbmod.channels = usbmod->channels_playback;
+ pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT;
+ usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE;
+ ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__,
+ pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+ pcm_config_usbmod.rate);
+
+ while(proxy_open_retry_count){
+ usbmod->proxy_pcm_playback_handle = pcm_open(usbmod->proxy_card,
+ usbmod->proxy_device_id, PCM_IN |
+ PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod);
+ if(!usbmod->proxy_pcm_playback_handle){
+ proxy_open_retry_count--;
+ usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
+ ALOGE("%s: pcm_open for proxy failed retrying = %d",
+ __func__, proxy_open_retry_count);
+ }
+ else{
+ break;
+ }
+ }
+
+ if ((usbmod->proxy_pcm_playback_handle
+ && !pcm_is_ready(usbmod->proxy_pcm_playback_handle))
+ || (!usbmod->is_playback_running)) {
+ ALOGE("%s: failed: %s", __func__,
+ pcm_get_error(usbmod->proxy_pcm_playback_handle));
+ pcm_close(usbmod->proxy_pcm_playback_handle);
+ usbmod->proxy_pcm_playback_handle = NULL;
+ pthread_mutex_unlock(&usbmod->usb_playback_lock);
+ return -ENOMEM;
+ }
+ ALOGD("%s: PROXY configured for playback", __func__);
+ pthread_mutex_unlock(&usbmod->usb_playback_lock);
+
+ /* main loop to read from proxy and write to usb */
+ while (usbmod->is_playback_running) {
+ /* read data from proxy */
+ ret = pcm_mmap_read(usbmod->proxy_pcm_playback_handle,
+ (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+ /* Write to usb */
+ ret = pcm_mmap_write(usbmod->usb_pcm_playback_handle,
+ (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+ if(!usbmod->is_playback_running)
+ break;
+
+ memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
+ } /* main loop end */
+
+ ALOGD("%s: exiting USB playback thread",__func__);
+ return 0;
+}
+
+static void* usb_playback_launcher(void *adev)
+{
+ int32_t ret;
+
+ usbmod->is_playback_running = true;
+ ret = usb_playback_entry(adev);
+
+ if (ret) {
+ ALOGE("%s: failed with err:%d", __func__, ret);
+ usbmod->is_playback_running = false;
+ }
+ return NULL;
+}
+
+static int32_t usb_record_entry(void *adev)
+{
+ unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0};
+ int32_t ret, bytes, proxy_open_retry_count;
+ ALOGD("%s: entry", __func__);
+
+ /* update audio device pointer */
+ usbmod->adev = (struct audio_device*)adev;
+ proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT;
+
+ /* get capabilities */
+ pthread_mutex_lock(&usbmod->usb_record_lock);
+ ret = usb_get_capability((char *)"Capture:",
+ &usbmod->channels_record, &usbmod->sample_rate_record);
+ if (ret) {
+ ALOGE("%s: could not get capture capabilities from usb device",
+ __func__);
+ pthread_mutex_unlock(&usbmod->usb_record_lock);
+ return -EINVAL;
+ }
+ /* update config for usb
+ 1 pcm frame(sample)= 4 bytes since two channels*/
+ pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4;
+ pcm_config_usbmod.channels = usbmod->channels_record;
+ pcm_config_usbmod.rate = usbmod->sample_rate_record;
+ ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__,
+ pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+ pcm_config_usbmod.rate);
+
+ usbmod->usb_pcm_record_handle = pcm_open(usbmod->usb_card, \
+ usbmod->usb_device_id, PCM_IN |
+ PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod);
+
+ if ((usbmod->usb_pcm_record_handle \
+ && !pcm_is_ready(usbmod->usb_pcm_record_handle))
+ || (!usbmod->is_record_running)) {
+ ALOGE("%s: failed: %s", __func__,
+ pcm_get_error(usbmod->usb_pcm_record_handle));
+ pcm_close(usbmod->usb_pcm_record_handle);
+ usbmod->usb_pcm_record_handle = NULL;
+ pthread_mutex_unlock(&usbmod->usb_record_lock);
+ return -ENOMEM;
+ }
+ ALOGD("%s: USB configured for capture", __func__);
+
+ /* update config for proxy*/
+ pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/4;
+ pcm_config_usbmod.rate = usbmod->sample_rate_record;
+ pcm_config_usbmod.channels = usbmod->channels_record;
+ pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT * 2;
+ usbmod->proxy_device_id = AFE_PROXY_CAPTURE_DEVICE;
+ ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__,
+ pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
+ pcm_config_usbmod.rate);
+
+ while(proxy_open_retry_count){
+ usbmod->proxy_pcm_record_handle = pcm_open(usbmod->proxy_card,
+ usbmod->proxy_device_id, PCM_OUT |
+ PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod);
+ if(!usbmod->proxy_pcm_record_handle){
+ proxy_open_retry_count--;
+ usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
+ ALOGE("%s: pcm_open for proxy(recording) failed retrying = %d",
+ __func__, proxy_open_retry_count);
+ }
+ else{
+ break;
+ }
+ }
+ if ((usbmod->proxy_pcm_record_handle
+ && !pcm_is_ready(usbmod->proxy_pcm_record_handle))
+ || (!usbmod->is_record_running)) {
+ ALOGE("%s: failed: %s", __func__,
+ pcm_get_error(usbmod->proxy_pcm_record_handle));
+ pcm_close(usbmod->proxy_pcm_record_handle);
+ usbmod->proxy_pcm_record_handle = NULL;
+ pthread_mutex_unlock(&usbmod->usb_record_lock);
+ return -ENOMEM;
+ }
+ ALOGD("%s: PROXY configured for capture", __func__);
+ pthread_mutex_unlock(&usbmod->usb_record_lock);
+
+ /* main loop to read from usb and write to proxy */
+ while (usbmod->is_record_running) {
+ /* read data from usb */
+ ret = pcm_mmap_read(usbmod->usb_pcm_record_handle,
+ (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+ /* Write to proxy */
+ ret = pcm_mmap_write(usbmod->proxy_pcm_record_handle,
+ (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
+ if(!usbmod->is_record_running)
+ break;
+
+ memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
+ } /* main loop end */
+
+ ALOGD("%s: exiting USB capture thread",__func__);
+ return 0;
+}
+
+static void* usb_capture_launcher(void *adev)
+{
+ int32_t ret;
+
+ usbmod->is_record_running = true;
+ ret = usb_record_entry(adev);
+
+ if (ret) {
+ ALOGE("%s: failed with err:%d", __func__, ret);
+ usbmod->is_record_running = false;
+ }
+ return NULL;
+}
+
+void audio_extn_usb_init(void *adev)
+{
+ pthread_once(&alloc_usbmod_once_ctl, usb_alloc);
+
+ usbmod->is_playback_running = false;
+ usbmod->is_record_running = false;
+
+ usbmod->usb_pcm_playback_handle = NULL;
+ usbmod->proxy_pcm_playback_handle = NULL;
+
+ usbmod->usb_pcm_record_handle = NULL;
+ usbmod->proxy_pcm_record_handle = NULL;
+
+ usbmod->usb_card = 1;
+ usbmod->usb_device_id = 0;
+ usbmod->proxy_card = 0;
+ usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE;
+ usbmod->adev = (struct audio_device*)adev;
+}
+
+void audio_extn_usb_deinit()
+{
+ if (NULL != usbmod){
+ free(usbmod);
+ usbmod = NULL;
+ }
+}
+
+void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx)
+{
+ /* Proxy port and USB headset are related to two different sound cards */
+ if (sndcard_idx == usbmod->usb_card) {
+ usbmod->usb_card = usbmod->proxy_card;
+ }
+
+ usbmod->proxy_card = sndcard_idx;
+}
+
+void audio_extn_usb_start_playback(void *adev)
+{
+ int32_t ret;
+
+ if (NULL == usbmod){
+ ALOGE("%s: USB device object is NULL", __func__);
+ return;
+ }
+
+ if (usbmod->is_playback_running){
+ ALOGE("%s: USB playback thread already running", __func__);
+ return;
+ }
+
+ ALOGD("%s: creating USB playback thread", __func__);
+ ret = pthread_create(&usbmod->usb_playback_thr, NULL,
+ usb_playback_launcher, (void*)adev);
+ if (ret)
+ ALOGE("%s: failed to create USB playback thread with err:%d",
+ __func__, ret);
+}
+
+void audio_extn_usb_stop_playback()
+{
+ int32_t ret;
+ ALOGD("%s: entry", __func__);
+
+ usbmod->is_playback_running = false;
+ if (NULL != usbmod->proxy_pcm_playback_handle)
+ pcm_stop(usbmod->proxy_pcm_playback_handle);
+
+ if (NULL != usbmod->usb_pcm_playback_handle)
+ pcm_stop(usbmod->usb_pcm_playback_handle);
+
+ if(usbmod->usb_playback_thr) {
+ ret = pthread_join(usbmod->usb_playback_thr,NULL);
+ ALOGE("%s: return for pthread_join = %d", __func__, ret);
+ usbmod->usb_playback_thr = (pthread_t)NULL;
+ }
+
+ pthread_mutex_lock(&usbmod->usb_playback_lock);
+ if (NULL != usbmod->usb_pcm_playback_handle){
+ pcm_close(usbmod->usb_pcm_playback_handle);
+ usbmod->usb_pcm_playback_handle = NULL;
+ }
+
+ if (NULL != usbmod->proxy_pcm_playback_handle){
+ pcm_close(usbmod->proxy_pcm_playback_handle);
+ usbmod->proxy_pcm_playback_handle = NULL;
+ }
+ pthread_mutex_unlock(&usbmod->usb_playback_lock);
+
+ ALOGD("%s: exiting",__func__);
+}
+
+void audio_extn_usb_start_capture(void *adev)
+{
+ int32_t ret;
+
+ if (NULL == usbmod){
+ ALOGE("%s: USB device object is NULL", __func__);
+ return;
+ }
+
+ if (usbmod->is_record_running){
+ ALOGE("%s: USB capture thread already running", __func__);
+ return;
+ }
+
+ ALOGD("%s: creating USB capture thread", __func__);
+ ret = pthread_create(&usbmod->usb_record_thr, NULL,
+ usb_capture_launcher, (void*)adev);
+ if (ret)
+ ALOGE("%s: failed to create USB capture thread with err:%d",
+ __func__, ret);
+}
+
+void audio_extn_usb_stop_capture()
+{
+ int32_t ret;
+ ALOGD("%s: entry", __func__);
+
+ usbmod->is_record_running = false;
+ if (NULL != usbmod->proxy_pcm_record_handle)
+ pcm_stop(usbmod->proxy_pcm_record_handle);
+
+ if (NULL != usbmod->usb_pcm_record_handle)
+ pcm_stop(usbmod->usb_pcm_record_handle);
+
+ if(usbmod->usb_record_thr) {
+ ret = pthread_join(usbmod->usb_record_thr,NULL);
+ ALOGE("%s: return for pthread_join = %d", __func__, ret);
+ usbmod->usb_record_thr = (pthread_t)NULL;
+ }
+
+ pthread_mutex_lock(&usbmod->usb_record_lock);
+ if (NULL != usbmod->usb_pcm_record_handle){
+ pcm_close(usbmod->usb_pcm_record_handle);
+ usbmod->usb_pcm_record_handle = NULL;
+ }
+
+ if (NULL != usbmod->proxy_pcm_record_handle){
+ pcm_close(usbmod->proxy_pcm_record_handle);
+ usbmod->proxy_pcm_record_handle = NULL;
+ }
+ pthread_mutex_unlock(&usbmod->usb_record_lock);
+
+ ALOGD("%s: exiting",__func__);
+}
+
+bool audio_extn_usb_is_proxy_inuse()
+{
+ if( usbmod->is_record_running || usbmod->is_playback_running)
+ return true;
+ else
+ return false;
+}
+#endif /*USB_HEADSET_ENABLED end*/
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 48c426d..a81a53a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -46,6 +49,8 @@
#include "audio_hw.h"
#include "platform_api.h"
#include <platform.h>
+#include "audio_extn.h"
+#include "voice_extn.h"
#include "sound/compress_params.h"
@@ -94,22 +99,30 @@
.format = PCM_FORMAT_S16_LE,
};
-struct pcm_config pcm_config_voice_call = {
- .channels = 1,
- .rate = 8000,
- .period_size = 160,
- .period_count = 2,
- .format = PCM_FORMAT_S16_LE,
-};
-
-static const char * const use_case_table[AUDIO_USECASE_MAX] = {
+const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
- [USECASE_AUDIO_RECORD] = "audio-record",
- [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
- [USECASE_VOICE_CALL] = "voice-call",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
+ [USECASE_AUDIO_RECORD] = "audio-record",
+ [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
+ [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
+ [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
+ [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
+ [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
+ [USECASE_VOICE_CALL] = "voice-call",
+
+ [USECASE_VOICE2_CALL] = "voice2-call",
+ [USECASE_VOLTE_CALL] = "volte-call",
+ [USECASE_QCHAT_CALL] = "qchat-call",
+ [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
+ [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
+ [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
+ [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
+ [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
+ [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
+ [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
+ [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
};
@@ -126,6 +139,10 @@
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
};
+static struct audio_device *adev = NULL;
+static pthread_mutex_t adev_init_lock;
+static unsigned int audio_device_ref_count;
+
static int set_voice_volume_l(struct audio_device *adev, float volume);
static bool is_supported_format(audio_format_t format)
@@ -149,18 +166,18 @@
id = SND_AUDIOCODEC_AAC;
break;
default:
- ALOGE("%s: Unsupported audio format", __func__);
+ ALOGE("%s: Unsupported audio format :%x", __func__, format);
}
return id;
}
-static int enable_audio_route(struct audio_device *adev,
+int enable_audio_route(struct audio_device *adev,
struct audio_usecase *usecase,
bool update_mixer)
{
snd_device_t snd_device;
- char mixer_path[50];
+ char mixer_path[MIXER_PATH_MAX_LENGTH];
if (usecase == NULL)
return -EINVAL;
@@ -183,12 +200,12 @@
return 0;
}
-static int disable_audio_route(struct audio_device *adev,
- struct audio_usecase *usecase,
- bool update_mixer)
+int disable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer)
{
snd_device_t snd_device;
- char mixer_path[50];
+ char mixer_path[MIXER_PATH_MAX_LENGTH];
if (usecase == NULL)
return -EINVAL;
@@ -209,10 +226,12 @@
return 0;
}
-static int enable_snd_device(struct audio_device *adev,
+int enable_snd_device(struct audio_device *adev,
snd_device_t snd_device,
bool update_mixer)
{
+ char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+
if (snd_device < SND_DEVICE_MIN ||
snd_device >= SND_DEVICE_MAX) {
ALOGE("%s: Invalid sound device %d", __func__, snd_device);
@@ -220,30 +239,56 @@
}
adev->snd_dev_ref_cnt[snd_device]++;
+
+ if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
+ ALOGE("%s: Invalid sound device returned", __func__);
+ return -EINVAL;
+ }
if (adev->snd_dev_ref_cnt[snd_device] > 1) {
ALOGV("%s: snd_device(%d: %s) is already active",
- __func__, snd_device, platform_get_snd_device_name(snd_device));
+ __func__, snd_device, device_name);
return 0;
}
- if (platform_send_audio_calibration(adev->platform, snd_device) < 0) {
- adev->snd_dev_ref_cnt[snd_device]--;
- return -EINVAL;
- }
+ /* start usb playback thread */
+ if(SND_DEVICE_OUT_USB_HEADSET == snd_device ||
+ SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device)
+ audio_extn_usb_start_playback(adev);
- ALOGV("%s: snd_device(%d: %s)", __func__,
- snd_device, platform_get_snd_device_name(snd_device));
- audio_route_apply_path(adev->audio_route, platform_get_snd_device_name(snd_device));
+ /* start usb capture thread */
+ if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device)
+ audio_extn_usb_start_capture(adev);
+
+ if (snd_device == SND_DEVICE_OUT_SPEAKER &&
+ audio_extn_spkr_prot_is_enabled()) {
+ if (audio_extn_spkr_prot_start_processing(snd_device)) {
+ ALOGE("%s: spkr_start_processing failed", __func__);
+ return -EINVAL;
+ }
+ } else {
+ ALOGV("%s: snd_device(%d: %s)", __func__,
+ snd_device, device_name);
+ if (platform_send_audio_calibration(adev->platform, snd_device) < 0) {
+ adev->snd_dev_ref_cnt[snd_device]--;
+ return -EINVAL;
+ }
+ audio_extn_listen_update_status(snd_device,
+ LISTEN_EVENT_SND_DEVICE_BUSY);
+
+ audio_route_apply_path(adev->audio_route, device_name);
+ }
if (update_mixer)
audio_route_update_mixer(adev->audio_route);
return 0;
}
-static int disable_snd_device(struct audio_device *adev,
- snd_device_t snd_device,
- bool update_mixer)
+int disable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer)
{
+ char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+
if (snd_device < SND_DEVICE_MIN ||
snd_device >= SND_DEVICE_MAX) {
ALOGE("%s: Invalid sound device %d", __func__, snd_device);
@@ -253,14 +298,39 @@
ALOGE("%s: device ref cnt is already 0", __func__);
return -EINVAL;
}
+
adev->snd_dev_ref_cnt[snd_device]--;
+
+ if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
+ ALOGE("%s: Invalid sound device returned", __func__);
+ return -EINVAL;
+ }
+
if (adev->snd_dev_ref_cnt[snd_device] == 0) {
ALOGV("%s: snd_device(%d: %s)", __func__,
- snd_device, platform_get_snd_device_name(snd_device));
- audio_route_reset_path(adev->audio_route, platform_get_snd_device_name(snd_device));
+ snd_device, device_name);
+ /* exit usb play back thread */
+ if(SND_DEVICE_OUT_USB_HEADSET == snd_device ||
+ SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET == snd_device)
+ audio_extn_usb_stop_playback();
+
+ /* exit usb capture thread */
+ if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device)
+ audio_extn_usb_stop_capture(adev);
+
+ if (snd_device == SND_DEVICE_OUT_SPEAKER &&
+ audio_extn_spkr_prot_is_enabled()) {
+ audio_extn_spkr_prot_stop_processing();
+ } else
+ audio_route_reset_path(adev->audio_route, device_name);
+
if (update_mixer)
audio_route_update_mixer(adev->audio_route);
+
+ audio_extn_listen_update_status(snd_device,
+ LISTEN_EVENT_SND_DEVICE_FREE);
}
+
return 0;
}
@@ -290,7 +360,7 @@
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->type != PCM_CAPTURE &&
+ if (usecase->type == PCM_PLAYBACK &&
usecase != uc_info &&
usecase->out_snd_device != snd_device &&
usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
@@ -321,6 +391,12 @@
}
}
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (switch_device[usecase->id]) {
+ enable_snd_device(adev, snd_device, false);
+ }
+ }
/* Make sure new snd device is enabled before re-routing the streams */
audio_route_update_mixer(adev->audio_route);
@@ -363,7 +439,7 @@
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->type != PCM_PLAYBACK &&
+ if (usecase->type == PCM_CAPTURE &&
usecase != uc_info &&
usecase->in_snd_device != snd_device) {
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
@@ -405,6 +481,51 @@
}
}
+static int disable_all_usecases_of_type(struct audio_device *adev,
+ usecase_type_t usecase_type,
+ bool update_mixer)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ int ret = 0;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == usecase_type) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ ret = disable_audio_route(adev, usecase, update_mixer);
+ if (ret) {
+ ALOGE("%s: Failed to disable usecase id %d",
+ __func__, usecase->id);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int enable_all_usecases_of_type(struct audio_device *adev,
+ usecase_type_t usecase_type,
+ bool update_mixer)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ int ret = 0;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == usecase_type) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ ret = enable_audio_route(adev, usecase, update_mixer);
+ if (ret) {
+ ALOGE("%s: Failed to enable usecase id %d",
+ __func__, usecase->id);
+ }
+ }
+ }
+
+ return ret;
+}
/* must be called with hw device mutex locked */
static int read_hdmi_channel_masks(struct stream_out *out)
@@ -434,8 +555,23 @@
return ret;
}
-static struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
- audio_usecase_t uc_id)
+static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == VOICE_CALL) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ return usecase->id;
+ }
+ }
+ return USECASE_INVALID;
+}
+
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+ audio_usecase_t uc_id)
{
struct audio_usecase *usecase;
struct listnode *node;
@@ -448,13 +584,13 @@
return NULL;
}
-static int select_devices(struct audio_device *adev,
- audio_usecase_t uc_id)
+int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
snd_device_t out_snd_device = SND_DEVICE_NONE;
snd_device_t in_snd_device = SND_DEVICE_NONE;
struct audio_usecase *usecase = NULL;
struct audio_usecase *vc_usecase = NULL;
+ struct audio_usecase *voip_usecase = NULL;
struct listnode *node;
int status = 0;
@@ -464,7 +600,9 @@
return -EINVAL;
}
- if (usecase->type == VOICE_CALL) {
+ if ((usecase->type == VOICE_CALL) ||
+ (usecase->type == VOIP_CALL) ||
+ (usecase->type == PCM_HFP_CALL)) {
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out->devices);
in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
@@ -477,12 +615,20 @@
* usecase. This is to avoid switching devices for voice call when
* check_usecases_codec_backend() is called below.
*/
- if (adev->in_call) {
- vc_usecase = get_usecase_from_list(adev, USECASE_VOICE_CALL);
- if (vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ if (voice_is_in_call(adev)) {
+ vc_usecase = get_usecase_from_list(adev,
+ get_voice_usecase_id_from_list(adev));
+ if ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+ (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL)) {
in_snd_device = vc_usecase->in_snd_device;
out_snd_device = vc_usecase->out_snd_device;
}
+ } else if (voice_extn_compress_voip_is_active(adev)) {
+ voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+ if (voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ in_snd_device = voip_usecase->in_snd_device;
+ out_snd_device = voip_usecase->out_snd_device;
+ }
}
if (usecase->type == PCM_PLAYBACK) {
usecase->devices = usecase->stream.out->devices;
@@ -526,8 +672,9 @@
* and enable both RX and TX devices though one of them is same as current
* device.
*/
- if (usecase->type == VOICE_CALL) {
+ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
status = platform_switch_voice_call_device_pre(adev->platform);
+ disable_all_usecases_of_type(adev, VOICE_CALL, true);
}
/* Disable current sound devices */
@@ -553,7 +700,7 @@
enable_snd_device(adev, in_snd_device, false);
}
- if (usecase->type == VOICE_CALL)
+ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
status = platform_switch_voice_call_device_post(adev->platform,
out_snd_device,
in_snd_device);
@@ -563,7 +710,19 @@
usecase->in_snd_device = in_snd_device;
usecase->out_snd_device = out_snd_device;
- enable_audio_route(adev, usecase, true);
+ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
+ enable_all_usecases_of_type(adev, usecase->type, true);
+ else
+ enable_audio_route(adev, usecase, true);
+
+ /* Applicable only on the targets that has external modem.
+ * Enable device command should be sent to modem only after
+ * enabling voice call mixer controls
+ */
+ if (usecase->type == VOICE_CALL)
+ status = platform_switch_voice_call_usecase_route_post(adev->platform,
+ out_snd_device,
+ in_snd_device);
return status;
}
@@ -585,6 +744,9 @@
return -EINVAL;
}
+ /* Close in-call recording streams */
+ voice_check_and_stop_incall_rec_usecase(adev, in);
+
/* 1. Disable stream specific mixer controls */
disable_audio_route(adev, uc_info, true);
@@ -605,7 +767,16 @@
struct audio_usecase *uc_info;
struct audio_device *adev = in->dev;
+ in->usecase = platform_update_usecase_from_source(in->source,in->usecase);
ALOGV("%s: enter: usecase(%d)", __func__, in->usecase);
+
+ /* Check if source matches incall recording usecase criteria */
+ ret = voice_check_and_set_incall_rec_usecase(adev, in);
+ if (ret)
+ goto error_config;
+ else
+ ALOGV("%s: usecase(%d)", __func__, in->usecase);
+
in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
if (in->pcm_device_id < 0) {
ALOGE("%s: Could not find PCM device id for the usecase(%d)",
@@ -881,9 +1052,12 @@
return -EINVAL;
}
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
- adev->visualizer_stop_output != NULL)
- adev->visualizer_stop_output(out->handle);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (adev->visualizer_stop_output != NULL)
+ adev->visualizer_stop_output(out->handle, out->pcm_device_id);
+ if (adev->offload_effects_stop_output != NULL)
+ adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
+ }
/* 1. Get and set stream specific mixer controls */
disable_audio_route(adev, uc_info, true);
@@ -961,7 +1135,9 @@
compress_nonblock(out->compr, out->non_blocking);
if (adev->visualizer_start_output != NULL)
- adev->visualizer_start_output(out->handle);
+ adev->visualizer_start_output(out->handle, out->pcm_device_id);
+ if (adev->offload_effects_start_output != NULL)
+ adev->offload_effects_start_output(out->handle, out->pcm_device_id);
}
ALOGV("%s: exit", __func__);
return 0;
@@ -971,127 +1147,24 @@
return ret;
}
-static int stop_voice_call(struct audio_device *adev)
-{
- int i, ret = 0;
- struct audio_usecase *uc_info;
-
- ALOGV("%s: enter", __func__);
- adev->in_call = false;
-
- ret = platform_stop_voice_call(adev->platform);
-
- /* 1. Close the PCM devices */
- if (adev->voice_call_rx) {
- pcm_close(adev->voice_call_rx);
- adev->voice_call_rx = NULL;
- }
- if (adev->voice_call_tx) {
- pcm_close(adev->voice_call_tx);
- adev->voice_call_tx = NULL;
- }
-
- uc_info = get_usecase_from_list(adev, USECASE_VOICE_CALL);
- if (uc_info == NULL) {
- ALOGE("%s: Could not find the usecase (%d) in the list",
- __func__, USECASE_VOICE_CALL);
- return -EINVAL;
- }
-
- /* 2. Get and set stream specific mixer controls */
- disable_audio_route(adev, uc_info, true);
-
- /* 3. Disable the rx and tx devices */
- disable_snd_device(adev, uc_info->out_snd_device, false);
- disable_snd_device(adev, uc_info->in_snd_device, true);
-
- list_remove(&uc_info->list);
- free(uc_info);
-
- ALOGV("%s: exit: status(%d)", __func__, ret);
- return ret;
-}
-
-static int start_voice_call(struct audio_device *adev)
-{
- int i, ret = 0;
- struct audio_usecase *uc_info;
- int pcm_dev_rx_id, pcm_dev_tx_id;
-
- ALOGV("%s: enter", __func__);
-
- uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
- uc_info->id = USECASE_VOICE_CALL;
- uc_info->type = VOICE_CALL;
- uc_info->stream.out = adev->primary_output;
- uc_info->devices = adev->primary_output->devices;
- uc_info->in_snd_device = SND_DEVICE_NONE;
- uc_info->out_snd_device = SND_DEVICE_NONE;
-
- list_add_tail(&adev->usecase_list, &uc_info->list);
-
- select_devices(adev, USECASE_VOICE_CALL);
-
- pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
- pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
-
- if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
- ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
- __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
- ret = -EIO;
- goto error_start_voice;
- }
-
- ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
- __func__, SOUND_CARD, pcm_dev_rx_id);
- adev->voice_call_rx = pcm_open(SOUND_CARD,
- pcm_dev_rx_id,
- PCM_OUT | PCM_MONOTONIC, &pcm_config_voice_call);
- if (adev->voice_call_rx && !pcm_is_ready(adev->voice_call_rx)) {
- ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_rx));
- ret = -EIO;
- goto error_start_voice;
- }
-
- ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
- __func__, SOUND_CARD, pcm_dev_tx_id);
- adev->voice_call_tx = pcm_open(SOUND_CARD,
- pcm_dev_tx_id,
- PCM_IN, &pcm_config_voice_call);
- if (adev->voice_call_tx && !pcm_is_ready(adev->voice_call_tx)) {
- ALOGE("%s: %s", __func__, pcm_get_error(adev->voice_call_tx));
- ret = -EIO;
- goto error_start_voice;
- }
-
- /* set cached volume */
- set_voice_volume_l(adev, adev->voice_volume);
-
- pcm_start(adev->voice_call_rx);
- pcm_start(adev->voice_call_tx);
-
- ret = platform_start_voice_call(adev->platform);
- if (ret < 0) {
- ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
- goto error_start_voice;
- }
- adev->in_call = true;
- return 0;
-
-error_start_voice:
- stop_voice_call(adev);
-
- ALOGD("%s: exit: status(%d)", __func__, ret);
- return ret;
-}
-
static int check_input_parameters(uint32_t sample_rate,
audio_format_t format,
int channel_count)
{
- if (format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+ int ret = 0;
- if ((channel_count < 1) || (channel_count > 2)) return -EINVAL;
+ if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
+ !voice_extn_compress_voip_is_format_supported(format) &&
+ !audio_extn_compr_cap_format_supported(format)) ret = -EINVAL;
+
+ switch (channel_count) {
+ case 1:
+ case 2:
+ case 6:
+ break;
+ default:
+ ret = -EINVAL;
+ }
switch (sample_rate) {
case 8000:
@@ -1105,10 +1178,10 @@
case 48000:
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
static size_t get_input_buffer_size(uint32_t sample_rate,
@@ -1148,9 +1221,10 @@
{
struct stream_out *out = (struct stream_out *)stream;
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
return out->compr_config.fragment_size;
- }
+ else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
+ return voice_extn_compress_voip_out_get_buffer_size(out);
return out->config.period_size * audio_stream_frame_size(stream);
}
@@ -1181,6 +1255,13 @@
ALOGV("%s: enter: usecase(%d: %s)", __func__,
out->usecase, use_case_table[out->usecase]);
+ if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ /* Ignore standby in case of voip call because the voip output
+ * stream is closed in adev_close_output_stream()
+ */
+ ALOGV("%s: Ignore Standby in VOIP call", __func__);
+ return 0;
+ }
pthread_mutex_lock(&out->lock);
if (!out->standby) {
@@ -1302,24 +1383,32 @@
if (!out->standby)
select_devices(adev, out->usecase);
- if ((adev->mode == AUDIO_MODE_IN_CALL) && !adev->in_call &&
+ if ((adev->mode == AUDIO_MODE_IN_CALL) &&
+ !voice_is_in_call(adev) &&
(out == adev->primary_output)) {
- start_voice_call(adev);
- } else if ((adev->mode == AUDIO_MODE_IN_CALL) && adev->in_call &&
- (out == adev->primary_output)) {
- select_devices(adev, USECASE_VOICE_CALL);
+ voice_start_call(adev);
+ } else if ((adev->mode == AUDIO_MODE_IN_CALL) &&
+ voice_is_in_call(adev) &&
+ (out == adev->primary_output)) {
+ select_devices(adev, get_voice_usecase_id_from_list(adev));
}
}
- if ((adev->mode == AUDIO_MODE_NORMAL) && adev->in_call &&
+ if ((adev->mode == AUDIO_MODE_NORMAL) &&
+ voice_is_in_call(adev) &&
(out == adev->primary_output)) {
- stop_voice_call(adev);
+ voice_stop_call(adev);
}
pthread_mutex_unlock(&adev->lock);
pthread_mutex_unlock(&out->lock);
}
+ if (out == adev->primary_output) {
+ pthread_mutex_lock(&adev->lock);
+ audio_extn_set_parameters(adev, parms);
+ pthread_mutex_unlock(&adev->lock);
+ }
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
parse_compress_metadata(out, parms);
}
@@ -1360,7 +1449,11 @@
str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
str = str_parms_to_str(reply);
} else {
- str = strdup(keys);
+ voice_extn_out_get_parameters(out, query, reply);
+ str = str_parms_to_str(reply);
+ if (!strncmp(str, "", sizeof(""))) {
+ str = strdup(keys);
+ }
}
str_parms_destroy(query);
str_parms_destroy(reply);
@@ -1390,10 +1483,14 @@
out->muted = (left == 0.0f);
return 0;
} else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- const char *mixer_ctl_name = "Compress Playback Volume";
+ char mixer_ctl_name[128];
struct audio_device *adev = out->dev;
struct mixer_ctl *ctl;
+ int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+ PCM_PLAYBACK);
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Compress Playback %d Volume", pcm_device_id);
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
@@ -1420,7 +1517,10 @@
if (out->standby) {
out->standby = false;
pthread_mutex_lock(&adev->lock);
- ret = start_output_stream(out);
+ if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
+ ret = voice_extn_compress_voip_start_output_stream(out);
+ else
+ ret = start_output_stream(out);
pthread_mutex_unlock(&adev->lock);
/* ToDo: If use case is compress offload should return 0 */
if (ret != 0) {
@@ -1645,6 +1745,11 @@
{
struct stream_in *in = (struct stream_in *)stream;
+ if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
+ return voice_extn_compress_voip_in_get_buffer_size(in);
+ else if(audio_extn_compr_cap_usecase_supported(in->usecase))
+ return audio_extn_compr_cap_get_buffer_size(in->config.format);
+
return in->config.period_size * audio_stream_frame_size(stream);
}
@@ -1657,7 +1762,9 @@
static audio_format_t in_get_format(const struct audio_stream *stream)
{
- return AUDIO_FORMAT_PCM_16_BIT;
+ struct stream_in *in = (struct stream_in *)stream;
+
+ return in->format;
}
static int in_set_format(struct audio_stream *stream, audio_format_t format)
@@ -1671,6 +1778,15 @@
struct audio_device *adev = in->dev;
int status = 0;
ALOGV("%s: enter", __func__);
+
+ if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ /* Ignore standby in case of voip call because the voip input
+ * stream is closed in adev_close_input_stream()
+ */
+ ALOGV("%s: Ignore Standby in VOIP call", __func__);
+ return status;
+ }
+
pthread_mutex_lock(&in->lock);
if (!in->standby) {
pthread_mutex_lock(&adev->lock);
@@ -1738,7 +1854,21 @@
static char* in_get_parameters(const struct audio_stream *stream,
const char *keys)
{
- return strdup("");
+ struct stream_in *in = (struct stream_in *)stream;
+ struct str_parms *query = str_parms_create_str(keys);
+ char *str;
+ char value[256];
+ struct str_parms *reply = str_parms_create();
+ ALOGV("%s: enter: keys - %s", __func__, keys);
+
+ voice_extn_in_get_parameters(in, query, reply);
+
+ str = str_parms_to_str(reply);
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ ALOGV("%s: exit: returns - %s", __func__, str);
+ return str;
}
static int in_set_gain(struct audio_stream_in *stream, float gain)
@@ -1756,7 +1886,10 @@
pthread_mutex_lock(&in->lock);
if (in->standby) {
pthread_mutex_lock(&adev->lock);
- ret = start_input_stream(in);
+ if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
+ ret = voice_extn_compress_voip_start_input_stream(in);
+ else
+ ret = start_input_stream(in);
pthread_mutex_unlock(&adev->lock);
if (ret != 0) {
goto exit;
@@ -1765,14 +1898,19 @@
}
if (in->pcm) {
- ret = pcm_read(in->pcm, buffer, bytes);
+ if (audio_extn_ssr_get_enabled() && popcount(in->channel_mask) == 6)
+ ret = audio_extn_ssr_read(stream, buffer, bytes);
+ else if (audio_extn_compr_cap_usecase_supported(in->usecase))
+ ret = audio_extn_compr_cap_read(in, buffer, bytes);
+ else
+ ret = pcm_read(in->pcm, buffer, bytes);
}
/*
* Instead of writing zeroes here, we could trust the hardware
* to always provide zeroes when muted.
*/
- if (ret == 0 && adev->mic_mute)
+ if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call(adev))
memset(buffer, 0, bytes);
exit:
@@ -1813,6 +1951,12 @@
if (!in->standby)
select_devices(in->dev, in->usecase);
}
+ if (in->enable_ns != enable &&
+ (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
+ in->enable_ns = enable;
+ if (!in->standby)
+ select_devices(in->dev, in->usecase);
+ }
pthread_mutex_unlock(&in->dev->lock);
pthread_mutex_unlock(&in->lock);
@@ -1862,8 +2006,7 @@
out->handle = handle;
/* Init use case and pcm_config */
- if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
- !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+ if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT &&
out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
pthread_mutex_lock(&adev->lock);
ret = read_hdmi_channel_masks(out);
@@ -1883,10 +2026,15 @@
out->config.rate = config->sample_rate;
out->config.channels = popcount(out->channel_mask);
out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
- } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
- out->config = pcm_config_deep_buffer;
- out->sample_rate = out->config.rate;
+ } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+ (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) &&
+ (voice_extn_compress_voip_is_config_supported(config))) {
+ ret = voice_extn_compress_voip_open_output_stream(out);
+ if (ret != 0) {
+ ALOGE("%s: Compress voip output cannot be opened, error:%d",
+ __func__, ret);
+ goto error_open;
+ }
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
@@ -1894,7 +2042,8 @@
ret = -EINVAL;
goto error_open;
}
- if (!is_supported_format(config->offload_info.format)) {
+ if (!is_supported_format(config->offload_info.format) &&
+ !audio_extn_dolby_is_supported_format(config->offload_info.format)) {
ALOGE("%s: Unsupported audio format", __func__);
ret = -EINVAL;
goto error_open;
@@ -1917,7 +2066,11 @@
out->stream.drain = out_drain;
out->stream.flush = out_flush;
- out->compr_config.codec->id =
+ if (audio_extn_dolby_is_supported_format(config->offload_info.format))
+ out->compr_config.codec->id =
+ audio_extn_dolby_get_snd_codec_id(config->offload_info.format);
+ else
+ out->compr_config.codec->id =
get_snd_codec_id(config->offload_info.format);
out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
@@ -1937,10 +2090,31 @@
ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
__func__, config->offload_info.version,
config->offload_info.bit_rate);
- } else {
+
+ if (audio_extn_dolby_is_supported_format(out->format)) {
+ ret = audio_extn_dolby_set_DMID(adev);
+ if (ret != 0) {
+ ALOGE("%s: Dolby DMID cannot be set error:%d",
+ __func__, ret);
+ goto error_open;
+ }
+ }
+
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
+ ret = voice_check_and_set_incall_music_usecase(adev, out);
+ if (ret != 0) {
+ ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
+ __func__, ret);
+ goto error_open;
+ }
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
out->config = pcm_config_low_latency;
out->sample_rate = out->config.rate;
+ } else {
+ out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+ out->config = pcm_config_deep_buffer;
+ out->sample_rate = out->config.rate;
}
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
@@ -2009,9 +2183,18 @@
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
+ int ret = 0;
ALOGV("%s: enter", __func__);
- out_standby(&stream->common);
+ if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ ret = voice_extn_compress_voip_close_output_stream(&stream->common);
+ if(ret != 0)
+ ALOGE("%s: Compress voip output cannot be closed, error:%d",
+ __func__, ret);
+ }
+ else
+ out_standby(&stream->common);
+
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
destroy_offload_callback_thread(out);
@@ -2033,33 +2216,13 @@
int val;
int ret;
- ALOGV("%s: enter: %s", __func__, kvpairs);
+ ALOGD("%s: enter: %s", __func__, kvpairs);
+ pthread_mutex_lock(&adev->lock);
parms = str_parms_create_str(kvpairs);
- ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
- if (ret >= 0) {
- int tty_mode;
- if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
- tty_mode = TTY_MODE_OFF;
- else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
- tty_mode = TTY_MODE_VCO;
- else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
- tty_mode = TTY_MODE_HCO;
- else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
- tty_mode = TTY_MODE_FULL;
- else
- return -EINVAL;
-
- pthread_mutex_lock(&adev->lock);
- if (tty_mode != adev->tty_mode) {
- adev->tty_mode = tty_mode;
- adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
- if (adev->in_call)
- select_devices(adev, USECASE_VOICE_CALL);
- }
- pthread_mutex_unlock(&adev->lock);
- }
+ voice_set_parameters(adev, parms);
+ platform_set_parameters(adev->platform, parms);
ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
if (ret >= 0) {
@@ -2097,7 +2260,6 @@
default:
ALOGE("%s: unexpected rotation of %d", __func__, val);
}
- pthread_mutex_lock(&adev->lock);
if (adev->speaker_lr_swap != reverse_speakers) {
adev->speaker_lr_swap = reverse_speakers;
// only update the selected device if there is active pcm playback
@@ -2111,10 +2273,12 @@
}
}
}
- pthread_mutex_unlock(&adev->lock);
}
+ audio_extn_set_parameters(adev, parms);
str_parms_destroy(parms);
+
+ pthread_mutex_unlock(&adev->lock);
ALOGV("%s: exit with code(%d)", __func__, ret);
return ret;
}
@@ -2122,7 +2286,23 @@
static char* adev_get_parameters(const struct audio_hw_device *dev,
const char *keys)
{
- return strdup("");
+ struct audio_device *adev = (struct audio_device *)dev;
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys);
+ char *str;
+
+ pthread_mutex_lock(&adev->lock);
+
+ audio_extn_get_parameters(adev, query, reply);
+ voice_extn_get_parameters(adev, query, reply);
+ platform_get_parameters(adev->platform, query, reply);
+ str = str_parms_to_str(reply);
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ pthread_mutex_unlock(&adev->lock);
+ ALOGV("%s: exit: returns - %s", __func__, str);
+ return str;
}
static int adev_init_check(const struct audio_hw_device *dev)
@@ -2130,38 +2310,13 @@
return 0;
}
-/* always called with adev lock held */
-static int set_voice_volume_l(struct audio_device *adev, float volume)
-{
- int vol, err = 0;
-
- if (adev->mode == AUDIO_MODE_IN_CALL) {
- if (volume < 0.0) {
- volume = 0.0;
- } else if (volume > 1.0) {
- volume = 1.0;
- }
-
- vol = lrint(volume * 100.0);
-
- // Voice volume levels from android are mapped to driver volume levels as follows.
- // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
- // So adjust the volume to get the correct volume index in driver
- vol = 100 - vol;
-
- err = platform_set_voice_volume(adev->platform, vol);
- }
- return err;
-}
-
static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
{
int ret;
struct audio_device *adev = (struct audio_device *)dev;
pthread_mutex_lock(&adev->lock);
/* cache volume */
- adev->voice_volume = volume;
- ret = set_voice_volume_l(adev, adev->voice_volume);
+ ret = voice_set_volume(adev, volume);
pthread_mutex_unlock(&adev->lock);
return ret;
}
@@ -2190,9 +2345,9 @@
static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
{
struct audio_device *adev = (struct audio_device *)dev;
-
pthread_mutex_lock(&adev->lock);
if (adev->mode != mode) {
+ ALOGD("%s mode %d\n", __func__, mode);
adev->mode = mode;
}
pthread_mutex_unlock(&adev->lock);
@@ -2201,23 +2356,19 @@
static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
{
- struct audio_device *adev = (struct audio_device *)dev;
- int err = 0;
+ int ret;
pthread_mutex_lock(&adev->lock);
- adev->mic_mute = state;
-
- err = platform_set_mic_mute(adev->platform, state);
+ ALOGD("%s state %d\n", __func__, state);
+ ret = voice_set_mic_mute((struct audio_device *)dev, state);
pthread_mutex_unlock(&adev->lock);
- return err;
+
+ return ret;
}
static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
{
- struct audio_device *adev = (struct audio_device *)dev;
-
- *state = adev->mic_mute;
-
+ *state = voice_get_mic_mute((struct audio_device *)dev);
return 0;
}
@@ -2237,7 +2388,7 @@
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_in *in;
- int ret, buffer_size, frame_size;
+ int ret = 0, buffer_size, frame_size;
int channel_count = popcount(config->channel_mask);
ALOGV("%s: enter", __func__);
@@ -2272,18 +2423,44 @@
/* Update config params with the requested sample rate and channels */
in->usecase = USECASE_AUDIO_RECORD;
in->config = pcm_config_audio_capture;
- in->config.channels = channel_count;
in->config.rate = config->sample_rate;
+ in->format = config->format;
- frame_size = audio_stream_frame_size((struct audio_stream *)in);
- buffer_size = get_input_buffer_size(config->sample_rate,
- config->format,
- channel_count);
- in->config.period_size = buffer_size / frame_size;
+ if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+ (voice_extn_compress_voip_is_config_supported(config))) {
+ ret = voice_extn_compress_voip_open_input_stream(in);
+ if (ret != 0)
+ {
+ ALOGE("%s: Compress voip input cannot be opened, error:%d",
+ __func__, ret);
+ goto err_open;
+ }
+ } else if (channel_count == 6) {
+ if(audio_extn_ssr_get_enabled()) {
+ if(audio_extn_ssr_init(adev, in)) {
+ ALOGE("%s: audio_extn_ssr_init failed", __func__);
+ ret = -EINVAL;
+ goto err_open;
+ }
+ } else {
+ ret = -EINVAL;
+ goto err_open;
+ }
+ } else if (audio_extn_compr_cap_enabled() &&
+ audio_extn_compr_cap_format_supported(config->format)) {
+ audio_extn_compr_cap_init(adev, in);
+ } else {
+ in->config.channels = channel_count;
+ frame_size = audio_stream_frame_size((struct audio_stream *)in);
+ buffer_size = get_input_buffer_size(config->sample_rate,
+ config->format,
+ channel_count);
+ in->config.period_size = buffer_size / frame_size;
+ }
*stream_in = &in->stream;
ALOGV("%s: exit", __func__);
- return 0;
+ return ret;
err_open:
free(in);
@@ -2294,11 +2471,26 @@
static void adev_close_input_stream(struct audio_hw_device *dev,
struct audio_stream_in *stream)
{
+ int ret;
+ struct stream_in *in = (struct stream_in *)stream;
ALOGV("%s", __func__);
- in_standby(&stream->common);
+ if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ ret = voice_extn_compress_voip_close_input_stream(&stream->common);
+ if (ret != 0)
+ ALOGE("%s: Compress voip input cannot be closed, error:%d",
+ __func__, ret);
+ } else
+ in_standby(&stream->common);
+
+ if (audio_extn_ssr_get_enabled() && (popcount(in->channel_mask) == 6)) {
+ audio_extn_ssr_deinit();
+ }
free(stream);
+ if(audio_extn_compr_cap_enabled() &&
+ audio_extn_compr_cap_format_supported(in->config.format))
+ audio_extn_compr_cap_deinit();
return;
}
@@ -2310,22 +2502,42 @@
static int adev_close(hw_device_t *device)
{
struct audio_device *adev = (struct audio_device *)device;
- audio_route_free(adev->audio_route);
- free(adev->snd_dev_ref_cnt);
- platform_deinit(adev->platform);
- free(device);
+
+ if (!adev)
+ return 0;
+
+ pthread_mutex_lock(&adev_init_lock);
+
+ if ((--audio_device_ref_count) == 0) {
+ audio_extn_listen_deinit(adev);
+ audio_route_free(adev->audio_route);
+ free(adev->snd_dev_ref_cnt);
+ platform_deinit(adev->platform);
+ free(device);
+ adev = NULL;
+ }
+ pthread_mutex_unlock(&adev_init_lock);
return 0;
}
static int adev_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
- struct audio_device *adev;
int i, ret;
ALOGD("%s: enter", __func__);
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
+ pthread_mutex_lock(&adev_init_lock);
+ if (audio_device_ref_count != 0){
+ *device = &adev->device.common;
+ audio_device_ref_count++;
+ ALOGD("%s: returning existing instance of adev", __func__);
+ ALOGD("%s: exit", __func__);
+ pthread_mutex_unlock(&adev_init_lock);
+ return 0;
+ }
+
adev = calloc(1, sizeof(struct audio_device));
adev->device.common.tag = HARDWARE_DEVICE_TAG;
@@ -2352,22 +2564,16 @@
adev->device.dump = adev_dump;
/* Set the default route before the PCM stream is opened */
- pthread_mutex_lock(&adev->lock);
adev->mode = AUDIO_MODE_NORMAL;
adev->active_input = NULL;
adev->primary_output = NULL;
adev->out_device = AUDIO_DEVICE_NONE;
- adev->voice_call_rx = NULL;
- adev->voice_call_tx = NULL;
- adev->voice_volume = 1.0f;
- adev->tty_mode = TTY_MODE_OFF;
adev->bluetooth_nrec = true;
- adev->in_call = false;
adev->acdb_settings = TTY_MODE_OFF;
/* adev->cur_hdmi_channels = 0; by calloc() */
adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
+ voice_init(adev);
list_init(&adev->usecase_list);
- pthread_mutex_unlock(&adev->lock);
/* Loads platform specific libraries dynamically */
adev->platform = platform_init(adev);
@@ -2386,16 +2592,37 @@
} else {
ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
adev->visualizer_start_output =
- (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
"visualizer_hal_start_output");
adev->visualizer_stop_output =
- (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
"visualizer_hal_stop_output");
}
}
+ audio_extn_listen_init(adev, SOUND_CARD);
+
+ if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
+ adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
+ if (adev->offload_effects_lib == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__,
+ OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__,
+ OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+ adev->offload_effects_start_output =
+ (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+ "offload_effects_bundle_hal_start_output");
+ adev->offload_effects_stop_output =
+ (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+ "offload_effects_bundle_hal_stop_output");
+ }
+ }
*device = &adev->device.common;
+ audio_device_ref_count++;
+ pthread_mutex_unlock(&adev_init_lock);
+
ALOGV("%s: exit", __func__);
return 0;
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 0da4324..0904137 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,16 +22,18 @@
#include <cutils/list.h>
#include <hardware/audio.h>
-
#include <tinyalsa/asoundlib.h>
#include <tinycompress/tinycompress.h>
#include <audio_route/audio_route.h>
+#include "voice.h"
#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
/* Flags used to initialize acdb_settings variable that goes to ACDB library */
#define DMIC_FLAG 0x00000002
+#define QMIC_FLAG 0x00000004
#define TTY_MODE_OFF 0x00000010
#define TTY_MODE_FULL 0x00000020
#define TTY_MODE_VCO 0x00000040
@@ -54,12 +59,37 @@
USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
USECASE_AUDIO_PLAYBACK_MULTI_CH,
USECASE_AUDIO_PLAYBACK_OFFLOAD,
+
+ /* FM usecase */
+ USECASE_AUDIO_PLAYBACK_FM,
+
+ /* HFP Use case*/
+ USECASE_AUDIO_HFP_SCO,
/* Capture usecases */
USECASE_AUDIO_RECORD,
+ USECASE_AUDIO_RECORD_COMPRESS,
USECASE_AUDIO_RECORD_LOW_LATENCY,
+ USECASE_AUDIO_RECORD_FM_VIRTUAL,
+ /* Voice usecase */
USECASE_VOICE_CALL,
+
+ /* Voice extension usecases */
+ USECASE_VOICE2_CALL,
+ USECASE_VOLTE_CALL,
+ USECASE_QCHAT_CALL,
+ USECASE_COMPRESS_VOIP_CALL,
+
+ USECASE_INCALL_REC_UPLINK,
+ USECASE_INCALL_REC_DOWNLINK,
+ USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
+
+ USECASE_INCALL_MUSIC_UPLINK,
+ USECASE_INCALL_MUSIC_UPLINK2,
+
+ USECASE_AUDIO_SPKR_CALIB_RX,
+ USECASE_AUDIO_SPKR_CALIB_TX,
AUDIO_USECASE_MAX
} audio_usecase_t;
@@ -143,6 +173,8 @@
audio_channel_mask_t channel_mask;
audio_usecase_t usecase;
bool enable_aec;
+ bool enable_ns;
+ audio_format_t format;
struct audio_device *dev;
};
@@ -150,7 +182,9 @@
typedef enum {
PCM_PLAYBACK,
PCM_CAPTURE,
- VOICE_CALL
+ VOICE_CALL,
+ VOIP_CALL,
+ PCM_HFP_CALL
} usecase_type_t;
union stream_ptr {
@@ -176,28 +210,42 @@
audio_devices_t out_device;
struct stream_in *active_input;
struct stream_out *primary_output;
- int in_call;
- float voice_volume;
- bool mic_mute;
- int tty_mode;
bool bluetooth_nrec;
bool screen_off;
- struct pcm *voice_call_rx;
- struct pcm *voice_call_tx;
int *snd_dev_ref_cnt;
struct listnode usecase_list;
struct audio_route *audio_route;
int acdb_settings;
bool speaker_lr_swap;
+ struct voice voice;
unsigned int cur_hdmi_channels;
void *platform;
void *visualizer_lib;
- int (*visualizer_start_output)(audio_io_handle_t);
- int (*visualizer_stop_output)(audio_io_handle_t);
+ int (*visualizer_start_output)(audio_io_handle_t, int);
+ int (*visualizer_stop_output)(audio_io_handle_t, int);
+ void *offload_effects_lib;
+ int (*offload_effects_start_output)(audio_io_handle_t, int);
+ int (*offload_effects_stop_output)(audio_io_handle_t, int);
};
+int select_devices(struct audio_device *adev,
+ audio_usecase_t uc_id);
+int disable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer);
+int disable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer);
+int enable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer);
+int enable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer);
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+ audio_usecase_t uc_id);
/*
* NOTE: when multiple mutexes have to be acquired, always take the
* stream_in or stream_out mutex first, followed by the audio_device mutex.
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index b200e27..298c60d 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,10 +32,6 @@
#define LIB_ACDB_LOADER "libacdbloader.so"
#define LIB_CSD_CLIENT "libcsd-client.so"
-#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */
-#define DUALMIC_CONFIG_ENDFIRE 1
-#define DUALMIC_CONFIG_BROADSIDE 2
-
/*
* This is the sysfs path for the HDMI audio data block
*/
@@ -74,14 +73,17 @@
typedef int (*csd_stop_voice_t)();
-/* Audio calibration related functions */
struct platform_data {
struct audio_device *adev;
bool fluence_in_spkr_mode;
bool fluence_in_voice_call;
bool fluence_in_voice_rec;
+ int fluence_type;
int dualmic_config;
+ void *hw_info;
+
+ /* Audio calibration related functions */
void *acdb_handle;
acdb_init_t acdb_init;
acdb_deallocate_t acdb_deallocate;
@@ -123,7 +125,6 @@
[SND_DEVICE_OUT_HDMI] = "hdmi",
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
[SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
- [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus",
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
@@ -140,19 +141,14 @@
[SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
[SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
[SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
- [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef",
- [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs",
- [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus",
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef",
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs",
+ [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
[SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef",
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs",
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence",
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence",
+ [SND_DEVICE_IN_VOICE_REC_DMIC] = "voice-rec-dmic-ef",
+ [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
};
/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
@@ -168,7 +164,6 @@
[SND_DEVICE_OUT_HDMI] = 18,
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
[SND_DEVICE_OUT_BT_SCO] = 22,
- [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 81,
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
@@ -184,51 +179,20 @@
[SND_DEVICE_IN_HDMI_MIC] = 4,
[SND_DEVICE_IN_BT_SCO_MIC] = 21,
[SND_DEVICE_IN_CAMCORDER_MIC] = 61,
- [SND_DEVICE_IN_VOICE_DMIC_EF] = 6,
- [SND_DEVICE_IN_VOICE_DMIC_BS] = 5,
- [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 91,
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 13,
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12,
+ [SND_DEVICE_IN_VOICE_DMIC] = 6,
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 13,
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
[SND_DEVICE_IN_VOICE_REC_MIC] = 62,
/* TODO: Update with proper acdb ids */
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62,
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62,
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6,
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5,
+ [SND_DEVICE_IN_VOICE_REC_DMIC] = 62,
+ [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 6,
};
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
-static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
-static bool is_tmus = false;
-
-static void check_operator()
-{
- char value[PROPERTY_VALUE_MAX];
- int mccmnc;
- property_get("gsm.sim.operator.numeric",value,"0");
- mccmnc = atoi(value);
- ALOGD("%s: tmus mccmnc %d", __func__, mccmnc);
- switch(mccmnc) {
- /* TMUS MCC(310), MNC(490, 260, 026) */
- case 310490:
- case 310260:
- case 310026:
- is_tmus = true;
- break;
- }
-}
-
-bool is_operator_tmus()
-{
- pthread_once(&check_op_once_ctl, check_operator);
- return is_tmus;
-}
-
static int set_echo_reference(struct mixer *mixer, const char* ec_ref)
{
struct mixer_ctl *ctl;
@@ -251,6 +215,7 @@
char baseband[PROPERTY_VALUE_MAX];
char value[PROPERTY_VALUE_MAX];
struct platform_data *my_data;
+ const char *snd_card_name;
adev->mixer = mixer_open(MIXER_CARD);
@@ -267,34 +232,40 @@
my_data = calloc(1, sizeof(struct platform_data));
+ snd_card_name = mixer_get_name(adev->mixer);
+ my_data->hw_info = hw_info_init(snd_card_name);
+ if (!my_data->hw_info) {
+ ALOGE("%s: Failed to init hardware info", __func__);
+ }
+
my_data->adev = adev;
- my_data->dualmic_config = DUALMIC_CONFIG_NONE;
my_data->fluence_in_spkr_mode = false;
my_data->fluence_in_voice_call = false;
my_data->fluence_in_voice_rec = false;
+ my_data->fluence_type = FLUENCE_NONE;
- property_get("persist.audio.dualmic.config",value,"");
- if (!strcmp("broadside", value)) {
- my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE;
- adev->acdb_settings |= DMIC_FLAG;
- } else if (!strcmp("endfire", value)) {
- my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE;
- adev->acdb_settings |= DMIC_FLAG;
+ property_get("ro.qc.sdk.audio.fluencetype", value, "");
+ if (!strncmp("fluencepro", value, sizeof("fluencepro"))) {
+ my_data->fluence_type = FLUENCE_QUAD_MIC;
+ } else if (!strncmp("fluence", value, sizeof("fluence"))) {
+ my_data->fluence_type = FLUENCE_DUAL_MIC;
+ } else {
+ my_data->fluence_type = FLUENCE_NONE;
}
- if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ if (my_data->fluence_type != FLUENCE_NONE) {
property_get("persist.audio.fluence.voicecall",value,"");
- if (!strcmp("true", value)) {
+ if (!strncmp("true", value, sizeof("true"))) {
my_data->fluence_in_voice_call = true;
}
property_get("persist.audio.fluence.voicerec",value,"");
- if (!strcmp("true", value)) {
+ if (!strncmp("true", value, sizeof("true"))) {
my_data->fluence_in_voice_rec = true;
}
property_get("persist.audio.fluence.speaker",value,"");
- if (!strcmp("true", value)) {
+ if (!strncmp("true", value, sizeof("true"))) {
my_data->fluence_in_spkr_mode = true;
}
}
@@ -364,6 +335,9 @@
void platform_deinit(void *platform)
{
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ hw_info_deinit(my_data->hw_info);
free(platform);
}
@@ -375,16 +349,36 @@
return "";
}
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+ char *device_name)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+ strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+ hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+ } else {
+ strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
{
if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
- strcat(mixer_path, " bt-sco");
+ strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
+ strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
else if(snd_device == SND_DEVICE_OUT_BT_SCO)
- strcat(mixer_path, " bt-sco");
+ strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+ else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
+ strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
else if (snd_device == SND_DEVICE_OUT_HDMI)
- strcat(mixer_path, " hdmi");
+ strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
- strcat(mixer_path, " speaker-and-hdmi");
+ strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH);
}
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
@@ -587,10 +581,7 @@
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
- if (is_operator_tmus())
- snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS;
- else
- snd_device = SND_DEVICE_OUT_HANDSET;
+ snd_device = SND_DEVICE_OUT_HANDSET;
}
if (snd_device != SND_DEVICE_NONE) {
goto exit;
@@ -686,30 +677,28 @@
}
if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
- if (my_data->fluence_in_voice_call == false) {
+ if (my_data->fluence_type == FLUENCE_NONE ||
+ my_data->fluence_in_voice_call == false) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else {
- if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- if (is_operator_tmus())
- snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS;
- else
- snd_device = SND_DEVICE_IN_VOICE_DMIC_EF;
- } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE)
- snd_device = SND_DEVICE_IN_VOICE_DMIC_BS;
- else
- snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ snd_device = SND_DEVICE_IN_VOICE_DMIC;
+ adev->acdb_settings |= DMIC_FLAG;
}
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
} else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
- if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
- my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF;
- } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
- my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS;
+ if (my_data->fluence_type != FLUENCE_NONE &&
+ my_data->fluence_in_voice_call &&
+ my_data->fluence_in_spkr_mode) {
+ if(my_data->fluence_type == FLUENCE_DUAL_MIC) {
+ adev->acdb_settings |= DMIC_FLAG;
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+ } else {
+ adev->acdb_settings |= QMIC_FLAG;
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
+ }
} else {
snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
}
@@ -721,21 +710,15 @@
}
} else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF;
- else if (my_data->fluence_in_voice_rec)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE;
- } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) {
- if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS;
- else if (my_data->fluence_in_voice_rec)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE;
- }
+ if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC;
+ else if (my_data->fluence_in_voice_rec)
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
- if (snd_device == SND_DEVICE_NONE) {
+ if (snd_device == SND_DEVICE_NONE)
snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
- }
+ else
+ adev->acdb_settings |= DMIC_FLAG;
}
} else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
@@ -884,6 +867,24 @@
return max_channels;
}
+void platform_get_parameters(void *platform, struct str_parms *query,
+ struct str_parms *reply)
+{
+ LOGE("%s: Not implemented", __func__);
+}
+
+int platform_set_parameters(void *platform, struct str_parms *parms)
+{
+ LOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
+int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id)
+{
+ LOGE("%s: Not implemented", __func__);
+ return -ENOSYS;
+}
+
/* Delay in Us */
int64_t platform_render_latency(audio_usecase_t usecase)
{
@@ -896,3 +897,14 @@
return 0;
}
}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+ ALOGV("%s: input source :%d", __func__, source);
+ return usecase;
+}
+
+bool platform_listen_update_status(snd_device_t snd_device)
+{
+ return false;
+}
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 4bc5003..e38d801 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +20,12 @@
#ifndef QCOM_AUDIO_PLATFORM_H
#define QCOM_AUDIO_PLATFORM_H
+enum {
+ FLUENCE_NONE,
+ FLUENCE_DUAL_MIC,
+ FLUENCE_QUAD_MIC
+};
+
/*
* Below are the devices for which is back end is same, SLIMBUS_0_RX.
* All these devices are handled by the internal HW codec. We can
@@ -46,7 +55,6 @@
SND_DEVICE_OUT_HDMI,
SND_DEVICE_OUT_SPEAKER_AND_HDMI,
SND_DEVICE_OUT_BT_SCO,
- SND_DEVICE_OUT_VOICE_HANDSET_TMUS,
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
@@ -69,19 +77,15 @@
SND_DEVICE_IN_HDMI_MIC,
SND_DEVICE_IN_BT_SCO_MIC,
SND_DEVICE_IN_CAMCORDER_MIC,
- SND_DEVICE_IN_VOICE_DMIC_EF,
- SND_DEVICE_IN_VOICE_DMIC_BS,
- SND_DEVICE_IN_VOICE_DMIC_EF_TMUS,
- SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF,
- SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS,
+ SND_DEVICE_IN_VOICE_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_QMIC,
SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
SND_DEVICE_IN_VOICE_REC_MIC,
- SND_DEVICE_IN_VOICE_REC_DMIC_EF,
- SND_DEVICE_IN_VOICE_REC_DMIC_BS,
- SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE,
- SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE,
+ SND_DEVICE_IN_VOICE_REC_DMIC,
+ SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -92,7 +96,7 @@
#define SOUND_CARD 0
#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
-
+#define MIXER_PATH_MAX_LENGTH 100
/*
* tinyAlsa library interprets period size as number of frames
* one frame = channel_count * sizeof (pcm sample)
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
new file mode 100644
index 0000000..58ca4dc
--- /dev/null
+++ b/hal/msm8974/hw_info.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "hardware_info"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+struct hardware_info {
+ char name[HW_INFO_ARRAY_MAX_SIZE];
+ char type[HW_INFO_ARRAY_MAX_SIZE];
+ /* variables for handling target variants */
+ uint32_t num_snd_devices;
+ char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
+ snd_device_t *snd_devices;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define LITERAL_TO_STRING(x) #x
+#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
+ " ASSERT_FATAL(" #condition ") failed.")
+
+static const snd_device_t taiko_fluid_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static const snd_device_t taiko_CDP_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t taiko_apq8084_CDP_variant_devices[] = {
+ SND_DEVICE_IN_HANDSET_MIC,
+};
+
+static const snd_device_t taiko_liquid_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_IN_SPEAKER_MIC,
+ SND_DEVICE_IN_HEADSET_MIC,
+ SND_DEVICE_IN_VOICE_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+ SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+ SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+ SND_DEVICE_IN_QUAD_MIC,
+ SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+ SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+};
+
+static const snd_device_t taiko_DB_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_IN_SPEAKER_MIC,
+ SND_DEVICE_IN_HEADSET_MIC,
+ SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t tapan_lite_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t tapan_skuf_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ /*SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,*/
+};
+
+static const snd_device_t tapan_lite_skuf_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t helicon_skuab_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static void update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card")) {
+ strlcpy(hw_info->type, "mtp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "apq8084-taiko-cdp-snd-card")) {
+ strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_apq8084_CDP_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_apq8084_CDP_variant_devices);
+ strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) {
+ strlcpy(hw_info->type , " liquid", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type));
+ hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices);
+ strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8084 device", __func__);
+ }
+}
+
+static void update_hardware_info_8974(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "msm8974-taiko-mtp-snd-card")) {
+ strlcpy(hw_info->type, " mtp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8974-taiko-cdp-snd-card")) {
+ strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices);
+ strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8974-taiko-fluid-snd-card")) {
+ strlcpy(hw_info->type, " fluid", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *) taiko_fluid_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_fluid_variant_devices);
+ strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8974-taiko-liquid-snd-card")) {
+ strlcpy(hw_info->type, " liquid", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices);
+ strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "apq8074-taiko-db-snd-card")) {
+ strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_DB_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_DB_variant_devices);
+ strlcpy(hw_info->dev_extn, "-DB", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8974 device", __func__);
+ }
+}
+
+static void update_hardware_info_8610(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "msm8x10-snd-card")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8x10-skuab-snd-card")) {
+ strlcpy(hw_info->type, "skuab", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)helicon_skuab_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(helicon_skuab_variant_devices);
+ strlcpy(hw_info->dev_extn, "-skuab", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8x10-skuaa-snd-card")) {
+ strlcpy(hw_info->type, " skuaa", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8x10 device", __func__);
+ }
+}
+
+static void update_hardware_info_8226(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "msm8226-tapan-snd-card")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8226-tapan9302-snd-card")) {
+ strlcpy(hw_info->type, "tapan_lite", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)tapan_lite_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_variant_devices);
+ strlcpy(hw_info->dev_extn, "-lite", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8226-tapan-skuf-snd-card")) {
+ strlcpy(hw_info->type, " skuf", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *) tapan_skuf_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tapan_skuf_variant_devices);
+ strlcpy(hw_info->dev_extn, "-skuf", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8226-tapan9302-skuf-snd-card")) {
+ strlcpy(hw_info->type, " tapan9302-skuf", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)tapan_lite_skuf_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_skuf_variant_devices);
+ strlcpy(hw_info->dev_extn, "-skuf-lite", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8x26 device", __func__);
+ }
+}
+
+void *hw_info_init(const char *snd_card_name)
+{
+ struct hardware_info *hw_info;
+
+ hw_info = malloc(sizeof(struct hardware_info));
+
+ if(strstr(snd_card_name, "msm8974") ||
+ strstr(snd_card_name, "apq8074")) {
+ ALOGV("8974 - variant soundcard");
+ update_hardware_info_8974(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "msm8226")) {
+ ALOGV("8x26 - variant soundcard");
+ update_hardware_info_8226(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "msm8x10")) {
+ ALOGV("8x10 - variant soundcard");
+ update_hardware_info_8610(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "apq8084")) {
+ ALOGV("8084 - variant soundcard");
+ update_hardware_info_8084(hw_info, snd_card_name);
+ } else {
+ ALOGE("%s: Unupported target %s:",__func__, snd_card_name);
+ CHECK(0);
+ free(hw_info);
+ hw_info = NULL;
+ }
+
+ return hw_info;
+}
+
+void hw_info_deinit(void *hw_info)
+{
+ struct hardware_info *my_data = (struct hardware_info*) hw_info;
+
+ if(!my_data)
+ free(my_data);
+}
+
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+ char *device_name)
+{
+ struct hardware_info *my_data = (struct hardware_info*) hw_info;
+ uint32_t i = 0;
+
+ snd_device_t *snd_devices =
+ (snd_device_t *) my_data->snd_devices;
+
+ if(snd_devices != NULL) {
+ for (i = 0; i < my_data->num_snd_devices; i++) {
+ if (snd_device == (snd_device_t)snd_devices[i]) {
+ ALOGV("extract dev_extn device %d, extn = %s",
+ (snd_device_t)snd_devices[i], my_data->dev_extn);
+ CHECK(strlcat(device_name, my_data->dev_extn,
+ DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE);
+ break;
+ }
+ }
+ }
+ ALOGD("%s : device_name = %s", __func__,device_name);
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index b5d568f..25f52d6 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,18 +25,18 @@
#include <dlfcn.h>
#include <cutils/log.h>
#include <cutils/properties.h>
+#include <cutils/str_parms.h>
#include <audio_hw.h>
#include <platform_api.h>
#include "platform.h"
+#include "audio_extn.h"
+#include "voice_extn.h"
#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
#define LIB_ACDB_LOADER "libacdbloader.so"
#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
-#define DUALMIC_CONFIG_NONE 0 /* Target does not contain 2 mics */
-#define DUALMIC_CONFIG_ENDFIRE 1
-#define DUALMIC_CONFIG_BROADSIDE 2
-
/*
* This file will have a maximum of 38 bytes:
*
@@ -51,10 +54,12 @@
#define RETRY_NUMBER 10
#define RETRY_US 500000
-#define MAX_VOL_INDEX 5
-#define MIN_VOL_INDEX 0
-#define percent_to_index(val, min, max) \
- ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
+
+#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence"
+#define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate"
+#define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable"
struct audio_block_header
{
@@ -62,34 +67,66 @@
int length;
};
+/* Audio calibration related functions */
typedef void (*acdb_deallocate_t)();
typedef int (*acdb_init_t)();
typedef void (*acdb_send_audio_cal_t)(int, int);
typedef void (*acdb_send_voice_cal_t)(int, int);
-/* Audio calibration related functions */
struct platform_data {
struct audio_device *adev;
bool fluence_in_spkr_mode;
bool fluence_in_voice_call;
bool fluence_in_voice_rec;
- int dualmic_config;
-
+ bool fluence_in_audio_rec;
+ int fluence_type;
+ int btsco_sample_rate;
+ bool slowtalk;
+ /* Audio calibration related functions */
void *acdb_handle;
acdb_init_t acdb_init;
acdb_deallocate_t acdb_deallocate;
acdb_send_audio_cal_t acdb_send_audio_cal;
acdb_send_voice_cal_t acdb_send_voice_cal;
+
+ void *hw_info;
+ struct csd_data *csd;
};
static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
- [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
- [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
- [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
- [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
- [USECASE_AUDIO_RECORD] = {0, 0},
- [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
- [USECASE_VOICE_CALL] = {2, 2},
+ [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
+ DEEP_BUFFER_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+ LOWLATENCY_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+ MULTIMEDIA2_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
+ {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
+ [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
+ [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+ LOWLATENCY_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
+ MULTIMEDIA2_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
+ [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
+ [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
+ [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
+ [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
+ [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
+ [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE},
+ [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE,
+ INCALL_MUSIC_UPLINK_PCM_DEVICE},
+ [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE,
+ INCALL_MUSIC_UPLINK2_PCM_DEVICE},
+ [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
+ [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
};
/* Array to store sound devices */
@@ -107,144 +144,140 @@
[SND_DEVICE_OUT_HDMI] = "hdmi",
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
[SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
- [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus",
+ [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+ [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
+ [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
+ [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm",
+ [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones",
+ [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones",
+ [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones",
+ [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
+ [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
+ [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
- [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
- [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
[SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
- [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "voice-speaker-mic",
- [SND_DEVICE_IN_HEADSET_MIC_AEC] = "headset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
+ [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = "headset-mic",
[SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
[SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
[SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
[SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
[SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
- [SND_DEVICE_IN_VOICE_DMIC_EF] = "voice-dmic-ef",
- [SND_DEVICE_IN_VOICE_DMIC_BS] = "voice-dmic-bs",
- [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = "voice-dmic-ef-tmus",
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = "voice-speaker-dmic-ef",
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = "voice-speaker-dmic-bs",
+ [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
[SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = "voice-rec-dmic-ef",
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = "voice-rec-dmic-bs",
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = "voice-rec-dmic-ef-fluence",
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = "voice-rec-dmic-bs-fluence",
+ [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
+ [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
+ [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+ [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
+ [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm",
+ [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic",
+ [SND_DEVICE_IN_QUAD_MIC] = "quad-mic",
+ [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
+ [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
+ [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
};
/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
static const int acdb_device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_NONE] = -1,
[SND_DEVICE_OUT_HANDSET] = 7,
- [SND_DEVICE_OUT_SPEAKER] = 15,
- [SND_DEVICE_OUT_SPEAKER_REVERSE] = 15,
+ [SND_DEVICE_OUT_SPEAKER] = 14,
+ [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
[SND_DEVICE_OUT_HEADPHONES] = 10,
[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
[SND_DEVICE_OUT_VOICE_HANDSET] = 7,
- [SND_DEVICE_OUT_VOICE_SPEAKER] = 15,
+ [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
[SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
[SND_DEVICE_OUT_HDMI] = 18,
- [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15,
+ [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
[SND_DEVICE_OUT_BT_SCO] = 22,
- [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88,
+ [SND_DEVICE_OUT_BT_SCO_WB] = 39,
[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+ [SND_DEVICE_OUT_AFE_PROXY] = 0,
+ [SND_DEVICE_OUT_USB_HEADSET] = 0,
+ [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
+ [SND_DEVICE_OUT_TRANSMISSION_FM] = 0,
+ [SND_DEVICE_OUT_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_ANC_FB_HEADSET] = 27,
+ [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
+ [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_ANC_HANDSET] = 103,
+ [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
[SND_DEVICE_IN_HANDSET_MIC] = 4,
- [SND_DEVICE_IN_SPEAKER_MIC] = 4, /* ToDo: Check if this needs to changed to 11 */
+ [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
+ [SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
+ [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
+ [SND_DEVICE_IN_HANDSET_DMIC] = 41,
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109,
+ [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110,
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111,
+ [SND_DEVICE_IN_SPEAKER_MIC] = 11,
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112,
+ [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113,
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114,
+ [SND_DEVICE_IN_SPEAKER_DMIC] = 43,
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115,
+ [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116,
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117,
[SND_DEVICE_IN_HEADSET_MIC] = 8,
- [SND_DEVICE_IN_HANDSET_MIC_AEC] = 40,
- [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 42,
- [SND_DEVICE_IN_HEADSET_MIC_AEC] = 47,
+ [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = 47,
[SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
[SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
[SND_DEVICE_IN_HDMI_MIC] = 4,
[SND_DEVICE_IN_BT_SCO_MIC] = 21,
- [SND_DEVICE_IN_CAMCORDER_MIC] = 61,
- [SND_DEVICE_IN_VOICE_DMIC_EF] = 41,
- [SND_DEVICE_IN_VOICE_DMIC_BS] = 5,
- [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 89,
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43,
- [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12,
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
+ [SND_DEVICE_IN_CAMCORDER_MIC] = 4,
+ [SND_DEVICE_IN_VOICE_DMIC] = 41,
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
[SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
[SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
- [SND_DEVICE_IN_VOICE_REC_MIC] = 62,
- /* TODO: Update with proper acdb ids */
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF] = 62,
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS] = 62,
- [SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE] = 6,
- [SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE] = 5,
+ [SND_DEVICE_IN_VOICE_REC_MIC] = 4,
+ [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
+ [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
+ [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41,
+ [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+ [SND_DEVICE_IN_CAPTURE_FM] = 0,
+ [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104,
+ [SND_DEVICE_IN_QUAD_MIC] = 46,
+ [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
+ [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
+ [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
};
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
-static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
-static bool is_tmus = false;
-
-static void check_operator()
-{
- char value[PROPERTY_VALUE_MAX];
- int mccmnc;
- property_get("gsm.sim.operator.numeric",value,"0");
- mccmnc = atoi(value);
- ALOGD("%s: tmus mccmnc %d", __func__, mccmnc);
- switch(mccmnc) {
- /* TMUS MCC(310), MNC(490, 260, 026) */
- case 310490:
- case 310260:
- case 310026:
- /* Add new TMUS MNC(800, 660, 580, 310, 270, 250, 240, 230, 220, 210, 200, 160) */
- case 310800:
- case 310660:
- case 310580:
- case 310310:
- case 310270:
- case 310250:
- case 310240:
- case 310230:
- case 310220:
- case 310210:
- case 310200:
- case 310160:
- is_tmus = true;
- break;
- }
-}
-
-bool is_operator_tmus()
-{
- pthread_once(&check_op_once_ctl, check_operator);
- return is_tmus;
-}
-
-static int set_volume_values(int type, int volume, int* values)
-{
- values[0] = volume;
- values[1] = ALL_SESSION_VSID;
-
- switch(type) {
- case VOLUME_SET:
- values[2] = DEFAULT_VOLUME_RAMP_DURATION_MS;
- break;
- case MUTE_SET:
- values[2] = DEFAULT_MUTE_RAMP_DURATION;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static int set_echo_reference(struct mixer *mixer, const char* ec_ref)
{
struct mixer_ctl *ctl;
@@ -261,11 +294,137 @@
return 0;
}
+static struct csd_data *open_csd_client()
+{
+ struct csd_data *csd = calloc(1, sizeof(struct csd_data));
+
+ csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+ if (csd->csd_client == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+ goto error;
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+ csd->deinit = (deinit_t)dlsym(csd->csd_client,
+ "csd_client_deinit");
+ if (csd->deinit == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+ dlerror());
+ goto error;
+ }
+ csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+ "csd_client_disable_device");
+ if (csd->disable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_disable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+ "csd_client_enable_device");
+ if (csd->enable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_enable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+ "csd_client_start_voice");
+ if (csd->start_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+ "csd_client_stop_voice");
+ if (csd->stop_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->volume = (volume_t)dlsym(csd->csd_client,
+ "csd_client_volume");
+ if (csd->volume == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_volume",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+ "csd_client_mic_mute");
+ if (csd->mic_mute == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+ "csd_client_slow_talk");
+ if (csd->slow_talk == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+ "csd_client_start_playback");
+ if (csd->start_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+ "csd_client_stop_playback");
+ if (csd->stop_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_record = (start_record_t)dlsym(csd->csd_client,
+ "csd_client_start_record");
+ if (csd->start_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+ "csd_client_stop_record");
+ if (csd->stop_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+ if (csd->init == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_init",
+ __func__, dlerror());
+ goto error;
+ } else {
+ csd->init();
+ }
+ }
+ return csd;
+
+error:
+ free(csd);
+ csd = NULL;
+ return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+ if (csd != NULL) {
+ csd->deinit();
+ dlclose(csd->csd_client);
+ free(csd);
+ csd = NULL;
+ }
+}
+
void *platform_init(struct audio_device *adev)
{
+ char platform[PROPERTY_VALUE_MAX];
+ char baseband[PROPERTY_VALUE_MAX];
char value[PROPERTY_VALUE_MAX];
struct platform_data *my_data;
int retry_num = 0;
+ const char *snd_card_name;
adev->mixer = mixer_open(MIXER_CARD);
@@ -280,7 +439,10 @@
return NULL;
}
- adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH);
+ if (audio_extn_read_xml(adev, MIXER_CARD, MIXER_XML_PATH,
+ MIXER_XML_PATH_AUXPCM) == -ENOSYS)
+ adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH);
+
if (!adev->audio_route) {
ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
return NULL;
@@ -288,34 +450,47 @@
my_data = calloc(1, sizeof(struct platform_data));
+ snd_card_name = mixer_get_name(adev->mixer);
+ my_data->hw_info = hw_info_init(snd_card_name);
+ if (!my_data->hw_info) {
+ ALOGE("%s: Failed to init hardware info", __func__);
+ }
+
my_data->adev = adev;
- my_data->dualmic_config = DUALMIC_CONFIG_NONE;
+ my_data->btsco_sample_rate = SAMPLE_RATE_8KHZ;
my_data->fluence_in_spkr_mode = false;
my_data->fluence_in_voice_call = false;
my_data->fluence_in_voice_rec = false;
+ my_data->fluence_in_audio_rec = false;
+ my_data->fluence_type = FLUENCE_NONE;
- property_get("persist.audio.dualmic.config",value,"");
- if (!strcmp("broadside", value)) {
- my_data->dualmic_config = DUALMIC_CONFIG_BROADSIDE;
- adev->acdb_settings |= DMIC_FLAG;
- } else if (!strcmp("endfire", value)) {
- my_data->dualmic_config = DUALMIC_CONFIG_ENDFIRE;
- adev->acdb_settings |= DMIC_FLAG;
+ property_get("ro.qc.sdk.audio.fluencetype", value, "");
+ if (!strncmp("fluencepro", value, sizeof("fluencepro"))) {
+ my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC;
+ } else if (!strncmp("fluence", value, sizeof("fluence"))) {
+ my_data->fluence_type = FLUENCE_DUAL_MIC;
+ } else {
+ my_data->fluence_type = FLUENCE_NONE;
}
- if (my_data->dualmic_config != DUALMIC_CONFIG_NONE) {
+ if (my_data->fluence_type != FLUENCE_NONE) {
property_get("persist.audio.fluence.voicecall",value,"");
- if (!strcmp("true", value)) {
+ if (!strncmp("true", value, sizeof("true"))) {
my_data->fluence_in_voice_call = true;
}
property_get("persist.audio.fluence.voicerec",value,"");
- if (!strcmp("true", value)) {
+ if (!strncmp("true", value, sizeof("true"))) {
my_data->fluence_in_voice_rec = true;
}
+ property_get("persist.audio.fluence.audiorec",value,"");
+ if (!strncmp("true", value, sizeof("true"))) {
+ my_data->fluence_in_audio_rec = true;
+ }
+
property_get("persist.audio.fluence.speaker",value,"");
- if (!strcmp("true", value)) {
+ if (!strncmp("true", value, sizeof("true"))) {
my_data->fluence_in_spkr_mode = true;
}
}
@@ -342,12 +517,36 @@
my_data->acdb_init();
}
+ /* If platform is apq8084 and baseband is MDM, load CSD Client specific
+ * symbols. Voice call is handled by MDM and apps processor talks to
+ * MDM through CSD Client
+ */
+ property_get("ro.board.platform", platform, "");
+ property_get("ro.baseband", baseband, "");
+ if (!strncmp("apq8084", platform, sizeof("apq8084")) &&
+ !strncmp("mdm", baseband, sizeof("mdm"))) {
+ my_data->csd = open_csd_client();
+ }
+
+ /* init usb */
+ audio_extn_usb_init(adev);
+
+ /* Read one time ssr property */
+ audio_extn_ssr_update_enabled(adev);
+ audio_extn_spkr_prot_init(adev);
return my_data;
}
void platform_deinit(void *platform)
{
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ hw_info_deinit(my_data->hw_info);
+ close_csd_client(my_data->csd);
+
free(platform);
+ /* deinit usb */
+ audio_extn_usb_deinit();
}
const char *platform_get_snd_device_name(snd_device_t snd_device)
@@ -358,16 +557,49 @@
return "";
}
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+ char *device_name)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+ strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+ hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+ } else {
+ strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
{
if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
- strcat(mixer_path, " bt-sco");
+ strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
+ strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
else if(snd_device == SND_DEVICE_OUT_BT_SCO)
- strcat(mixer_path, " bt-sco");
+ strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+ else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
+ strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
else if (snd_device == SND_DEVICE_OUT_HDMI)
- strcat(mixer_path, " hdmi");
+ strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
strcat(mixer_path, " speaker-and-hdmi");
+ else if (snd_device == SND_DEVICE_OUT_AFE_PROXY)
+ strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_USB_HEADSET)
+ strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)
+ strlcat(mixer_path, " speaker-and-usb-headphones",
+ MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC)
+ strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
+ strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM)
+ strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH);
}
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
@@ -406,7 +638,19 @@
int platform_switch_voice_call_device_pre(void *platform)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL &&
+ my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+ /* This must be called before disabling mixer controls on APQ side */
+ ret = my_data->csd->disable_device();
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
+ return ret;
}
int platform_switch_voice_call_device_post(void *platform,
@@ -432,14 +676,59 @@
return 0;
}
-int platform_start_voice_call(void *platform)
+int platform_switch_voice_call_usecase_route_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_rx_id, acdb_tx_id;
+ int ret = 0;
+
+ acdb_rx_id = acdb_device_table[out_snd_device];
+ acdb_tx_id = acdb_device_table[in_snd_device];
+
+ if (my_data->csd != NULL) {
+ if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+ ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+ my_data->adev->acdb_settings);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device, failed, error %d",
+ __func__, ret);
+ }
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
+ }
+ }
+ return ret;
}
-int platform_stop_voice_call(void *platform)
+int platform_start_voice_call(void *platform, uint32_t vsid)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_stop_voice_call(void *platform, uint32_t vsid)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
}
int platform_set_voice_volume(void *platform, int volume)
@@ -448,13 +737,16 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
const char *mixer_ctl_name = "Voice Rx Gain";
- int values[VOLUME_CTL_PARAM_NUM];
- int ret = 0;
+ int vol_index = 0, ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
// Voice volume levels are mapped to adsp volume levels as follows.
// 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0
// But this values don't changed in kernel. So, below change is need.
- volume = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ set_values[0] = vol_index;
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
@@ -462,18 +754,16 @@
__func__, mixer_ctl_name);
return -EINVAL;
}
- ret = set_volume_values(VOLUME_SET, volume, values);
- if (ret < 0) {
- ALOGV("%s: failed setting volume by incorrect type", __func__);
- return -EINVAL;
- }
- ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int));
- if (ret < 0) {
- ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
- return -EINVAL;
- }
+ ALOGV("Setting voice volume index: %d", set_values[0]);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
- return 0;
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->volume(ALL_SESSION_VSID, volume);
+ if (ret < 0) {
+ ALOGE("%s: csd_volume error %d", __func__, ret);
+ }
+ }
+ return ret;
}
int platform_set_mic_mute(void *platform, bool state)
@@ -482,30 +772,28 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
const char *mixer_ctl_name = "Voice Tx Mute";
- int values[VOLUME_CTL_PARAM_NUM];
int ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
- if (adev->mode == AUDIO_MODE_IN_CALL) {
- ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, mixer_ctl_name);
- return -EINVAL;
- }
- ALOGV("Setting mic mute: %d", state);
- ret = set_volume_values(MUTE_SET, state, values);
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("Setting voice mute state: %d", state);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state);
if (ret < 0) {
- ALOGV("%s: failed setting mute by incorrect type", __func__);
- return -EINVAL;
- }
- ret = mixer_ctl_set_array(ctl, values, sizeof(values)/sizeof(int));
- if (ret < 0) {
- ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
- return -EINVAL;
+ ALOGE("%s: csd_mic_mute error %d", __func__, ret);
}
}
-
- return 0;
+ return ret;
}
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
@@ -515,6 +803,10 @@
audio_mode_t mode = adev->mode;
snd_device_t snd_device = SND_DEVICE_NONE;
+ audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+ AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+ int channel_count = popcount(channel_mask);
+
ALOGV("%s: enter: output devices(%#x)", __func__, devices);
if (devices == AUDIO_DEVICE_NONE ||
devices & AUDIO_DEVICE_BIT_IN) {
@@ -522,26 +814,51 @@
goto exit;
}
- if (mode == AUDIO_MODE_IN_CALL) {
+ if ((mode == AUDIO_MODE_IN_CALL) ||
+ voice_extn_compress_voip_is_active(adev)) {
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- if (adev->tty_mode == TTY_MODE_FULL)
- snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
- else if (adev->tty_mode == TTY_MODE_VCO)
- snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
- else if (adev->tty_mode == TTY_MODE_HCO)
- snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
- else
+ if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
+ !voice_extn_compress_voip_is_active(adev)) {
+ switch (adev->voice.tty_mode) {
+ case TTY_MODE_FULL:
+ snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES;
+ break;
+ case TTY_MODE_VCO:
+ snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES;
+ break;
+ case TTY_MODE_HCO:
+ snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
+ break;
+ default:
+ ALOGE("%s: Invalid TTY mode (%#x)",
+ __func__, adev->voice.tty_mode);
+ }
+ } else if (audio_extn_get_anc_enabled()) {
+ if (audio_extn_should_use_fb_anc())
+ snd_device = SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET;
+ } else {
snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
+ }
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_OUT_BT_SCO;
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ else
+ snd_device = SND_DEVICE_OUT_BT_SCO;
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+ } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_OUT_USB_HEADSET;
+ } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+ snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
- if (is_operator_tmus())
- snd_device = SND_DEVICE_OUT_VOICE_HANDSET_TMUS;
+ if (audio_extn_should_use_handset_anc(channel_count))
+ snd_device = SND_DEVICE_OUT_ANC_HANDSET;
else
- snd_device = SND_DEVICE_OUT_HANDSET;
+ snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
}
if (snd_device != SND_DEVICE_NONE) {
goto exit;
@@ -554,10 +871,16 @@
snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
} else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_SPEAKER)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+ if (audio_extn_get_anc_enabled())
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
} else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
AUDIO_DEVICE_OUT_SPEAKER)) {
snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+ } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
} else {
ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
goto exit;
@@ -574,18 +897,38 @@
if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- snd_device = SND_DEVICE_OUT_HEADPHONES;
+ if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
+ && audio_extn_get_anc_enabled()) {
+ if (audio_extn_should_use_fb_anc())
+ snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+ else
+ snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+ }
+ else
+ snd_device = SND_DEVICE_OUT_HEADPHONES;
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
if (adev->speaker_lr_swap)
snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
else
snd_device = SND_DEVICE_OUT_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_OUT_BT_SCO;
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ else
+ snd_device = SND_DEVICE_OUT_BT_SCO;
} else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
snd_device = SND_DEVICE_OUT_HDMI ;
+ } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_OUT_USB_HEADSET;
+ } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+ snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
} else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
snd_device = SND_DEVICE_OUT_HANDSET;
+ } else if (devices & AUDIO_DEVICE_OUT_PROXY) {
+ ALOGD("%s: setting sink capability for Proxy", __func__);
+ audio_extn_set_afe_proxy_channel_mixer(adev);
+ snd_device = SND_DEVICE_OUT_AFE_PROXY;
} else {
ALOGE("%s: Unknown device(s) %#x", __func__, devices);
}
@@ -608,18 +951,17 @@
audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
snd_device_t snd_device = SND_DEVICE_NONE;
+ int channel_count = popcount(channel_mask);
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
- if (mode == AUDIO_MODE_IN_CALL) {
- if (out_device == AUDIO_DEVICE_NONE) {
- ALOGE("%s: No output device set for voice call", __func__);
- goto exit;
- }
- if (adev->tty_mode != TTY_MODE_OFF) {
+ if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+ voice_extn_compress_voip_is_active(adev))) {
+ if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
+ !voice_extn_compress_voip_is_active(adev)) {
if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- switch (adev->tty_mode) {
+ switch (adev->voice.tty_mode) {
case TTY_MODE_FULL:
snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
break;
@@ -630,37 +972,43 @@
snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
break;
default:
- ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->tty_mode);
+ ALOGE("%s: Invalid TTY mode (%#x)",
+ __func__, adev->voice.tty_mode);
}
goto exit;
}
}
if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
- if (my_data->fluence_in_voice_call == false) {
+ if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
+ audio_extn_should_use_handset_anc(channel_count)) {
+ snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
+ } else if (my_data->fluence_type == FLUENCE_NONE ||
+ my_data->fluence_in_voice_call == false) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ set_echo_reference(adev->mixer, "SLIM_RX");
} else {
- if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- if (is_operator_tmus())
- snd_device = SND_DEVICE_IN_VOICE_DMIC_EF_TMUS;
- else
- snd_device = SND_DEVICE_IN_VOICE_DMIC_EF;
- } else if(my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE)
- snd_device = SND_DEVICE_IN_VOICE_DMIC_BS;
- else
- snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ snd_device = SND_DEVICE_IN_VOICE_DMIC;
+ adev->acdb_settings |= DMIC_FLAG;
}
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ else
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
- if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
- my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF;
- } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode &&
- my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) {
- snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS;
+ if (my_data->fluence_type != FLUENCE_NONE &&
+ my_data->fluence_in_voice_call &&
+ my_data->fluence_in_spkr_mode) {
+ if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+ adev->acdb_settings |= QMIC_FLAG;
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
+ } else {
+ adev->acdb_settings |= DMIC_FLAG;
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+ }
} else {
snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
}
@@ -672,19 +1020,16 @@
}
} else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
- if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF;
- else if (my_data->fluence_in_voice_rec)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE;
- } else if (my_data->dualmic_config == DUALMIC_CONFIG_BROADSIDE) {
- if (channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS;
- else if (my_data->fluence_in_voice_rec)
- snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE;
- }
-
- if (snd_device == SND_DEVICE_NONE) {
+ if (channel_count == 2) {
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else if (adev->active_input->enable_ns)
+ snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
+ else if (my_data->fluence_type != FLUENCE_NONE &&
+ my_data->fluence_in_voice_rec) {
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else {
snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
}
}
@@ -692,18 +1037,72 @@
if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
in_device = AUDIO_DEVICE_IN_BACK_MIC;
if (adev->active_input) {
- if (adev->active_input->enable_aec) {
+ if (adev->active_input->enable_aec &&
+ adev->active_input->enable_ns) {
if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
- snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+ my_data->fluence_in_spkr_mode) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
} else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+ snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
}
set_echo_reference(adev->mixer, "SLIM_RX");
+ } else if (adev->active_input->enable_aec) {
+ if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+ } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+ }
+ set_echo_reference(adev->mixer, "SLIM_RX");
+ } else if (adev->active_input->enable_ns) {
+ if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+ } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+ }
+ set_echo_reference(adev->mixer, "NONE");
} else
set_echo_reference(adev->mixer, "NONE");
}
+ } else if (source == AUDIO_SOURCE_MIC) {
+ if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
+ channel_count == 1 ) {
+ if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
+ my_data->fluence_in_audio_rec)
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+ }
+ } else if (source == AUDIO_SOURCE_FM_RX ||
+ source == AUDIO_SOURCE_FM_RX_A2DP) {
+ snd_device = SND_DEVICE_IN_CAPTURE_FM;
} else if (source == AUDIO_SOURCE_DEFAULT) {
goto exit;
}
@@ -717,15 +1116,28 @@
!(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
!(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ if (audio_extn_ssr_get_enabled() && channel_count == 6)
+ snd_device = SND_DEVICE_IN_QUAD_MIC;
+ else if (channel_count == 2)
+ snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
+ else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
snd_device = SND_DEVICE_IN_SPEAKER_MIC;
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC;
} else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC ;
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ else
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
} else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
snd_device = SND_DEVICE_IN_HDMI_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
+ in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_FM_RX) {
+ snd_device = SND_DEVICE_IN_CAPTURE_FM;
} else {
ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
ALOGW("%s: Using default handset-mic", __func__);
@@ -737,13 +1149,22 @@
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
- snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ if (channel_count > 1)
+ snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
+ else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
- snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ else
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
} else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
snd_device = SND_DEVICE_IN_HDMI_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
} else {
ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
ALOGW("%s: Using default handset-mic", __func__);
@@ -844,6 +1265,191 @@
return max_channels;
}
+static int platform_set_slowtalk(struct platform_data *my_data, bool state)
+{
+ int ret = 0;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Slowtalk Enable";
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID};
+
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ } else {
+ ALOGV("Setting slowtalk state: %d", state);
+ ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+ my_data->slowtalk = state;
+ }
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_set_parameters(void *platform, struct str_parms *parms)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ char *str;
+ char value[32];
+ int val;
+ int ret = 0;
+
+ ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
+
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val);
+ if (ret >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO);
+ my_data->btsco_sample_rate = val;
+ if (val == SAMPLE_RATE_16KHZ) {
+ audio_route_apply_path(my_data->adev->audio_route,
+ "bt-sco-wb-samplerate");
+ audio_route_update_mixer(my_data->adev->audio_route);
+ }
+ }
+
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val);
+ if (ret >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
+ ret = platform_set_slowtalk(my_data, val);
+ if (ret)
+ ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
+ }
+
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ return ret;
+}
+
+int platform_set_incall_recording_session_id(void *platform,
+ uint32_t session_id, int rec_mode)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voc VSID";
+ int num_ctl_values;
+ int i;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ } else {
+ num_ctl_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_ctl_values; i++) {
+ if (mixer_ctl_set_value(ctl, i, session_id)) {
+ ALOGV("Error: invalid session_id: %x", session_id);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_record(ALL_SESSION_VSID, rec_mode);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_start_record failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+int platform_stop_incall_recording_usecase(void *platform)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_record(ALL_SESSION_VSID);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_stop_record failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+int platform_start_incall_music_usecase(void *platform)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_playback(ALL_SESSION_VSID);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_start_playback failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+int platform_stop_incall_music_usecase(void *platform)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_playback(ALL_SESSION_VSID);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_stop_playback failed, error %d",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
+void platform_get_parameters(void *platform,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ char *str = NULL;
+ char value[256] = {0};
+ int ret;
+ int fluence_type;
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE,
+ value, sizeof(value));
+ if (ret >= 0) {
+ if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+ strlcpy(value, "fluencepro", sizeof(value));
+ } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ strlcpy(value, "fluence", sizeof(value));
+ } else {
+ strlcpy(value, "none", sizeof(value));
+ }
+
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value);
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
+ value, sizeof(value));
+ if (ret >= 0) {
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SLOWTALK,
+ my_data->slowtalk);
+ }
+
+ ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply));
+}
+
/* Delay in Us */
int64_t platform_render_latency(audio_usecase_t usecase)
{
@@ -856,3 +1462,22 @@
return 0;
}
}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+ ALOGV("%s: input source :%d", __func__, source);
+ if(source == AUDIO_SOURCE_FM_RX_A2DP)
+ usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
+ return usecase;
+}
+
+bool platform_listen_update_status(snd_device_t snd_device)
+{
+ if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
+ (snd_device < SND_DEVICE_IN_END) &&
+ (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
+ (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+ return true;
+ else
+ return false;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index a6b3c31..8518c7d 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +20,12 @@
#ifndef QCOM_AUDIO_PLATFORM_H
#define QCOM_AUDIO_PLATFORM_H
+enum {
+ FLUENCE_NONE,
+ FLUENCE_DUAL_MIC = 0x1,
+ FLUENCE_QUAD_MIC = 0x2,
+};
+
/*
* Below are the devices for which is back end is same, SLIMBUS_0_RX.
* All these devices are handled by the internal HW codec. We can
@@ -47,10 +56,21 @@
SND_DEVICE_OUT_HDMI,
SND_DEVICE_OUT_SPEAKER_AND_HDMI,
SND_DEVICE_OUT_BT_SCO,
- SND_DEVICE_OUT_VOICE_HANDSET_TMUS,
+ SND_DEVICE_OUT_BT_SCO_WB,
SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+ SND_DEVICE_OUT_AFE_PROXY,
+ SND_DEVICE_OUT_USB_HEADSET,
+ SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+ SND_DEVICE_OUT_TRANSMISSION_FM,
+ SND_DEVICE_OUT_ANC_HEADSET,
+ SND_DEVICE_OUT_ANC_FB_HEADSET,
+ SND_DEVICE_OUT_VOICE_ANC_HEADSET,
+ SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_OUT_ANC_HANDSET,
+ SND_DEVICE_OUT_SPEAKER_PROTECTED,
SND_DEVICE_OUT_END,
/*
@@ -60,29 +80,46 @@
/* Capture devices */
SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN,
- SND_DEVICE_IN_SPEAKER_MIC,
- SND_DEVICE_IN_HEADSET_MIC,
SND_DEVICE_IN_HANDSET_MIC_AEC,
+ SND_DEVICE_IN_HANDSET_MIC_NS,
+ SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC,
+ SND_DEVICE_IN_HANDSET_DMIC_AEC,
+ SND_DEVICE_IN_HANDSET_DMIC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC_AEC_NS,
+ SND_DEVICE_IN_SPEAKER_MIC,
SND_DEVICE_IN_SPEAKER_MIC_AEC,
- SND_DEVICE_IN_HEADSET_MIC_AEC,
+ SND_DEVICE_IN_SPEAKER_MIC_NS,
+ SND_DEVICE_IN_SPEAKER_MIC_AEC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC,
+ SND_DEVICE_IN_SPEAKER_DMIC_AEC,
+ SND_DEVICE_IN_SPEAKER_DMIC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS,
+ SND_DEVICE_IN_HEADSET_MIC,
+ SND_DEVICE_IN_HEADSET_MIC_FLUENCE,
SND_DEVICE_IN_VOICE_SPEAKER_MIC,
SND_DEVICE_IN_VOICE_HEADSET_MIC,
SND_DEVICE_IN_HDMI_MIC,
SND_DEVICE_IN_BT_SCO_MIC,
+ SND_DEVICE_IN_BT_SCO_MIC_WB,
SND_DEVICE_IN_CAMCORDER_MIC,
- SND_DEVICE_IN_VOICE_DMIC_EF,
- SND_DEVICE_IN_VOICE_DMIC_BS,
- SND_DEVICE_IN_VOICE_DMIC_EF_TMUS,
- SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF,
- SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS,
+ SND_DEVICE_IN_VOICE_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_QMIC,
SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
SND_DEVICE_IN_VOICE_REC_MIC,
- SND_DEVICE_IN_VOICE_REC_DMIC_EF,
- SND_DEVICE_IN_VOICE_REC_DMIC_BS,
- SND_DEVICE_IN_VOICE_REC_DMIC_EF_FLUENCE,
- SND_DEVICE_IN_VOICE_REC_DMIC_BS_FLUENCE,
+ SND_DEVICE_IN_VOICE_REC_MIC_NS,
+ SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+ SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+ SND_DEVICE_IN_USB_HEADSET_MIC,
+ SND_DEVICE_IN_CAPTURE_FM,
+ SND_DEVICE_IN_AANC_HANDSET_MIC,
+ SND_DEVICE_IN_QUAD_MIC,
+ SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+ SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+ SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
SND_DEVICE_IN_END,
SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -94,12 +131,15 @@
#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
-#define ALL_SESSION_VSID 0xFFFFFFFF
+#define ALL_SESSION_VSID 0xFFFFFFFF
#define DEFAULT_MUTE_RAMP_DURATION 500
#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
-#define VOLUME_SET 0
-#define MUTE_SET 1
-#define VOLUME_CTL_PARAM_NUM 3
+#define MIXER_PATH_MAX_LENGTH 100
+
+#define MAX_VOL_INDEX 5
+#define MIN_VOL_INDEX 0
+#define percent_to_index(val, min, max) \
+ ((val) * ((max) - (min)) * 0.01 + (min) + .5)
/*
* tinyAlsa library interprets period size as number of frames
@@ -122,4 +162,84 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define DEVICE_NAME_MAX_SIZE 128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
+#define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
+#define MULTIMEDIA2_PCM_DEVICE 1
+#define FM_PLAYBACK_PCM_DEVICE 5
+#define FM_CAPTURE_PCM_DEVICE 6
+#define HFP_PCM_RX 5
+#define HFP_SCO_RX 35
+#define HFP_ASM_RX_TX 36
+
+#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
+#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22
+#define PLAYBACK_OFFLOAD_DEVICE 9
+#define COMPRESS_VOIP_CALL_PCM_DEVICE 3
+
+#ifdef PLATFORM_MSM8610
+#define LOWLATENCY_PCM_DEVICE 12
+#else
+#define LOWLATENCY_PCM_DEVICE 15
+#endif
+#ifdef PLATFORM_MSM8x26
+#define COMPRESS_CAPTURE_DEVICE 20
+#else
+#define COMPRESS_CAPTURE_DEVICE 19
+#endif
+
+#ifdef PLATFORM_MSM8x26
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 14
+#define VOLTE_CALL_PCM_DEVICE 17
+#define QCHAT_CALL_PCM_DEVICE 18
+#elif PLATFORM_APQ8084
+#define VOICE_CALL_PCM_DEVICE 20
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 21
+#define QCHAT_CALL_PCM_DEVICE 06
+#else
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#endif
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+/* CSD-CLIENT related functions */
+typedef int (*init_t)();
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int);
+typedef int (*mic_mute_t)(uint32_t, int);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t);
+/* CSD Client structure */
+struct csd_data {
+ void *csd_client;
+ init_t init;
+ deinit_t deinit;
+ disable_device_t disable_device;
+ enable_device_t enable_device;
+ volume_t volume;
+ mic_mute_t mic_mute;
+ slow_talk_t slow_talk;
+ start_voice_t start_voice;
+ stop_voice_t stop_voice;
+ start_playback_t start_playback;
+ stop_playback_t stop_playback;
+ start_record_t start_record;
+ stop_record_t stop_record;
+};
+
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index afd2ee4..4096ef0 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +23,8 @@
void *platform_init(struct audio_device *adev);
void platform_deinit(void *platform);
const char *platform_get_snd_device_name(snd_device_t snd_device);
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+ char *device_name);
void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
@@ -27,16 +32,29 @@
int platform_switch_voice_call_device_post(void *platform,
snd_device_t out_snd_device,
snd_device_t in_snd_device);
-int platform_start_voice_call(void *platform);
-int platform_stop_voice_call(void *platform);
+int platform_switch_voice_call_usecase_route_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device);
+int platform_start_voice_call(void *platform, uint32_t vsid);
+int platform_stop_voice_call(void *platform, uint32_t vsid);
int platform_set_voice_volume(void *platform, int volume);
int platform_set_mic_mute(void *platform, bool state);
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
int platform_set_hdmi_channels(void *platform, int channel_count);
int platform_edid_get_max_channels(void *platform);
-
+void platform_get_parameters(void *platform, struct str_parms *query,
+ struct str_parms *reply);
+int platform_set_parameters(void *platform, struct str_parms *parms);
+int platform_set_incall_recording_session_id(void *platform, uint32_t session_id,
+ int rec_mode);
+int platform_stop_incall_recording_usecase(void *platform);
+int platform_start_incall_music_usecase(void *platform);
+int platform_stop_incall_music_usecase(void *platform);
/* returns the latency for a usecase in Us */
int64_t platform_render_latency(audio_usecase_t usecase);
+int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
+
+bool platform_listen_update_status(snd_device_t snd_device);
#endif // QCOM_AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
new file mode 100644
index 0000000..25b53d4
--- /dev/null
+++ b/hal/voice.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 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 "voice"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+
+#include "audio_hw.h"
+#include "voice.h"
+#include "voice_extn/voice_extn.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "audio_extn.h"
+
+struct pcm_config pcm_config_voice_call = {
+ .channels = 1,
+ .rate = 8000,
+ .period_size = 160,
+ .period_count = 2,
+ .format = PCM_FORMAT_S16_LE,
+};
+
+extern const char * const use_case_table[AUDIO_USECASE_MAX];
+
+static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev,
+ audio_usecase_t usecase_id)
+{
+ struct voice_session *session = NULL;
+ int ret = 0;
+
+ ret = voice_extn_get_session_from_use_case(adev, usecase_id, &session);
+ if (ret == -ENOSYS) {
+ session = &adev->voice.session[VOICE_SESS_IDX];
+ }
+
+ return session;
+}
+
+int stop_call(struct audio_device *adev, audio_usecase_t usecase_id)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ struct voice_session *session = NULL;
+
+ ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
+
+ session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+ session->state.current = CALL_INACTIVE;
+
+ ret = platform_stop_voice_call(adev->platform, session->vsid);
+
+ /* 1. Close the PCM devices */
+ if (session->pcm_rx) {
+ pcm_close(session->pcm_rx);
+ session->pcm_rx = NULL;
+ }
+ if (session->pcm_tx) {
+ pcm_close(session->pcm_tx);
+ session->pcm_tx = NULL;
+ }
+
+ uc_info = get_usecase_from_list(adev, usecase_id);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, usecase_id);
+ return -EINVAL;
+ }
+
+ /* 2. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device, false);
+ disable_snd_device(adev, uc_info->in_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int start_call(struct audio_device *adev, audio_usecase_t usecase_id)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ int pcm_dev_rx_id, pcm_dev_tx_id;
+ struct voice_session *session = NULL;
+ struct pcm_config voice_config = pcm_config_voice_call;
+
+ ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
+
+ session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = usecase_id;
+ uc_info->type = VOICE_CALL;
+ uc_info->stream.out = adev->primary_output;
+ uc_info->devices = adev->primary_output->devices;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, usecase_id);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
+
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+ ret = -EIO;
+ goto error_start_voice;
+ }
+
+ ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_rx_id);
+ session->pcm_rx = pcm_open(SOUND_CARD,
+ pcm_dev_rx_id,
+ PCM_OUT, &voice_config);
+ if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx));
+ ret = -EIO;
+ goto error_start_voice;
+ }
+
+ ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ session->pcm_tx = pcm_open(SOUND_CARD,
+ pcm_dev_tx_id,
+ PCM_IN, &voice_config);
+ if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
+ ret = -EIO;
+ goto error_start_voice;
+ }
+ pcm_start(session->pcm_rx);
+ pcm_start(session->pcm_tx);
+
+ voice_set_volume(adev, adev->voice.volume);
+
+ ret = platform_start_voice_call(adev->platform, session->vsid);
+ if (ret < 0) {
+ ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
+ goto error_start_voice;
+ }
+
+ session->state.current = CALL_ACTIVE;
+ return 0;
+
+error_start_voice:
+ stop_call(adev, usecase_id);
+
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+bool voice_is_in_call(struct audio_device *adev)
+{
+ bool in_call = false;
+ int ret = 0;
+
+ ret = voice_extn_is_in_call(adev, &in_call);
+ if (ret == -ENOSYS) {
+ in_call = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
+ }
+
+ return in_call;
+}
+
+uint32_t voice_get_active_session_id(struct audio_device *adev)
+{
+ int ret = 0;
+ uint32_t session_id;
+
+ ret = voice_extn_get_active_session_id(adev, &session_id);
+ if (ret == -ENOSYS) {
+ session_id = VOICE_VSID;
+ }
+ return session_id;
+}
+
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in)
+{
+ int ret = 0;
+ uint32_t session_id;
+ int usecase_id;
+ int rec_mode = INCALL_REC_NONE;
+
+ if (voice_is_in_call(adev)) {
+ switch (in->source) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ in->usecase = USECASE_INCALL_REC_UPLINK;
+ rec_mode = INCALL_REC_UPLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ in->usecase = USECASE_INCALL_REC_DOWNLINK;
+ rec_mode = INCALL_REC_DOWNLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_CALL:
+ in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK;
+ rec_mode = INCALL_REC_UPLINK_AND_DOWNLINK;
+ break;
+ default:
+ ALOGV("%s: Source type %d doesnt match incall recording criteria",
+ __func__, in->source);
+ return ret;
+ }
+
+ session_id = voice_get_active_session_id(adev);
+ ret = platform_set_incall_recording_session_id(adev->platform,
+ session_id, rec_mode);
+ ALOGV("%s: Update usecase to %d",__func__, in->usecase);
+ } else {
+ ALOGV("%s: voice call not active", __func__);
+ }
+
+ return ret;
+}
+
+int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in)
+{
+ int ret = 0;
+
+ if (in->source == AUDIO_SOURCE_VOICE_UPLINK ||
+ in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+ in->source == AUDIO_SOURCE_VOICE_CALL) {
+ ret = platform_stop_incall_recording_usecase(adev->platform);
+ ALOGV("%s: Stop In-call recording", __func__);
+ }
+
+ return ret;
+}
+
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out)
+{
+ int ret = 0;
+
+ ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
+ if (ret == -ENOSYS) {
+ /* Incall music delivery is used only for LCH call state */
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int voice_set_mic_mute(struct audio_device *adev, bool state)
+{
+ int err = 0;
+
+ adev->voice.mic_mute = state;
+ if (adev->mode == AUDIO_MODE_IN_CALL)
+ err = platform_set_mic_mute(adev->platform, state);
+ if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
+ err = voice_extn_compress_voip_set_mic_mute(adev, state);
+
+ return err;
+}
+
+bool voice_get_mic_mute(struct audio_device *adev)
+{
+ return adev->voice.mic_mute;
+}
+
+int voice_set_volume(struct audio_device *adev, float volume)
+{
+ int vol, err = 0;
+
+ adev->voice.volume = volume;
+ if (adev->mode == AUDIO_MODE_IN_CALL) {
+ if (volume < 0.0) {
+ volume = 0.0;
+ } else if (volume > 1.0) {
+ volume = 1.0;
+ }
+
+ vol = lrint(volume * 100.0);
+
+ // Voice volume levels from android are mapped to driver volume levels as follows.
+ // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
+ // So adjust the volume to get the correct volume index in driver
+ vol = 100 - vol;
+
+ err = platform_set_voice_volume(adev->platform, vol);
+ }
+ if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
+ err = voice_extn_compress_voip_set_volume(adev, volume);
+
+
+ return err;
+}
+
+int voice_start_call(struct audio_device *adev)
+{
+ int ret = 0;
+
+ ret = voice_extn_start_call(adev);
+ if (ret == -ENOSYS) {
+ ret = start_call(adev, USECASE_VOICE_CALL);
+ }
+
+ return ret;
+}
+
+int voice_stop_call(struct audio_device *adev)
+{
+ int ret = 0;
+
+ ret = voice_extn_stop_call(adev);
+ if (ret == -ENOSYS) {
+ ret = stop_call(adev, USECASE_VOICE_CALL);
+ }
+
+ return ret;
+}
+
+int voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+ char *str;
+ char value[32];
+ int val;
+ int ret = 0;
+
+ ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
+
+ voice_extn_set_parameters(adev, parms);
+ voice_extn_compress_voip_set_parameters(adev, parms);
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
+ if (ret >= 0) {
+ int tty_mode;
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE);
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
+ tty_mode = TTY_MODE_OFF;
+ else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
+ tty_mode = TTY_MODE_VCO;
+ else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
+ tty_mode = TTY_MODE_HCO;
+ else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
+ tty_mode = TTY_MODE_FULL;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (tty_mode != adev->voice.tty_mode) {
+ adev->voice.tty_mode = tty_mode;
+ adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
+ if (voice_is_in_call(adev))
+ //todo: what about voice2, volte and qchat usecases?
+ select_devices(adev, USECASE_VOICE_CALL);
+ }
+ }
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC,
+ value, sizeof(value));
+ if (ret >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC);
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0)
+ platform_start_incall_music_usecase(adev->platform);
+ else
+ platform_stop_incall_music_usecase(adev->platform);
+ }
+
+done:
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ return ret;
+}
+
+void voice_init(struct audio_device *adev)
+{
+ int i = 0;
+
+ memset(&adev->voice, 0, sizeof(adev->voice));
+ adev->voice.tty_mode = TTY_MODE_OFF;
+ adev->voice.volume = 1.0f;
+ adev->voice.mic_mute = false;
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ adev->voice.session[i].pcm_rx = NULL;
+ adev->voice.session[i].pcm_tx = NULL;
+ adev->voice.session[i].state.current = CALL_INACTIVE;
+ adev->voice.session[i].state.new = CALL_INACTIVE;
+ adev->voice.session[i].vsid = 0;
+ }
+
+ voice_extn_init(adev);
+}
+
+
diff --git a/hal/voice.h b/hal/voice.h
new file mode 100644
index 0000000..eeb65dc
--- /dev/null
+++ b/hal/voice.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICE_H
+#define VOICE_H
+
+#define BASE_SESS_IDX 0
+#define VOICE_SESS_IDX (BASE_SESS_IDX)
+
+#ifdef MULTI_VOICE_SESSION_ENABLED
+#define MAX_VOICE_SESSIONS 4
+#else
+#define MAX_VOICE_SESSIONS 1
+#endif
+
+#define BASE_CALL_STATE 1
+#define CALL_INACTIVE (BASE_CALL_STATE)
+#define CALL_ACTIVE (BASE_CALL_STATE + 1)
+
+#define VOICE_VSID 0x10C01000
+
+#define AUDIO_PARAMETER_KEY_INCALLMUSIC "incall_music_enabled"
+#define AUDIO_PARAMETER_VALUE_TRUE "true"
+
+struct audio_device;
+struct str_parms;
+struct stream_in;
+struct stream_out;
+
+struct call_state {
+ int current;
+ int new;
+};
+
+struct voice_session {
+ struct pcm *pcm_rx;
+ struct pcm *pcm_tx;
+ struct call_state state;
+ uint32_t vsid;
+};
+
+struct voice {
+ struct voice_session session[MAX_VOICE_SESSIONS];
+ int tty_mode;
+ bool mic_mute;
+ float volume;
+};
+
+enum {
+ INCALL_REC_NONE = -1,
+ INCALL_REC_UPLINK,
+ INCALL_REC_DOWNLINK,
+ INCALL_REC_UPLINK_AND_DOWNLINK,
+};
+
+int voice_start_call(struct audio_device *adev);
+int voice_stop_call(struct audio_device *adev);
+int voice_set_parameters(struct audio_device *adev, struct str_parms *parms);
+void voice_init(struct audio_device *adev);
+bool voice_is_in_call(struct audio_device *adev);
+int voice_set_mic_mute(struct audio_device *dev, bool state);
+bool voice_get_mic_mute(struct audio_device *dev);
+int voice_set_volume(struct audio_device *adev, float volume);
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in);
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out);
+int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
+ struct stream_in *in);
+#endif //VOICE_H
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
new file mode 100644
index 0000000..d5b0f0e
--- /dev/null
+++ b/hal/voice_extn/compress_voip.c
@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 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 "compress_voip"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+
+#include "audio_hw.h"
+#include "platform_api.h"
+#include "platform.h"
+#include "voice_extn.h"
+
+#define COMPRESS_VOIP_IO_BUF_SIZE_NB 320
+#define COMPRESS_VOIP_IO_BUF_SIZE_WB 640
+
+struct pcm_config pcm_config_voip_nb = {
+ .channels = 1,
+ .rate = 8000, /* changed when the stream is opened */
+ .period_size = COMPRESS_VOIP_IO_BUF_SIZE_NB/2,
+ .period_count = 10,
+ .format = PCM_FORMAT_S16_LE,
+};
+
+struct pcm_config pcm_config_voip_wb = {
+ .channels = 1,
+ .rate = 16000, /* changed when the stream is opened */
+ .period_size = COMPRESS_VOIP_IO_BUF_SIZE_WB/2,
+ .period_count = 10,
+ .format = PCM_FORMAT_S16_LE,
+};
+
+struct voip_data {
+ struct pcm *pcm_rx;
+ struct pcm *pcm_tx;
+ struct stream_out *out_stream;
+ int ref_count;
+};
+
+#define MODE_IS127 0x2
+#define MODE_4GV_NB 0x3
+#define MODE_4GV_WB 0x4
+#define MODE_AMR 0x5
+#define MODE_AMR_WB 0xD
+#define MODE_PCM 0xC
+#define MODE_4GV_NW 0xE
+
+#define AUDIO_PARAMETER_KEY_VOIP_RATE "voip_rate"
+#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN "evrc_rate_min"
+#define AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX "evrc_rate_max"
+#define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE "dtx_on"
+#define AUDIO_PARAMETER_VALUE_VOIP_TRUE "true"
+#define AUDIO_PARAMETER_KEY_VOIP_CHECK "voip_flag"
+
+static struct voip_data voip_data = {
+ .pcm_rx = NULL,
+ .pcm_tx = NULL,
+ .out_stream = NULL,
+ .ref_count = 0
+};
+
+static int voip_set_volume(struct audio_device *adev, int volume);
+static int voip_set_mic_mute(struct audio_device *adev, bool state);
+static int voip_set_mode(struct audio_device *adev, int format);
+static int voip_set_rate(struct audio_device *adev, int rate);
+static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate,
+ int max_rate);
+static int voip_set_dtx(struct audio_device *adev, bool enable);
+static int voip_stop_call(struct audio_device *adev);
+static int voip_start_call(struct audio_device *adev,
+ struct pcm_config *voip_config);
+
+static int audio_format_to_voip_mode(int format)
+{
+ int mode;
+
+ switch(format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ mode = MODE_PCM;
+ break;
+ case AUDIO_FORMAT_AMR_NB:
+ mode = MODE_AMR;
+ break;
+ case AUDIO_FORMAT_AMR_WB:
+ mode = MODE_AMR_WB;
+ break;
+ case AUDIO_FORMAT_EVRC:
+ mode = MODE_IS127;
+ break;
+ case AUDIO_FORMAT_EVRCB:
+ mode = MODE_4GV_NB;
+ break;
+ case AUDIO_FORMAT_EVRCWB:
+ mode = MODE_4GV_WB;
+ break;
+ case AUDIO_FORMAT_EVRCNW:
+ mode = MODE_4GV_NW;
+ break;
+ default:
+ mode = MODE_PCM;
+ }
+ return mode;
+}
+
+static int voip_set_volume(struct audio_device *adev, int volume)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voip Rx Gain";
+ int vol_index = 0;
+ uint32_t set_values[ ] = {0,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+ ALOGV("%s: enter", __func__);
+
+ /* Voice volume levels are mapped to adsp volume levels as follows.
+ * 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0
+ * But this values don't changed in kernel. So, below change is need.
+ */
+ vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ set_values[0] = vol_index;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("%s: Setting voip volume index: %d", __func__, set_values[0]);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int voip_set_mic_mute(struct audio_device *adev, bool state)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voip Tx Mute";
+ uint32_t set_values[ ] = {0,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+ ALOGV("%s: enter, state=%d", __func__, state);
+
+ if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+ }
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int voip_set_mode(struct audio_device *adev, int format)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voip Mode Config";
+ uint32_t set_values[ ] = {0};
+ int mode;
+
+ ALOGD("%s: enter, format=%d", __func__, format);
+
+ mode = audio_format_to_voip_mode(format);
+ ALOGD("%s: Derived mode = %d", __func__, mode);
+
+ set_values[0] = mode;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int voip_set_rate(struct audio_device *adev, int rate)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voip Rate Config";
+ uint32_t set_values[ ] = {0};
+
+ ALOGD("%s: enter, rate=%d", __func__, rate);
+
+ set_values[0] = rate;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int voip_set_evrc_min_max_rate(struct audio_device *adev, int min_rate,
+ int max_rate)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voip Evrc Min Max Rate Config";
+ uint32_t set_values[ ] = {0, 0};
+
+ ALOGD("%s: enter, min_rate=%d, max_rate=%d",
+ __func__, min_rate, max_rate);
+
+ set_values[0] = min_rate;
+ set_values[1] = max_rate;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int voip_set_dtx(struct audio_device *adev, bool enable)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voip Dtx Mode";
+ uint32_t set_values[ ] = {0};
+
+ ALOGD("%s: enter, enable=%d", __func__, enable);
+
+ set_values[0] = enable;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int voip_stop_call(struct audio_device *adev)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter, ref_count=%d", __func__, voip_data.ref_count);
+ voip_data.ref_count--;
+
+ if (!voip_data.ref_count) {
+ uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, USECASE_COMPRESS_VOIP_CALL);
+ return -EINVAL;
+ }
+
+ /* 1. Close the PCM devices */
+ if (voip_data.pcm_rx) {
+ pcm_close(voip_data.pcm_rx);
+ voip_data.pcm_rx = NULL;
+ }
+ if (voip_data.pcm_tx) {
+ pcm_close(voip_data.pcm_tx);
+ voip_data.pcm_tx = NULL;
+ }
+
+ /* 2. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 3. Disable the rx and tx devices */
+ disable_snd_device(adev, uc_info->out_snd_device, false);
+ disable_snd_device(adev, uc_info->in_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+ } else
+ ALOGV("%s: NO-OP because ref_count=%d", __func__, voip_data.ref_count);
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+static int voip_start_call(struct audio_device *adev,
+ struct pcm_config *voip_config)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ int pcm_dev_rx_id, pcm_dev_tx_id;
+
+ ALOGD("%s: enter", __func__);
+
+ uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+ if ((uc_info == NULL) && (voip_data.out_stream)) {
+ ALOGV("%s: voip usecase is added to the list", __func__);
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = USECASE_COMPRESS_VOIP_CALL;
+ uc_info->type = VOIP_CALL;
+ uc_info->stream.out = voip_data.out_stream;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, USECASE_COMPRESS_VOIP_CALL);
+
+ pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
+ pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
+
+ if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0) {
+ ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(%d)",
+ __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+ ret = -EIO;
+ goto error_start_voip;
+ }
+
+ ALOGD("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_rx_id);
+ voip_data.pcm_rx = pcm_open(SOUND_CARD,
+ pcm_dev_rx_id,
+ PCM_OUT, voip_config);
+ if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx));
+ pcm_close(voip_data.pcm_rx);
+ voip_data.pcm_rx = NULL;
+ ret = -EIO;
+ goto error_start_voip;
+ }
+
+ ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+ __func__, SOUND_CARD, pcm_dev_tx_id);
+ voip_data.pcm_tx = pcm_open(SOUND_CARD,
+ pcm_dev_tx_id,
+ PCM_IN, voip_config);
+ if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx));
+ pcm_close(voip_data.pcm_rx);
+ voip_data.pcm_tx = NULL;
+ if (voip_data.pcm_rx) {
+ pcm_close(voip_data.pcm_rx);
+ voip_data.pcm_rx = NULL;
+ }
+ ret = -EIO;
+ goto error_start_voip;
+ }
+ pcm_start(voip_data.pcm_rx);
+ pcm_start(voip_data.pcm_tx);
+
+ voice_extn_compress_voip_set_volume(adev, adev->voice.volume);
+
+ if (ret < 0) {
+ ALOGE("%s: error %d\n", __func__, ret);
+ goto error_start_voip;
+ }
+ voip_data.ref_count = 0;
+ }
+ else
+ ALOGV("%s: voip usecase is already enabled", __func__);
+
+ voip_data.ref_count++;
+ return 0;
+
+error_start_voip:
+ voip_stop_call(adev);
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+void voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ char *str;
+ char value[32]={0};
+ int ret, rate;
+ int min_rate, max_rate;
+ bool flag;
+
+ ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE,
+ value, sizeof(value));
+ if (ret >= 0) {
+ rate = atoi(value);
+ voip_set_rate(adev, rate);
+ voip_set_evrc_min_max_rate(adev, rate, rate);
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN,
+ value, sizeof(value));
+ if (ret >= 0) {
+ min_rate = atoi(value);
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN);
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX,
+ value, sizeof(value));
+ if (ret >= 0) {
+ max_rate = atoi(value);
+ voip_set_evrc_min_max_rate(adev, min_rate, max_rate);
+ }
+ else
+ ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__);
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE,
+ value, sizeof(value));
+ if (ret >= 0) {
+ flag = false;
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0)
+ flag = true;
+ voip_set_dtx(adev, flag);
+ }
+
+ ALOGV("%s: exit", __func__);
+}
+
+void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret, val;
+ char value[32]={0};
+
+ ALOGD("%s: enter", __func__);
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value));
+
+ if (ret >= 0) {
+ if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true);
+ else
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false);
+ }
+
+ ALOGV("%s: exit", __func__);
+}
+
+void voice_extn_compress_voip_in_get_parameters(struct stream_in *in,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret, val;
+ char value[32]={0};
+
+ ALOGV("%s: enter", __func__);
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_CHECK, value, sizeof(value));
+
+ if (ret >= 0) {
+ if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, true);
+ else
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_CHECK, false);
+ }
+
+ ALOGD("%s: exit: return - %s", __func__, str_parms_to_str(reply));
+}
+
+int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out)
+{
+ if (out->config.rate == 16000)
+ return COMPRESS_VOIP_IO_BUF_SIZE_WB;
+ else
+ return COMPRESS_VOIP_IO_BUF_SIZE_NB;
+}
+
+int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in)
+{
+ if (in->config.rate == 16000)
+ return COMPRESS_VOIP_IO_BUF_SIZE_WB;
+ else
+ return COMPRESS_VOIP_IO_BUF_SIZE_NB;
+}
+
+int voice_extn_compress_voip_start_output_stream(struct stream_out *out)
+{
+ int ret = 0;
+ struct audio_device *adev = out->dev;
+ struct audio_usecase *uc_info;
+
+ ALOGD("%s: enter", __func__);
+
+ ret = voip_start_call(adev, &out->config);
+ out->pcm = voip_data.pcm_rx;
+ uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+ uc_info->stream.out = out;
+ uc_info->devices = out->devices;
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int voice_extn_compress_voip_start_input_stream(struct stream_in *in)
+{
+ int ret = 0;
+ struct audio_usecase *uc_info;
+ struct audio_device *adev = in->dev;
+
+ ALOGD("%s: enter", __func__);
+
+ ret = voip_start_call(adev, &in->config);
+ in->pcm = voip_data.pcm_tx;
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ int ret = 0;
+
+ ALOGD("%s: enter", __func__);
+
+ ret = voip_stop_call(adev);
+ voip_data.out_stream = NULL;
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int voice_extn_compress_voip_open_output_stream(struct stream_out *out)
+{
+ int mode, ret;
+
+ ALOGD("%s: enter", __func__);
+
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+ out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+ out->usecase = USECASE_COMPRESS_VOIP_CALL;
+ if (out->sample_rate == 16000)
+ out->config = pcm_config_voip_wb;
+ else
+ out->config = pcm_config_voip_nb;
+
+ voip_data.out_stream = out;
+
+ ret = voip_set_mode(out->dev, out->format);
+
+ ALOGV("%s: exit", __func__);
+ return ret;
+}
+
+int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ int status = 0;
+
+ ALOGD("%s: enter", __func__);
+
+ status = voip_stop_call(adev);
+
+ ALOGV("%s: exit: status(%d)", __func__, status);
+ return status;
+
+}
+
+int voice_extn_compress_voip_open_input_stream(struct stream_in *in)
+{
+ int sample_rate;
+ int buffer_size,frame_size;
+ int mode, ret;
+
+ ALOGD("%s: enter", __func__);
+
+ in->usecase = USECASE_COMPRESS_VOIP_CALL;
+ if (in->config.rate == 16000)
+ in->config = pcm_config_voip_wb;
+ else
+ in->config = pcm_config_voip_nb;
+
+ ret = voip_set_mode(in->dev, in->format);
+
+ ALOGV("%s: exit", __func__);
+ return ret;
+}
+
+int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume)
+{
+ int vol, err = 0;
+
+ ALOGV("%s: enter", __func__);
+
+ if (volume < 0.0) {
+ volume = 0.0;
+ } else if (volume > 1.0) {
+ volume = 1.0;
+ }
+
+ vol = lrint(volume * 100.0);
+
+ /* Voice volume levels from android are mapped to driver volume levels as follows.
+ * 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
+ * So adjust the volume to get the correct volume index in driver
+ */
+ vol = 100 - vol;
+
+ err = voip_set_volume(adev, vol);
+
+ ALOGV("%s: exit: status(%d)", __func__, err);
+
+ return err;
+}
+
+int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state)
+{
+ int err = 0;
+
+ ALOGV("%s: enter", __func__);
+
+ err = voip_set_mic_mute(adev, state);
+
+ ALOGV("%s: exit: status(%d)", __func__, err);
+ return err;
+}
+
+bool voice_extn_compress_voip_pcm_prop_check()
+{
+ char prop_value[PROPERTY_VALUE_MAX] = {0};
+
+ property_get("use.voice.path.for.pcm.voip", prop_value, "0");
+ if (!strncmp("true", prop_value, sizeof("true")))
+ {
+ ALOGD("%s: VoIP PCM property is enabled", __func__);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool voice_extn_compress_voip_is_active(struct audio_device *adev)
+{
+ struct audio_usecase *voip_usecase = NULL;
+ voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+
+ if (voip_usecase != NULL)
+ return true;
+ else
+ return false;
+}
+
+bool voice_extn_compress_voip_is_format_supported(audio_format_t format)
+{
+ switch (format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ if (voice_extn_compress_voip_pcm_prop_check())
+ return true;
+ else
+ return false;
+ case AUDIO_FORMAT_AMR_NB:
+ case AUDIO_FORMAT_AMR_WB:
+ case AUDIO_FORMAT_EVRC:
+ case AUDIO_FORMAT_EVRCB:
+ case AUDIO_FORMAT_EVRCWB:
+ case AUDIO_FORMAT_EVRCNW:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool voice_extn_compress_voip_is_config_supported(struct audio_config *config)
+{
+ bool ret = false;
+
+ ret = voice_extn_compress_voip_is_format_supported(config->format);
+ if (ret) {
+ if ((popcount(config->channel_mask) == 1) &&
+ (config->sample_rate == 8000 || config->sample_rate == 16000))
+ ret = true;
+ else
+ ret = false;
+ }
+ return ret;
+}
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
new file mode 100644
index 0000000..989a871
--- /dev/null
+++ b/hal/voice_extn/voice_extn.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 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 "voice_extn"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <sound/voice_params.h>
+
+#include "audio_hw.h"
+#include "voice.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "voice_extn.h"
+
+#define AUDIO_PARAMETER_KEY_VSID "vsid"
+#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state"
+
+#define VOICE2_VSID 0x10DC1000
+#define VOLTE_VSID 0x10C02000
+#define QCHAT_VSID 0x10803000
+#define ALL_VSID 0xFFFFFFFF
+
+/* Voice Session Indices */
+#define VOICE2_SESS_IDX (VOICE_SESS_IDX + 1)
+#define VOLTE_SESS_IDX (VOICE_SESS_IDX + 2)
+#define QCHAT_SESS_IDX (VOICE_SESS_IDX + 3)
+
+/* Call States */
+#define CALL_HOLD (BASE_CALL_STATE + 2)
+#define CALL_LOCAL_HOLD (BASE_CALL_STATE + 3)
+
+struct pcm_config pcm_config_incall_music = {
+ .channels = 1,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+ .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+ .stop_threshold = INT_MAX,
+ .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
+extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
+int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
+
+static bool is_valid_call_state(int call_state)
+{
+ if (call_state < CALL_INACTIVE || call_state > CALL_LOCAL_HOLD)
+ return false;
+ else
+ return true;
+}
+
+static bool is_valid_vsid(uint32_t vsid)
+{
+ if (vsid == VOICE_VSID ||
+ vsid == VOICE2_VSID ||
+ vsid == VOLTE_VSID ||
+ vsid == QCHAT_VSID)
+ return true;
+ else
+ return false;
+}
+
+static audio_usecase_t voice_extn_get_usecase_for_session_idx(const int index)
+{
+ audio_usecase_t usecase_id = -1;
+
+ switch(index) {
+ case VOICE_SESS_IDX:
+ usecase_id = USECASE_VOICE_CALL;
+ break;
+
+ case VOICE2_SESS_IDX:
+ usecase_id = USECASE_VOICE2_CALL;
+ break;
+
+ case VOLTE_SESS_IDX:
+ usecase_id = USECASE_VOLTE_CALL;
+ break;
+
+ case QCHAT_SESS_IDX:
+ usecase_id = USECASE_QCHAT_CALL;
+ break;
+
+ default:
+ ALOGE("%s: Invalid voice session index\n", __func__);
+ }
+
+ return usecase_id;
+}
+
+static uint32_t get_session_id_with_state(struct audio_device *adev,
+ int call_state)
+{
+ struct voice_session *session = NULL;
+ int i = 0;
+ uint32_t session_id = 0;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ session = &adev->voice.session[i];
+ if(session->state.current == call_state){
+ session_id = session->vsid;
+ break;
+ }
+ }
+
+ return session_id;
+}
+
+static int update_calls(struct audio_device *adev)
+{
+ int i = 0;
+ audio_usecase_t usecase_id = 0;
+ enum voice_lch_mode lch_mode;
+ struct voice_session *session = NULL;
+ int fd = 0;
+ int ret = 0;
+
+ ALOGD("%s: enter:", __func__);
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ usecase_id = voice_extn_get_usecase_for_session_idx(i);
+ session = &adev->voice.session[i];
+ ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
+ __func__, session->state.current, session->state.new, session->vsid);
+
+ switch(session->state.new)
+ {
+ case CALL_ACTIVE:
+ switch(session->state.current)
+ {
+ case CALL_INACTIVE:
+ ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
+ ret = start_call(adev, usecase_id);
+ if(ret < 0) {
+ ALOGE("%s: voice_start_call() failed for usecase: %d\n",
+ __func__, usecase_id);
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ case CALL_HOLD:
+ ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
+ session->state.current = session->state.new;
+ break;
+
+ case CALL_LOCAL_HOLD:
+ ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
+ lch_mode = VOICE_LCH_STOP;
+ if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
+ ALOGE("LOCAL_HOLD -> ACTIVE failed");
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_ACTIVE cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ case CALL_INACTIVE:
+ switch(session->state.current)
+ {
+ case CALL_ACTIVE:
+ case CALL_HOLD:
+ case CALL_LOCAL_HOLD:
+ ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
+ ret = stop_call(adev, usecase_id);
+ if(ret < 0) {
+ ALOGE("%s: voice_end_call() failed for usecase: %d\n",
+ __func__, usecase_id);
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_INACTIVE cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ case CALL_HOLD:
+ switch(session->state.current)
+ {
+ case CALL_ACTIVE:
+ ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
+ session->state.current = session->state.new;
+ break;
+
+ case CALL_LOCAL_HOLD:
+ ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
+ lch_mode = VOICE_LCH_STOP;
+ if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
+ ALOGE("LOCAL_HOLD -> HOLD failed");
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_HOLD cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ case CALL_LOCAL_HOLD:
+ switch(session->state.current)
+ {
+ case CALL_ACTIVE:
+ case CALL_HOLD:
+ ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
+ session->vsid);
+ lch_mode = VOICE_LCH_START;
+ if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
+ ALOGE("LOCAL_HOLD -> HOLD failed");
+ } else {
+ session->state.current = session->state.new;
+ }
+ break;
+
+ default:
+ ALOGV("%s: CALL_LOCAL_HOLD cannot be handled in state=%d vsid:%x",
+ __func__, session->state.current, session->vsid);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ } //end out switch loop
+ } //end for loop
+
+ return ret;
+}
+
+static int update_call_states(struct audio_device *adev,
+ const uint32_t vsid, const int call_state)
+{
+ struct voice_session *session = NULL;
+ int i = 0;
+ bool is_in_call;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ if (vsid == adev->voice.session[i].vsid) {
+ session = &adev->voice.session[i];
+ break;
+ }
+ }
+
+ if (session) {
+ session->state.new = call_state;
+ voice_extn_is_in_call(adev, &is_in_call);
+ ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode);
+ /* Dont start voice call before device routing for voice usescases has
+ * occured, otherwise voice calls will be started unintendedly on
+ * speaker.
+ */
+ if (is_in_call ||
+ (adev->mode == AUDIO_MODE_IN_CALL &&
+ adev->primary_output->devices != AUDIO_DEVICE_OUT_SPEAKER)) {
+ /* Device routing is not triggered for voice calls on the subsequent
+ * subs, Hence update the call states if voice call is already
+ * active on other sub.
+ */
+ update_calls(adev);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+
+}
+
+int voice_extn_get_active_session_id(struct audio_device *adev,
+ uint32_t *session_id)
+{
+ *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
+ return 0;
+}
+
+int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+{
+ struct voice_session *session = NULL;
+ int i = 0;
+ *in_call = false;
+
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ session = &adev->voice.session[i];
+ if(session->state.current != CALL_INACTIVE){
+ *in_call = true;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void voice_extn_init(struct audio_device *adev)
+{
+ adev->voice.session[VOICE_SESS_IDX].vsid = VOICE_VSID;
+ adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
+ adev->voice.session[VOLTE_SESS_IDX].vsid = VOLTE_VSID;
+ adev->voice.session[QCHAT_SESS_IDX].vsid = QCHAT_VSID;
+}
+
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+ const audio_usecase_t usecase_id,
+ struct voice_session **session)
+{
+
+ switch(usecase_id)
+ {
+ case USECASE_VOICE_CALL:
+ *session = &adev->voice.session[VOICE_SESS_IDX];
+ break;
+
+ case USECASE_VOICE2_CALL:
+ *session = &adev->voice.session[VOICE2_SESS_IDX];
+ break;
+
+ case USECASE_VOLTE_CALL:
+ *session = &adev->voice.session[VOLTE_SESS_IDX];
+ break;
+
+ case USECASE_QCHAT_CALL:
+ *session = &adev->voice.session[QCHAT_SESS_IDX];
+ break;
+
+ default:
+ ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
+ *session = NULL;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int voice_extn_start_call(struct audio_device *adev)
+{
+ /* Start voice calls on sessions whose call state has been
+ * udpated.
+ */
+ ALOGV("%s: enter:", __func__);
+ return update_calls(adev);
+}
+
+int voice_extn_stop_call(struct audio_device *adev)
+{
+ int i;
+ int ret = 0;
+
+ ALOGV("%s: enter:", __func__);
+
+ /* If BT device is enabled and voice calls are ended, telephony will call
+ * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to
+ * set routing with device BT A2DP profile. Hence end all voice calls when
+ * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected.
+ */
+ if (adev->mode == AUDIO_MODE_NORMAL) {
+ ALOGD("%s: end all calls", __func__);
+ for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+ adev->voice.session[i].state.new = CALL_INACTIVE;
+ }
+
+ ret = update_calls(adev);
+ }
+
+ return ret;
+}
+
+int voice_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ char *str;
+ int value;
+ int ret = 0;
+
+ ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
+
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
+ if (ret >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID);
+ int vsid = value;
+ int call_state = -1;
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
+ if (ret >= 0) {
+ call_state = value;
+ } else {
+ ALOGE("%s: call_state key not found", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) {
+ ret = update_call_states(adev, vsid, call_state);
+ } else {
+ ALOGE("%s: invalid vsid:%x or call_state:%d",
+ __func__, vsid, call_state);
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ ALOGD("%s: Not handled here", __func__);
+ }
+
+done:
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ return ret;
+}
+
+void voice_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ int ret;
+ char value[32]={0};
+ char *str = NULL;
+
+ ret = str_parms_get_str(query, "audio_mode", value,
+ sizeof(value));
+ if (ret >= 0) {
+ str_parms_add_int(reply, "audio_mode", adev->mode);
+ }
+
+ ALOGV("%s: returns %s", __func__, str_parms_to_str(reply));
+}
+
+void voice_extn_out_get_parameters(struct stream_out *out,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ voice_extn_compress_voip_out_get_parameters(out, query, reply);
+}
+
+void voice_extn_in_get_parameters(struct stream_in *in,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ voice_extn_compress_voip_in_get_parameters(in, query, reply);
+}
+
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out)
+{
+ uint32_t session_id = 0;
+
+ session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD);
+ if (session_id == VOICE_VSID) {
+ out->usecase = USECASE_INCALL_MUSIC_UPLINK;
+ } else if (session_id == VOICE2_VSID) {
+ out->usecase = USECASE_INCALL_MUSIC_UPLINK2;
+ } else {
+ ALOGE("%s: Invalid session id %x", __func__, session_id);
+ return -EINVAL;
+ }
+
+ out->config = pcm_config_incall_music;
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+ out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+
+ return 0;
+}
+
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
new file mode 100644
index 0000000..0ca2386
--- /dev/null
+++ b/hal/voice_extn/voice_extn.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VOICE_EXTN_H
+#define VOICE_EXTN_H
+
+#ifdef MULTI_VOICE_SESSION_ENABLED
+int voice_extn_start_call(struct audio_device *adev);
+int voice_extn_stop_call(struct audio_device *adev);
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+ const audio_usecase_t usecase_id,
+ struct voice_session **session);
+void voice_extn_init(struct audio_device *adev);
+int voice_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+void voice_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply);
+int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
+int voice_extn_get_active_session_id(struct audio_device *adev,
+ uint32_t *session_id);
+void voice_extn_in_get_parameters(struct stream_in *in,
+ struct str_parms *query,
+ struct str_parms *reply);
+void voice_extn_out_get_parameters(struct stream_out *out,
+ struct str_parms *query,
+ struct str_parms *reply);
+#else
+static int voice_extn_start_call(struct audio_device *adev)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_stop_call(struct audio_device *adev)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_get_session_from_use_case(struct audio_device *adev,
+ const audio_usecase_t usecase_id,
+ struct voice_session **session)
+{
+ return -ENOSYS;
+}
+
+static void voice_extn_init(struct audio_device *adev)
+{
+}
+
+static int voice_extn_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ return -ENOSYS;
+}
+
+static void voice_extn_get_parameters(const struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+}
+
+static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+{
+ return -ENOSYS;
+}
+
+static int voice_extn_get_active_session_id(struct audio_device *adev,
+ uint32_t *session_id)
+{
+ return -ENOSYS;
+}
+
+static void voice_extn_in_get_parameters(struct stream_in *in,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+}
+
+static void voice_extn_out_get_parameters(struct stream_out *out,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+}
+#endif
+
+#ifdef INCALL_MUSIC_ENABLED
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out);
+#else
+static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+ struct stream_out *out)
+{
+ return -ENOSYS;
+}
+#endif
+
+#ifdef COMPRESS_VOIP_ENABLED
+int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream);
+int voice_extn_compress_voip_open_output_stream(struct stream_out *out);
+
+int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream);
+int voice_extn_compress_voip_open_input_stream(struct stream_in *in);
+
+int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out);
+int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in);
+
+int voice_extn_compress_voip_start_input_stream(struct stream_in *in);
+int voice_extn_compress_voip_start_output_stream(struct stream_out *out);
+
+int voice_extn_compress_voip_set_mic_mute(struct audio_device *dev, bool state);
+int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume);
+int voice_extn_compress_voip_select_devices(struct audio_device *adev,
+ snd_device_t *out_snd_device,
+ snd_device_t *in_snd_device);
+void voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+ struct str_parms *parms);
+
+void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
+ struct str_parms *query,
+ struct str_parms *reply);
+void voice_extn_compress_voip_in_get_parameters(struct stream_in *in,
+ struct str_parms *query,
+ struct str_parms *reply);
+bool voice_extn_compress_voip_pcm_prop_check();
+bool voice_extn_compress_voip_is_active(struct audio_device *adev);
+bool voice_extn_compress_voip_is_format_supported(audio_format_t format);
+bool voice_extn_compress_voip_is_config_supported(struct audio_config *config);
+#else
+static int voice_extn_compress_voip_close_output_stream(struct audio_stream *stream)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_open_output_stream(struct stream_out *out)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_close_input_stream(struct audio_stream *stream)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_open_input_stream(struct stream_in *in)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_out_get_buffer_size(struct audio_stream *stream)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_start_input_stream(struct stream_in *in)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_start_output_stream(struct stream_out *out)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static int voice_extn_compress_voip_set_mic_mute(struct audio_device *adev, bool state)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return 0;
+}
+
+static int voice_extn_compress_voip_set_volume(struct audio_device *adev, float volume)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return 0;
+}
+
+static int voice_extn_compress_voip_select_devices(struct audio_device *adev,
+ snd_device_t *out_snd_device,
+ snd_device_t *in_snd_device)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return -ENOSYS;
+}
+
+static void voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+ struct str_parms *parms)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+}
+
+static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+}
+
+static void voice_extn_compress_voip_in_get_parameters(struct stream_in *in,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+}
+
+static bool voice_extn_compress_voip_pcm_prop_check()
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return false;
+}
+
+static bool voice_extn_compress_voip_is_active(struct audio_device *adev)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return false;
+}
+
+static bool voice_extn_compress_voip_is_format_supported(audio_format_t format)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return true;
+}
+
+static bool voice_extn_compress_voip_is_config_supported(struct audio_config *config)
+{
+ ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+ return true;
+}
+#endif
+
+#endif //VOICE_EXTN_H
diff --git a/hal_mpq/Android.mk b/hal_mpq/Android.mk
new file mode 100644
index 0000000..683de7a
--- /dev/null
+++ b/hal_mpq/Android.mk
@@ -0,0 +1,59 @@
+ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
+
+LOCAL_SRC_FILES := \
+ audio_hw.c \
+ audio_stream_out.c \
+ audio_bitstream_sm.c \
+ $(AUDIO_PLATFORM)/hw_info.c \
+ $(AUDIO_PLATFORM)/platform.c
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_ANC_HEADSET)),true)
+ LOCAL_CFLAGS += -DANC_HEADSET_ENABLED
+endif
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true)
+ LOCAL_CFLAGS += -DAFE_PROXY_ENABLED
+endif
+
+
+ifdef MULTIPLE_HW_VARIANTS_ENABLED
+ LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
+ LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libtinyalsa \
+ libtinycompress \
+ libaudioroute \
+ libdl
+
+LOCAL_C_INCLUDES := \
+ external/tinyalsa/include \
+ external/tinycompress/include \
+ $(call include-path-for, audio-route) \
+ $(call include-path-for, audio-effects) \
+ $(LOCAL_PATH)/$(AUDIO_PLATFORM)
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true)
+ LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED
+endif
+
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/hal_mpq/audio_bitstream_sm.c b/hal_mpq/audio_bitstream_sm.c
new file mode 100644
index 0000000..9f2564d
--- /dev/null
+++ b/hal_mpq/audio_bitstream_sm.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <math.h>
+
+#define LOG_TAG "AudioBitstreamStateMachine"
+//#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+
+#include <cutils/properties.h>
+#include "audio_hw.h"
+#include "platform_api.h"
+#include <platform.h>
+// ----------------------------------------------------------------------------
+
+
+/*
+Initialize all input and output pointers
+Allocate twice the max buffer size of input and output for sufficient buffering
+*/
+int audio_bitstream_init(struct audio_bitstream_sm *bstream, int buffering_factor)
+{
+ bstream->buffering_factor = buffering_factor;
+ bstream->buffering_factor_cnt = 0;
+
+ bstream->inp_buf=(char *)malloc(SAMPLES_PER_CHANNEL*
+ MAX_INPUT_CHANNELS_SUPPORTED*
+ (bstream->buffering_factor+1));
+ // multiplied by 2 to convert to bytes
+ if(bstream->inp_buf != NULL) {
+ bstream->inp_buf_curr_ptr = bstream->inp_buf;
+ bstream->inp_buf_write_ptr = bstream->inp_buf;
+ } else {
+ ALOGE("MS11 input buffer not allocated");
+ return 0;
+ }
+
+ bstream->enc_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL*
+ MAX_INPUT_CHANNELS_SUPPORTED*
+ FACTOR_FOR_BUFFERING);
+ if(bstream->enc_out_buf) {
+ bstream->enc_out_buf_write_ptr = bstream->enc_out_buf;
+ } else {
+ ALOGE("MS11 Enc output buffer not allocated");
+ return 0;
+ }
+ bstream->pcm_2_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL*STEREO_CHANNELS *
+ FACTOR_FOR_BUFFERING);
+ if(bstream->pcm_2_out_buf) {
+ bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf;
+ } else {
+ ALOGE("MS11 PCM2Ch output buffer not allocated");
+ return 0;
+ }
+ bstream->pcm_mch_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL *
+ MAX_OUTPUT_CHANNELS_SUPPORTED *
+ FACTOR_FOR_BUFFERING);
+ if(bstream->pcm_mch_out_buf) {
+ bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf;
+ } else {
+ ALOGE("MS11 PCMMCh output buffer not allocated");
+ return 0;
+ }
+ bstream->passt_out_buf =(char *)malloc(SAMPLES_PER_CHANNEL *
+ MAX_INPUT_CHANNELS_SUPPORTED *
+ FACTOR_FOR_BUFFERING);
+ if(bstream->passt_out_buf) {
+ bstream->passt_out_buf_write_ptr = bstream->passt_out_buf;
+ } else {
+ ALOGE("MS11 Enc output buffer not allocated");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+Free the allocated memory
+*/
+int audio_bitstream_close(struct audio_bitstream_sm *bstream)
+{
+ if(bstream->inp_buf != NULL) {
+ free(bstream->inp_buf);
+ bstream->inp_buf = NULL;
+ }
+ if(bstream->enc_out_buf != NULL) {
+ free(bstream->enc_out_buf);
+ bstream->enc_out_buf = NULL;
+ }
+ if(bstream->pcm_2_out_buf != NULL) {
+ free(bstream->pcm_2_out_buf);
+ bstream->pcm_2_out_buf = NULL;
+ }
+ if(bstream->pcm_mch_out_buf != NULL) {
+ free(bstream->pcm_mch_out_buf);
+ bstream->pcm_mch_out_buf = NULL;
+ }
+ if(bstream->passt_out_buf != NULL) {
+ free(bstream->passt_out_buf);
+ bstream->passt_out_buf = NULL;
+ }
+ bstream->buffering_factor = 1;
+ bstream->buffering_factor_cnt = 0;
+ return 0;
+}
+
+/*
+Reset the buffer pointers to start for. This will be help in flush and close
+*/
+void audio_bitstream_reset_ptr( struct audio_bitstream_sm *bstream)
+{
+ bstream->inp_buf_curr_ptr = bstream->inp_buf_write_ptr = bstream->inp_buf;
+ bstream->enc_out_buf_write_ptr = bstream->enc_out_buf;
+ bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf;
+ bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf;
+ bstream->passt_out_buf_write_ptr = bstream->passt_out_buf;
+ bstream->buffering_factor_cnt = 0;
+}
+
+/*
+Reset the output buffer pointers to start for port reconfiguration
+*/
+void audio_bitstream_reset_output_bitstream_ptr(
+ struct audio_bitstream_sm *bstream)
+{
+ bstream->enc_out_buf_write_ptr = bstream->enc_out_buf;
+ bstream->pcm_2_out_buf_write_ptr = bstream->pcm_2_out_buf;
+ bstream->pcm_mch_out_buf_write_ptr = bstream->pcm_mch_out_buf;
+ bstream->passt_out_buf_write_ptr = bstream->passt_out_buf;
+}
+
+/*
+Copy the bitstream/pcm from Player to internal buffer.
+The incoming bitstream is appended to existing bitstream
+*/
+void audio_bitstream_copy_to_internal_buffer(
+ struct audio_bitstream_sm *bstream,
+ char *buf_ptr, size_t bytes)
+{
+ int32_t bufLen = SAMPLES_PER_CHANNEL*MAX_INPUT_CHANNELS_SUPPORTED*(bstream->buffering_factor+1);
+ // flush the input buffer if input is not consumed
+ if( (bstream->inp_buf_write_ptr+bytes) > (bstream->inp_buf+bufLen) ) {
+ ALOGE("Input bitstream is not consumed");
+ return;
+ }
+
+ memcpy(bstream->inp_buf_write_ptr, buf_ptr, bytes);
+ bstream->inp_buf_write_ptr += bytes;
+ if(bstream->buffering_factor_cnt < bstream->buffering_factor)
+ bstream->buffering_factor_cnt++;
+}
+
+/*
+Append zeros to the bitstream, so that the entire bitstream in ADIF is pushed
+out for decoding
+*/
+void audio_bitstream_append_silence_internal_buffer(
+ struct audio_bitstream_sm *bstream,
+ uint32_t bytes, unsigned char value)
+{
+ int32_t bufLen = SAMPLES_PER_CHANNEL*MAX_INPUT_CHANNELS_SUPPORTED*
+ (bstream->buffering_factor+1);
+ uint32_t i = 0;
+ if( (bstream->inp_buf_write_ptr+bytes) > (bstream->inp_buf+bufLen) ) {
+ bytes = bufLen + bstream->inp_buf - bstream->inp_buf_write_ptr;
+ }
+ for(i=0; i< bytes; i++)
+ *bstream->inp_buf_write_ptr++ = value;
+ if(bstream->buffering_factor_cnt < bstream->buffering_factor)
+ bstream->buffering_factor_cnt++;
+}
+
+/*
+Flags if sufficient bitstream is available to proceed to decode based on
+the threshold
+*/
+int audio_bitstream_sufficient_buffer_to_decode(
+ struct audio_bitstream_sm *bstream,
+ int min_bytes_to_decode)
+{
+ int proceed_decode = 0;
+ if( (bstream->inp_buf_write_ptr -\
+ bstream->inp_buf_curr_ptr) > min_bytes_to_decode)
+ proceed_decode = 1;
+ return proceed_decode;
+}
+
+/*
+Gets the start address of the bitstream buffer. This is used for start of decode
+*/
+char* audio_bitstream_get_input_buffer_ptr(
+ struct audio_bitstream_sm *bstream)
+{
+ return bstream->inp_buf_curr_ptr;
+}
+
+/*
+Gets the writePtr of the bitstream buffer. This is used for calculating length of
+bitstream
+*/
+char* audio_bitstream_get_input_buffer_write_ptr(
+ struct audio_bitstream_sm *bstream)
+{
+ return bstream->inp_buf_write_ptr;
+}
+
+/*
+Get the output buffer start pointer to start rendering the pcm sampled to driver
+*/
+char* audio_bitstream_get_output_buffer_ptr(
+ struct audio_bitstream_sm *bstream,
+ int format)
+{
+ switch(format) {
+ case PCM_MCH_OUT:
+ return bstream->pcm_mch_out_buf;
+ case PCM_2CH_OUT:
+ return bstream->pcm_2_out_buf;
+ case COMPRESSED_OUT:
+ return bstream->enc_out_buf;
+ case TRANSCODE_OUT:
+ return bstream->passt_out_buf;
+ default:
+ return NULL;
+ }
+}
+
+/*
+Output the pointer from where the next PCM samples can be copied to buffer
+*/
+char* audio_bitstream_get_output_buffer_write_ptr(
+ struct audio_bitstream_sm *bstream,
+ int format)
+{
+ switch(format) {
+ case PCM_MCH_OUT:
+ return bstream->pcm_mch_out_buf_write_ptr;
+ case PCM_2CH_OUT:
+ return bstream->pcm_2_out_buf_write_ptr;
+ case COMPRESSED_OUT:
+ return bstream->enc_out_buf_write_ptr;
+ case TRANSCODE_OUT:
+ return bstream->passt_out_buf_write_ptr;
+ default:
+ return NULL;
+ }
+}
+
+/*
+Provides the bitstream size available in the internal buffer
+*/
+size_t audio_bitstream_get_size(struct audio_bitstream_sm *bstream)
+{
+ return (bstream->inp_buf_write_ptr-bstream->inp_buf_curr_ptr);
+}
+
+/*
+After decode, the residue bitstream in the buffer is moved to start, so as to
+avoid circularity constraints
+*/
+void audio_bitstream_copy_residue_to_start(
+ struct audio_bitstream_sm *bstream,
+ size_t bytes_consumed_in_decode)
+{
+ size_t remaining_curr_valid_bytes = bstream->inp_buf_write_ptr -
+ (bytes_consumed_in_decode+bstream->inp_buf_curr_ptr);
+ size_t remainingTotalBytes = bstream->inp_buf_write_ptr -
+ (bytes_consumed_in_decode+bstream->inp_buf);
+ if(bstream->buffering_factor_cnt == bstream->buffering_factor) {
+ memcpy(bstream->inp_buf, bstream->inp_buf+bytes_consumed_in_decode, remainingTotalBytes);
+ bstream->inp_buf_write_ptr = bstream->inp_buf+remainingTotalBytes;
+ bstream->inp_buf_curr_ptr = bstream->inp_buf_write_ptr-remaining_curr_valid_bytes;
+ } else {
+ bstream->inp_buf_curr_ptr += bytes_consumed_in_decode;
+ }
+}
+
+/*
+Remaing samples less than the one period size required for the pcm driver
+is moved to start of the buffer
+*/
+void audio_bitstream_copy_residue_output_start(
+ struct audio_bitstream_sm *bstream,
+ int format,
+ size_t samplesRendered)
+{
+ size_t remaining_bytes;
+ switch(format) {
+ case PCM_MCH_OUT:
+ remaining_bytes = bstream->pcm_mch_out_buf_write_ptr-\
+ (bstream->pcm_mch_out_buf+samplesRendered);
+ memcpy(bstream->pcm_mch_out_buf,
+ bstream->pcm_mch_out_buf+samplesRendered,
+ remaining_bytes);
+ bstream->pcm_mch_out_buf_write_ptr = \
+ bstream->pcm_mch_out_buf + remaining_bytes;
+ break;
+ case PCM_2CH_OUT:
+ remaining_bytes = bstream->pcm_2_out_buf_write_ptr-\
+ (bstream->pcm_2_out_buf+samplesRendered);
+ memcpy(bstream->pcm_2_out_buf,
+ bstream->pcm_2_out_buf+samplesRendered,
+ remaining_bytes);
+ bstream->pcm_2_out_buf_write_ptr = \
+ bstream->pcm_2_out_buf + remaining_bytes;
+ break;
+ case COMPRESSED_OUT:
+ remaining_bytes = bstream->enc_out_buf_write_ptr-\
+ (bstream->enc_out_buf+samplesRendered);
+ memcpy(bstream->enc_out_buf,
+ bstream->enc_out_buf+samplesRendered,
+ remaining_bytes);
+ bstream->enc_out_buf_write_ptr = \
+ bstream->enc_out_buf + remaining_bytes;
+ break;
+ case TRANSCODE_OUT:
+ remaining_bytes = bstream->passt_out_buf_write_ptr-\
+ (bstream->passt_out_buf+samplesRendered);
+ memcpy(bstream->passt_out_buf,
+ bstream->passt_out_buf+samplesRendered,
+ remaining_bytes);
+ bstream->passt_out_buf_write_ptr = \
+ bstream->passt_out_buf + remaining_bytes;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+The write pointer is updated after the incoming PCM samples are copied to the
+output buffer
+*/
+void audio_bitstream_set_output_buffer_write_ptr(
+ struct audio_bitstream_sm *bstream,
+ int format, size_t output_pcm_sample)
+{
+ int alloc_bytes;
+ switch(format) {
+ case PCM_MCH_OUT:
+ alloc_bytes = SAMPLES_PER_CHANNEL*\
+ MAX_OUTPUT_CHANNELS_SUPPORTED*FACTOR_FOR_BUFFERING;
+ if (bstream->pcm_mch_out_buf + alloc_bytes >\
+ bstream->pcm_mch_out_buf_write_ptr + output_pcm_sample)
+ bstream->pcm_mch_out_buf_write_ptr += output_pcm_sample;
+ break;
+ case PCM_2CH_OUT:
+ alloc_bytes = SAMPLES_PER_CHANNEL*STEREO_CHANNELS*FACTOR_FOR_BUFFERING;
+ if(bstream->pcm_2_out_buf + alloc_bytes > \
+ bstream->pcm_2_out_buf_write_ptr + output_pcm_sample)
+ bstream->pcm_2_out_buf_write_ptr += output_pcm_sample;
+ break;
+ case COMPRESSED_OUT:
+ alloc_bytes = SAMPLES_PER_CHANNEL*\
+ MAX_INPUT_CHANNELS_SUPPORTED*FACTOR_FOR_BUFFERING;
+ if (bstream->enc_out_buf + alloc_bytes > \
+ bstream->enc_out_buf_write_ptr + output_pcm_sample)
+ bstream->enc_out_buf_write_ptr += output_pcm_sample;
+ break;
+ case TRANSCODE_OUT:
+ alloc_bytes = SAMPLES_PER_CHANNEL*\
+ MAX_INPUT_CHANNELS_SUPPORTED*FACTOR_FOR_BUFFERING;
+ if (bstream->passt_out_buf + alloc_bytes > \
+ bstream->passt_out_buf_write_ptr + output_pcm_sample)
+ bstream->passt_out_buf_write_ptr += output_pcm_sample;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+Flags if sufficient samples are available to render to PCM driver
+*/
+int audio_bitstream_sufficient_sample_to_render(
+ struct audio_bitstream_sm *bstream,
+ int format, int mid_size_reqd)
+{
+ int status = 0;
+ char *buf_ptr = NULL, *buf_write_ptr = NULL;
+ switch(format) {
+ case PCM_MCH_OUT:
+ buf_ptr = bstream->pcm_mch_out_buf;
+ buf_write_ptr = bstream->pcm_mch_out_buf_write_ptr;
+ break;
+ case PCM_2CH_OUT:
+ buf_ptr = bstream->pcm_2_out_buf;
+ buf_write_ptr = bstream->pcm_2_out_buf_write_ptr;
+ break;
+ case COMPRESSED_OUT:
+ buf_ptr = bstream->enc_out_buf;
+ buf_write_ptr = bstream->enc_out_buf_write_ptr;
+ break;
+ case TRANSCODE_OUT:
+ buf_ptr = bstream->passt_out_buf;
+ buf_write_ptr = bstream->passt_out_buf_write_ptr;
+ break;
+ default:
+ break;
+ }
+ if( (buf_write_ptr-buf_ptr) >= mid_size_reqd )
+ status = 1;
+ return status;
+}
+
+void audio_bitstream_start_input_buffering_mode(
+ struct audio_bitstream_sm *bstream)
+{
+ bstream->buffering_factor_cnt = 0;
+}
+
+void audio_bitstream_stop_input_buffering_mode(
+ struct audio_bitstream_sm *bstream)
+{
+ size_t remaining_curr_valid_bytes = \
+ bstream->inp_buf_write_ptr - bstream->inp_buf_curr_ptr;
+ bstream->buffering_factor_cnt = bstream->buffering_factor;
+ memcpy(bstream->inp_buf,
+ bstream->inp_buf_curr_ptr,
+ remaining_curr_valid_bytes);
+ bstream->inp_buf_curr_ptr = bstream->inp_buf;
+ bstream->inp_buf_write_ptr = bstream->inp_buf + remaining_curr_valid_bytes;
+}
diff --git a/hal_mpq/audio_bitstream_sm.h b/hal_mpq/audio_bitstream_sm.h
new file mode 100644
index 0000000..db03bf5
--- /dev/null
+++ b/hal_mpq/audio_bitstream_sm.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_BITSTRM_SM_H
+#define QCOM_AUDIO_BITSTRM_SM_H
+int audio_bitstream_init(struct audio_bitstream_sm *bstream, int buffering_factor);
+int audio_bitstream_close(struct audio_bitstream_sm *bstream);
+int audio_bitstream_with_buffering_factor(struct audio_bitstream_sm *bstream,
+ int in_buffering_factor);
+void audio_bitstream_reset_ptr( struct audio_bitstream_sm *bstream);
+void audio_bitstream_reset_output_bitstream_ptr(
+ struct audio_bitstream_sm *bstream);
+void audio_bitstream_copy_to_internal_buffer(
+ struct audio_bitstream_sm *bstream,
+ char *buf_ptr, size_t bytes);
+void audio_bitstream_append_silence_internal_buffer(
+ struct audio_bitstream_sm *bstream,
+ uint32_t bytes, unsigned char value);
+int audio_bitstream_sufficient_buffer_to_decode(
+ struct audio_bitstream_sm *bstream,
+ int min_bytes_to_decode);
+char* audio_bitstream_get_input_buffer_ptr(
+ struct audio_bitstream_sm *bstream);
+char* audio_bitstream_get_input_buffer_write_ptr(
+ struct audio_bitstream_sm *bstream);
+char* audio_bitstream_get_output_buffer_ptr(
+ struct audio_bitstream_sm *bstream,
+ int format);
+char* audio_bitstream_get_output_buffer_write_ptr(
+ struct audio_bitstream_sm *bstream,
+ int format);
+size_t audio_bitstream_get_size(struct audio_bitstream_sm *bstream);
+void audio_bitstream_copy_residue_to_start(
+ struct audio_bitstream_sm *bstream,
+ size_t bytes_consumed_in_decode);
+void audio_bitstream_copy_residue_output_start(
+ struct audio_bitstream_sm *bstream,
+ int format,
+ size_t samplesRendered);
+void audio_bitstream_set_output_buffer_write_ptr(
+ struct audio_bitstream_sm *bstream,
+ int format, size_t output_pcm_sample);
+int audio_bitstream_sufficient_sample_to_render(
+ struct audio_bitstream_sm *bstream,
+ int format, int mid_size_reqd);
+void audio_bitstream_start_input_buffering_mode(
+ struct audio_bitstream_sm *bstream);
+void audio_bitstream_stop_input_buffering_mode(
+ struct audio_bitstream_sm *bstream);
+#endif
diff --git a/hal_mpq/audio_hw.c b/hal_mpq/audio_hw.c
new file mode 100644
index 0000000..fb83245
--- /dev/null
+++ b/hal_mpq/audio_hw.c
@@ -0,0 +1,1240 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+
+#include <hardware/audio_effect.h>
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_ns.h>
+#include "audio_hw.h"
+#include "platform_api.h"
+#include <platform.h>
+
+struct pcm_config pcm_config_audio_capture = {
+ .channels = 2,
+ .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+};
+
+static struct audio_device *adev = NULL;
+static pthread_mutex_t adev_init_lock;
+static unsigned int audio_device_ref_count;
+
+static int set_voice_volume_l(struct audio_device *adev, float volume);
+
+int enable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer)
+{
+ snd_device_t snd_device;
+ char mixer_path[MIXER_PATH_MAX_LENGTH];
+
+ if (usecase == NULL)
+ return -EINVAL;
+
+ ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
+
+ if (usecase->type == PCM_CAPTURE)
+ snd_device = usecase->in_snd_device;
+ else
+ snd_device = usecase->out_snd_device;
+
+ strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path));
+ platform_add_backend_name(mixer_path, snd_device);
+ ALOGV("%s: apply mixer path: %s", __func__, mixer_path);
+ audio_route_apply_path(adev->audio_route, mixer_path);
+ if (update_mixer)
+ audio_route_update_mixer(adev->audio_route);
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+int disable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer)
+{
+ snd_device_t snd_device;
+ char mixer_path[MIXER_PATH_MAX_LENGTH];
+
+ if (usecase == NULL)
+ return -EINVAL;
+
+ ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
+ if (usecase->type == PCM_CAPTURE)
+ snd_device = usecase->in_snd_device;
+ else
+ snd_device = usecase->out_snd_device;
+ strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path));
+ platform_add_backend_name(mixer_path, snd_device);
+ ALOGV("%s: reset mixer path: %s", __func__, mixer_path);
+ audio_route_reset_path(adev->audio_route, mixer_path);
+ if (update_mixer)
+ audio_route_update_mixer(adev->audio_route);
+
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+int enable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer)
+{
+ char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+
+ if (snd_device < SND_DEVICE_MIN ||
+ snd_device >= SND_DEVICE_MAX) {
+ ALOGE("%s: Invalid sound device %d", __func__, snd_device);
+ return -EINVAL;
+ }
+
+ adev->snd_dev_ref_cnt[snd_device]++;
+
+ if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
+ ALOGE("%s: Invalid sound device returned", __func__);
+ return -EINVAL;
+ }
+ if (adev->snd_dev_ref_cnt[snd_device] > 1) {
+ ALOGV("%s: snd_device(%d: %s) is already active",
+ __func__, snd_device, device_name);
+ return 0;
+ }
+
+ {
+ ALOGV("%s: snd_device(%d: %s)", __func__,
+ snd_device, device_name);
+ if (platform_send_audio_calibration(adev->platform, snd_device) < 0) {
+ adev->snd_dev_ref_cnt[snd_device]--;
+ return -EINVAL;
+ }
+ audio_route_apply_path(adev->audio_route, device_name);
+ }
+ if (update_mixer)
+ audio_route_update_mixer(adev->audio_route);
+
+ return 0;
+}
+
+int disable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer)
+{
+ char device_name[DEVICE_NAME_MAX_SIZE] = {0};
+
+ if (snd_device < SND_DEVICE_MIN ||
+ snd_device >= SND_DEVICE_MAX) {
+ ALOGE("%s: Invalid sound device %d", __func__, snd_device);
+ return -EINVAL;
+ }
+ if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
+ ALOGE("%s: device ref cnt is already 0", __func__);
+ return -EINVAL;
+ }
+
+ adev->snd_dev_ref_cnt[snd_device]--;
+
+ if(platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
+ ALOGE("%s: Invalid sound device returned", __func__);
+ return -EINVAL;
+ }
+
+ if (adev->snd_dev_ref_cnt[snd_device] == 0) {
+ ALOGV("%s: snd_device(%d: %s)", __func__,
+ snd_device, device_name);
+ audio_route_reset_path(adev->audio_route, device_name);
+
+ if (update_mixer)
+ audio_route_update_mixer(adev->audio_route);
+ }
+
+ return 0;
+}
+
+static void check_usecases_codec_backend(struct audio_device *adev,
+ struct audio_usecase *uc_info,
+ snd_device_t snd_device)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ bool switch_device[AUDIO_USECASE_MAX];
+ int i, num_uc_to_switch = 0;
+
+ /*
+ * This function is to make sure that all the usecases that are active on
+ * the hardware codec backend are always routed to any one device that is
+ * handled by the hardware codec.
+ * For example, if low-latency and deep-buffer usecases are currently active
+ * on speaker and out_set_parameters(headset) is received on low-latency
+ * output, then we have to make sure deep-buffer is also switched to headset,
+ * because of the limitation that both the devices cannot be enabled
+ * at the same time as they share the same backend.
+ */
+ /* Disable all the usecases on the shared backend other than the
+ specified usecase */
+ for (i = 0; i < AUDIO_USECASE_MAX; i++)
+ switch_device[i] = false;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK &&
+ usecase != uc_info &&
+ usecase->out_snd_device != snd_device &&
+ usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
+ __func__, use_case_table[usecase->id],
+ platform_get_snd_device_name(usecase->out_snd_device));
+ disable_audio_route(adev, usecase, false);
+ switch_device[usecase->id] = true;
+ num_uc_to_switch++;
+ }
+ }
+
+ if (num_uc_to_switch) {
+ /* Make sure all the streams are de-routed before disabling the device */
+ audio_route_update_mixer(adev->audio_route);
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (switch_device[usecase->id]) {
+ disable_snd_device(adev, usecase->out_snd_device, false);
+ }
+ }
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (switch_device[usecase->id]) {
+ enable_snd_device(adev, snd_device, false);
+ }
+ }
+ /* Make sure new snd device is enabled before re-routing the streams */
+ audio_route_update_mixer(adev->audio_route);
+
+ /* Re-route all the usecases on the shared backend other than the
+ specified usecase to new snd devices */
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ /* Update the out_snd_device only before enabling the audio route */
+ if (switch_device[usecase->id] ) {
+ usecase->out_snd_device = snd_device;
+ enable_audio_route(adev, usecase, false);
+ }
+ }
+
+ audio_route_update_mixer(adev->audio_route);
+ }
+}
+
+static void check_and_route_capture_usecases(struct audio_device *adev,
+ struct audio_usecase *uc_info,
+ snd_device_t snd_device)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ bool switch_device[AUDIO_USECASE_MAX];
+ int i, num_uc_to_switch = 0;
+
+ /*
+ * This function is to make sure that all the active capture usecases
+ * are always routed to the same input sound device.
+ * For example, if audio-record and voice-call usecases are currently
+ * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
+ * is received for voice call then we have to make sure that audio-record
+ * usecase is also switched to earpiece i.e. voice-dmic-ef,
+ * because of the limitation that two devices cannot be enabled
+ * at the same time if they share the same backend.
+ */
+ for (i = 0; i < AUDIO_USECASE_MAX; i++)
+ switch_device[i] = false;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_CAPTURE &&
+ usecase != uc_info &&
+ usecase->in_snd_device != snd_device) {
+ ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
+ __func__, use_case_table[usecase->id],
+ platform_get_snd_device_name(usecase->in_snd_device));
+ disable_audio_route(adev, usecase, false);
+ switch_device[usecase->id] = true;
+ num_uc_to_switch++;
+ }
+ }
+
+ if (num_uc_to_switch) {
+ /* Make sure all the streams are de-routed before disabling the device */
+ audio_route_update_mixer(adev->audio_route);
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (switch_device[usecase->id]) {
+ disable_snd_device(adev, usecase->in_snd_device, false);
+ enable_snd_device(adev, snd_device, false);
+ }
+ }
+
+ /* Make sure new snd device is enabled before re-routing the streams */
+ audio_route_update_mixer(adev->audio_route);
+
+ /* Re-route all the usecases on the shared backend other than the
+ specified usecase to new snd devices */
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ /* Update the in_snd_device only before enabling the audio route */
+ if (switch_device[usecase->id] ) {
+ usecase->in_snd_device = snd_device;
+ enable_audio_route(adev, usecase, false);
+ }
+ }
+
+ audio_route_update_mixer(adev->audio_route);
+ }
+}
+
+static int disable_all_usecases_of_type(struct audio_device *adev,
+ usecase_type_t usecase_type,
+ bool update_mixer)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ int ret = 0;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == usecase_type) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ ret = disable_audio_route(adev, usecase, update_mixer);
+ if (ret) {
+ ALOGE("%s: Failed to disable usecase id %d",
+ __func__, usecase->id);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int enable_all_usecases_of_type(struct audio_device *adev,
+ usecase_type_t usecase_type,
+ bool update_mixer)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ int ret = 0;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == usecase_type) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ ret = enable_audio_route(adev, usecase, update_mixer);
+ if (ret) {
+ ALOGE("%s: Failed to enable usecase id %d",
+ __func__, usecase->id);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == VOICE_CALL) {
+ ALOGV("%s: usecase id %d", __func__, usecase->id);
+ return usecase->id;
+ }
+ }
+ return USECASE_INVALID;
+}
+
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+ audio_usecase_t uc_id)
+{
+ struct audio_usecase *usecase;
+ struct listnode *node;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->id == uc_id)
+ return usecase;
+ }
+ return NULL;
+}
+
+int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
+{
+ snd_device_t out_snd_device = SND_DEVICE_NONE;
+ snd_device_t in_snd_device = SND_DEVICE_NONE;
+ struct audio_usecase *usecase = NULL;
+ struct audio_usecase *vc_usecase = NULL;
+ struct audio_usecase *voip_usecase = NULL;
+ struct listnode *node;
+ int status = 0;
+
+ usecase = get_usecase_from_list(adev, uc_id);
+ if (usecase == NULL) {
+ ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
+ return -EINVAL;
+ }
+
+ if ((usecase->type == VOICE_CALL) ||
+ (usecase->type == VOIP_CALL)) {
+ out_snd_device = platform_get_output_snd_device(adev->platform,
+ usecase->stream.out->devices);
+ in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
+ usecase->devices = usecase->stream.out->devices;
+ } else {
+ /*
+ * If the voice call is active, use the sound devices of voice call usecase
+ * so that it would not result any device switch. All the usecases will
+ * be switched to new device when select_devices() is called for voice call
+ * usecase. This is to avoid switching devices for voice call when
+ * check_usecases_codec_backend() is called below.
+ */
+ if (usecase->type == PCM_PLAYBACK) {
+ usecase->devices = usecase->stream.out->devices;
+ in_snd_device = SND_DEVICE_NONE;
+ if (out_snd_device == SND_DEVICE_NONE) {
+ out_snd_device = platform_get_output_snd_device(adev->platform,
+ usecase->stream.out->devices);
+ if (usecase->stream.out == adev->primary_output &&
+ adev->active_input &&
+ adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ select_devices(adev, adev->active_input->usecase);
+ }
+ }
+ } else if (usecase->type == PCM_CAPTURE) {
+ usecase->devices = usecase->stream.in->device;
+ out_snd_device = SND_DEVICE_NONE;
+ if (in_snd_device == SND_DEVICE_NONE) {
+ if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
+ adev->primary_output && !adev->primary_output->standby) {
+ in_snd_device = platform_get_input_snd_device(adev->platform,
+ adev->primary_output->devices);
+ } else {
+ in_snd_device = platform_get_input_snd_device(adev->platform,
+ AUDIO_DEVICE_NONE);
+ }
+ }
+ }
+ }
+
+ if (out_snd_device == usecase->out_snd_device &&
+ in_snd_device == usecase->in_snd_device) {
+ return 0;
+ }
+
+ ALOGD("%s: out_snd_device(%d: %s) in_snd_device(%d: %s)", __func__,
+ out_snd_device, platform_get_snd_device_name(out_snd_device),
+ in_snd_device, platform_get_snd_device_name(in_snd_device));
+
+ /*
+ * Limitation: While in call, to do a device switch we need to disable
+ * and enable both RX and TX devices though one of them is same as current
+ * device.
+ */
+ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
+ status = platform_switch_voice_call_device_pre(adev->platform);
+ disable_all_usecases_of_type(adev, VOICE_CALL, true);
+ }
+
+ /* Disable current sound devices */
+ if (usecase->out_snd_device != SND_DEVICE_NONE) {
+ disable_audio_route(adev, usecase, true);
+ disable_snd_device(adev, usecase->out_snd_device, false);
+ }
+
+ if (usecase->in_snd_device != SND_DEVICE_NONE) {
+ disable_audio_route(adev, usecase, true);
+ disable_snd_device(adev, usecase->in_snd_device, false);
+ }
+
+ /* Enable new sound devices */
+ if (out_snd_device != SND_DEVICE_NONE) {
+ if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
+ check_usecases_codec_backend(adev, usecase, out_snd_device);
+ enable_snd_device(adev, out_snd_device, false);
+ }
+
+ if (in_snd_device != SND_DEVICE_NONE) {
+ check_and_route_capture_usecases(adev, usecase, in_snd_device);
+ enable_snd_device(adev, in_snd_device, false);
+ }
+
+ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
+ status = platform_switch_voice_call_device_post(adev->platform,
+ out_snd_device,
+ in_snd_device);
+
+ audio_route_update_mixer(adev->audio_route);
+
+ usecase->in_snd_device = in_snd_device;
+ usecase->out_snd_device = out_snd_device;
+
+ if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
+ enable_all_usecases_of_type(adev, usecase->type, true);
+ else
+ enable_audio_route(adev, usecase, true);
+
+ /* Applicable only on the targets that has external modem.
+ * Enable device command should be sent to modem only after
+ * enabling voice call mixer controls
+ */
+ if (usecase->type == VOICE_CALL)
+ status = platform_switch_voice_call_usecase_route_post(adev->platform,
+ out_snd_device,
+ in_snd_device);
+
+ return status;
+}
+
+static int stop_input_stream(struct stream_in *in)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ struct audio_device *adev = in->dev;
+
+ adev->active_input = NULL;
+
+ ALOGV("%s: enter: usecase(%d: %s)", __func__,
+ in->usecase, use_case_table[in->usecase]);
+ uc_info = get_usecase_from_list(adev, in->usecase);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, in->usecase);
+ return -EINVAL;
+ }
+
+ /* 1. Disable stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 2. Disable the tx device */
+ disable_snd_device(adev, uc_info->in_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int start_input_stream(struct stream_in *in)
+{
+ /* 1. Enable output device and stream routing controls */
+ int ret = 0;
+ struct audio_usecase *uc_info;
+ struct audio_device *adev = in->dev;
+
+ in->usecase = platform_update_usecase_from_source(in->source,in->usecase);
+ ALOGV("%s: enter: usecase(%d)", __func__, in->usecase);
+
+ in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
+ if (in->pcm_device_id < 0) {
+ ALOGE("%s: Could not find PCM device id for the usecase(%d)",
+ __func__, in->usecase);
+ ret = -EINVAL;
+ goto error_config;
+ }
+
+ adev->active_input = in;
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = in->usecase;
+ uc_info->type = PCM_CAPTURE;
+ uc_info->stream.in = in;
+ uc_info->devices = in->device;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+ select_devices(adev, in->usecase);
+
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+ __func__, SOUND_CARD, in->pcm_device_id, in->config.channels);
+ in->pcm = pcm_open(SOUND_CARD, in->pcm_device_id,
+ PCM_IN, &in->config);
+ if (in->pcm && !pcm_is_ready(in->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ ret = -EIO;
+ goto error_open;
+ }
+ ALOGV("%s: exit", __func__);
+ return ret;
+
+error_open:
+ stop_input_stream(in);
+
+error_config:
+ adev->active_input = NULL;
+ ALOGD("%s: exit: status(%d)", __func__, ret);
+
+ return ret;
+}
+
+static int check_input_parameters(uint32_t sample_rate,
+ audio_format_t format,
+ int channel_count)
+{
+ int ret = 0;
+
+ if ((format != AUDIO_FORMAT_PCM_16_BIT)) ret = -EINVAL;
+
+ switch (channel_count) {
+ case 1:
+ case 2:
+ case 6:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ switch (sample_rate) {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static size_t get_input_buffer_size(uint32_t sample_rate,
+ audio_format_t format,
+ int channel_count)
+{
+ size_t size = 0;
+
+ if (check_input_parameters(sample_rate, format, channel_count) != 0)
+ return 0;
+
+ size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+ /* ToDo: should use frame_size computed based on the format and
+ channel_count here. */
+ size *= sizeof(short) * channel_count;
+
+ /* make sure the size is multiple of 64 */
+ size += 0x3f;
+ size &= ~0x3f;
+
+ return size;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+
+ return in->config.rate;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ return -ENOSYS;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+
+ return in->config.period_size * audio_stream_frame_size(stream);
+}
+
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+
+ return in->channel_mask;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+
+ return in->format;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ int status = 0;
+ ALOGV("%s: enter", __func__);
+
+ if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ /* Ignore standby in case of voip call because the voip input
+ * stream is closed in adev_close_input_stream()
+ */
+ ALOGV("%s: Ignore Standby in VOIP call", __func__);
+ return status;
+ }
+
+ pthread_mutex_lock(&in->lock);
+ if (!in->standby) {
+ in->standby = true;
+ if (in->pcm) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ }
+ pthread_mutex_lock(&adev->lock);
+ status = stop_input_stream(in);
+ pthread_mutex_unlock(&adev->lock);
+ }
+ pthread_mutex_unlock(&in->lock);
+ ALOGV("%s: exit: status(%d)", __func__, status);
+ return status;
+}
+
+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)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int ret, val = 0;
+
+ ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs);
+ parms = str_parms_create_str(kvpairs);
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
+
+ pthread_mutex_lock(&in->lock);
+ pthread_mutex_lock(&adev->lock);
+ if (ret >= 0) {
+ val = atoi(value);
+ /* no audio source uses val == 0 */
+ if ((in->source != val) && (val != 0)) {
+ in->source = val;
+ }
+ }
+
+ 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;
+ /* If recording is in progress, change the tx device to new device */
+ if (!in->standby)
+ ret = select_devices(adev, in->usecase);
+ }
+ }
+
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&in->lock);
+
+ str_parms_destroy(parms);
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+static char* in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct str_parms *query = str_parms_create_str(keys);
+ char *str;
+ char value[256];
+ struct str_parms *reply = str_parms_create();
+ ALOGV("%s: enter: keys - %s", __func__, keys);
+
+ str = str_parms_to_str(reply);
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ ALOGV("%s: exit: returns - %s", __func__, str);
+ return str;
+}
+
+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)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ int i, ret = -1;
+
+ pthread_mutex_lock(&in->lock);
+ if (in->standby) {
+ pthread_mutex_lock(&adev->lock);
+ ret = start_input_stream(in);
+ pthread_mutex_unlock(&adev->lock);
+ if (ret != 0) {
+ goto exit;
+ }
+ in->standby = 0;
+ }
+
+ if (in->pcm) {
+ ret = pcm_read(in->pcm, buffer, bytes);
+ }
+
+exit:
+ pthread_mutex_unlock(&in->lock);
+
+ if (ret != 0) {
+ in_standby(&in->stream.common);
+ ALOGV("%s: read failed - sleeping for buffer duration", __func__);
+ usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) /
+ in_get_sample_rate(&in->stream.common));
+ }
+ return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+ return 0;
+}
+
+static int add_remove_audio_effect(const struct audio_stream *stream,
+ effect_handle_t effect,
+ bool enable)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ int status = 0;
+
+ return 0;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream,
+ effect_handle_t effect)
+{
+ ALOGV("%s: effect %p", __func__, effect);
+ return add_remove_audio_effect(stream, effect, true);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream,
+ effect_handle_t effect)
+{
+ ALOGV("%s: effect %p", __func__, effect);
+ return add_remove_audio_effect(stream, effect, false);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+ struct audio_device *adev = (struct audio_device *)dev;
+ struct str_parms *parms;
+ char *str;
+ char value[32];
+ int val;
+ int ret;
+
+ ALOGD("%s: enter: %s", __func__, kvpairs);
+
+ pthread_mutex_lock(&adev->lock);
+ parms = str_parms_create_str(kvpairs);
+
+ platform_set_parameters(adev->platform, parms);
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
+ if (ret >= 0) {
+ /* When set to false, HAL should disable EC and NS
+ * But it is currently not supported.
+ */
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+ adev->bluetooth_nrec = true;
+ else
+ adev->bluetooth_nrec = false;
+ }
+
+ ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
+ if (ret >= 0) {
+ if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+ adev->screen_off = false;
+ else
+ adev->screen_off = true;
+ }
+
+ ret = str_parms_get_int(parms, "rotation", &val);
+ if (ret >= 0) {
+ bool reverse_speakers = false;
+ switch(val) {
+ // FIXME: note that the code below assumes that the speakers are in the correct placement
+ // relative to the user when the device is rotated 90deg from its default rotation. This
+ // assumption is device-specific, not platform-specific like this code.
+ case 270:
+ reverse_speakers = true;
+ break;
+ case 0:
+ case 90:
+ case 180:
+ break;
+ default:
+ ALOGE("%s: unexpected rotation of %d", __func__, val);
+ }
+ if (adev->speaker_lr_swap != reverse_speakers) {
+ adev->speaker_lr_swap = reverse_speakers;
+ // only update the selected device if there is active pcm playback
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK) {
+ select_devices(adev, usecase->id);
+ break;
+ }
+ }
+ }
+ }
+
+ str_parms_destroy(parms);
+
+ pthread_mutex_unlock(&adev->lock);
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ return ret;
+}
+
+static char* adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ struct audio_device *adev = (struct audio_device *)dev;
+ struct str_parms *reply = str_parms_create();
+ struct str_parms *query = str_parms_create_str(keys);
+ char *str;
+
+ pthread_mutex_lock(&adev->lock);
+
+ platform_get_parameters(adev->platform, query, reply);
+ str = str_parms_to_str(reply);
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+
+ pthread_mutex_unlock(&adev->lock);
+ ALOGV("%s: exit: returns - %s", __func__, str);
+ return str;
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+ return 0;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+ int ret = 0;
+ return ret;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float 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 audio_device *adev = (struct audio_device *)dev;
+ pthread_mutex_lock(&adev->lock);
+ if (adev->mode != mode) {
+ ALOGD("%s mode %d\n", __func__, mode);
+ adev->mode = mode;
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+ int ret = 0;
+
+ return ret;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+ return 0;
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
+{
+ int channel_count = popcount(config->channel_mask);
+
+ 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 audio_device *adev = (struct audio_device *)dev;
+ struct stream_in *in;
+ int ret = 0, buffer_size, frame_size;
+ int channel_count = popcount(config->channel_mask);
+
+ ALOGV("%s: enter", __func__);
+ *stream_in = NULL;
+ if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
+ return -EINVAL;
+
+ in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
+
+ 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;
+
+ in->device = devices;
+ in->source = AUDIO_SOURCE_DEFAULT;
+ in->dev = adev;
+ in->standby = 1;
+ in->channel_mask = config->channel_mask;
+
+ /* Update config params with the requested sample rate and channels */
+ in->usecase = USECASE_AUDIO_RECORD;
+ in->config = pcm_config_audio_capture;
+ in->config.rate = config->sample_rate;
+ in->format = config->format;
+
+ {
+ in->config.channels = channel_count;
+ frame_size = audio_stream_frame_size((struct audio_stream *)in);
+ buffer_size = get_input_buffer_size(config->sample_rate,
+ config->format,
+ channel_count);
+ in->config.period_size = buffer_size / frame_size;
+ }
+
+ *stream_in = &in->stream;
+ ALOGV("%s: exit", __func__);
+ return ret;
+
+err_open:
+ free(in);
+ *stream_in = NULL;
+ return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream)
+{
+ int ret;
+ struct stream_in *in = (struct stream_in *)stream;
+ ALOGV("%s", __func__);
+
+ in_standby(&stream->common);
+
+ free(stream);
+
+ return;
+}
+
+static int adev_dump(const audio_hw_device_t *device, int fd)
+{
+ return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+ struct audio_device *adev = (struct audio_device *)device;
+
+ if (!adev)
+ return 0;
+
+ pthread_mutex_lock(&adev_init_lock);
+
+ if ((--audio_device_ref_count) == 0) {
+ audio_route_free(adev->audio_route);
+ free(adev->snd_dev_ref_cnt);
+ platform_deinit(adev->platform);
+ free(device);
+ adev = NULL;
+ }
+ pthread_mutex_unlock(&adev_init_lock);
+ return 0;
+}
+
+static int adev_open(const hw_module_t *module, const char *name,
+ hw_device_t **device)
+{
+ int i, ret;
+
+ ALOGD("%s: enter", __func__);
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
+
+ pthread_mutex_lock(&adev_init_lock);
+ if (audio_device_ref_count != 0){
+ *device = &adev->device.common;
+ audio_device_ref_count++;
+ ALOGD("%s: returning existing instance of adev", __func__);
+ ALOGD("%s: exit", __func__);
+ pthread_mutex_unlock(&adev_init_lock);
+ return 0;
+ }
+
+ adev = calloc(1, sizeof(struct audio_device));
+
+ adev->device.common.tag = HARDWARE_DEVICE_TAG;
+ adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ adev->device.common.module = (struct hw_module_t *)module;
+ adev->device.common.close = adev_close;
+
+ adev->device.init_check = adev_init_check;
+ adev->device.set_voice_volume = adev_set_voice_volume;
+ adev->device.set_master_volume = adev_set_master_volume;
+ adev->device.get_master_volume = adev_get_master_volume;
+ adev->device.set_master_mute = adev_set_master_mute;
+ adev->device.get_master_mute = adev_get_master_mute;
+ adev->device.set_mode = adev_set_mode;
+ adev->device.set_mic_mute = adev_set_mic_mute;
+ adev->device.get_mic_mute = adev_get_mic_mute;
+ adev->device.set_parameters = adev_set_parameters;
+ adev->device.get_parameters = adev_get_parameters;
+ adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+ adev->device.open_output_stream = adev_open_output_stream;
+ adev->device.close_output_stream = adev_close_output_stream;
+ adev->device.open_input_stream = adev_open_input_stream;
+ adev->device.close_input_stream = adev_close_input_stream;
+ adev->device.dump = adev_dump;
+
+ /* Set the default route before the PCM stream is opened */
+ adev->mode = AUDIO_MODE_NORMAL;
+ adev->active_input = NULL;
+ adev->primary_output = NULL;
+ adev->out_device = AUDIO_DEVICE_NONE;
+ adev->bluetooth_nrec = true;
+ adev->acdb_settings = TTY_MODE_OFF;
+ /* adev->cur_hdmi_channels = 0; by calloc() */
+ adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
+ list_init(&adev->usecase_list);
+
+ /* Loads platform specific libraries dynamically */
+ adev->platform = platform_init(adev);
+ if (!adev->platform) {
+ free(adev->snd_dev_ref_cnt);
+ free(adev);
+ ALOGE("%s: Failed to init platform data, aborting.", __func__);
+ *device = NULL;
+ return -EINVAL;
+ }
+
+ if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
+ adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
+ if (adev->visualizer_lib == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
+ adev->visualizer_start_output =
+ (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ "visualizer_hal_start_output");
+ adev->visualizer_stop_output =
+ (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ "visualizer_hal_stop_output");
+ }
+ }
+ *device = &adev->device.common;
+
+ audio_device_ref_count++;
+ pthread_mutex_unlock(&adev_init_lock);
+
+ ALOGV("%s: exit", __func__);
+ 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 = "MPQ Audio HAL",
+ .author = "The Linux Foundation",
+ .methods = &hal_module_methods,
+ },
+};
diff --git a/hal_mpq/audio_hw.h b/hal_mpq/audio_hw.h
new file mode 100644
index 0000000..e1319a5
--- /dev/null
+++ b/hal_mpq/audio_hw.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_HW_H
+#define QCOM_AUDIO_HW_H
+
+#include <cutils/list.h>
+#include <hardware/audio.h>
+#include <tinyalsa/asoundlib.h>
+#include <tinycompress/tinycompress.h>
+
+#include <audio_route/audio_route.h>
+
+#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
+
+/* Flags used to initialize acdb_settings variable that goes to ACDB library */
+#define DMIC_FLAG 0x00000002
+#define QMIC_FLAG 0x00000004
+#define TTY_MODE_OFF 0x00000010
+#define TTY_MODE_FULL 0x00000020
+#define TTY_MODE_VCO 0x00000040
+#define TTY_MODE_HCO 0x00000080
+#define TTY_MODE_CLEAR 0xFFFFFF0F
+
+#define ACDB_DEV_TYPE_OUT 1
+#define ACDB_DEV_TYPE_IN 2
+
+#define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define DEFAULT_HDMI_OUT_CHANNELS 2
+
+typedef int snd_device_t;
+
+/* These are the supported use cases by the hardware.
+ * Each usecase is mapped to a specific PCM device.
+ * Refer to pcm_device_table[].
+ */
+typedef enum {
+ USECASE_INVALID = -1,
+ /* Playback usecases */
+ USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0,
+ USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
+ USECASE_AUDIO_PLAYBACK_MULTI_CH,
+ USECASE_AUDIO_PLAYBACK_OFFLOAD,
+
+ /* FM usecase */
+ USECASE_AUDIO_PLAYBACK_FM,
+
+ /* Capture usecases */
+ USECASE_AUDIO_RECORD,
+ USECASE_AUDIO_RECORD_COMPRESS,
+ USECASE_AUDIO_RECORD_LOW_LATENCY,
+ USECASE_AUDIO_RECORD_FM_VIRTUAL,
+
+ /* Voice usecase */
+ USECASE_VOICE_CALL,
+
+ /* Voice extension usecases */
+ USECASE_VOICE2_CALL,
+ USECASE_VOLTE_CALL,
+ USECASE_QCHAT_CALL,
+ USECASE_COMPRESS_VOIP_CALL,
+
+ USECASE_INCALL_REC_UPLINK,
+ USECASE_INCALL_REC_DOWNLINK,
+ USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
+
+ USECASE_INCALL_MUSIC_UPLINK,
+ USECASE_INCALL_MUSIC_UPLINK2,
+
+ USECASE_AUDIO_SPKR_CALIB_RX,
+ USECASE_AUDIO_SPKR_CALIB_TX,
+ AUDIO_USECASE_MAX
+} audio_usecase_t;
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/*
+ * tinyAlsa library interprets period size as number of frames
+ * one frame = channel_count * sizeof (pcm sample)
+ * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes
+ * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes
+ * We should take care of returning proper size when AudioFlinger queries for
+ * the buffer size of an input/output stream
+ */
+
+enum {
+ OFFLOAD_CMD_EXIT, /* exit compress offload thread loop*/
+ OFFLOAD_CMD_DRAIN, /* send a full drain request to DSP */
+ OFFLOAD_CMD_PARTIAL_DRAIN, /* send a partial drain request to DSP */
+ OFFLOAD_CMD_WAIT_FOR_BUFFER, /* wait for buffer released by DSP */
+};
+
+enum {
+ OFFLOAD_STATE_IDLE,
+ OFFLOAD_STATE_PLAYING,
+ OFFLOAD_STATE_PAUSED,
+};
+
+struct offload_cmd {
+ struct listnode node;
+ int cmd;
+ int data[];
+};
+
+struct stream_out {
+ struct audio_stream_out stream;
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ pthread_cond_t cond;
+ struct pcm_config config;
+ struct compr_config compr_config;
+ struct pcm *pcm;
+ struct compress *compr;
+ int standby;
+ int pcm_device_id;
+ unsigned int sample_rate;
+ audio_channel_mask_t channel_mask;
+ audio_format_t format;
+ audio_devices_t devices;
+ audio_output_flags_t flags;
+ audio_usecase_t usecase;
+ /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
+ audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+ bool muted;
+ uint64_t written; /* total frames written, not cleared when entering standby */
+ audio_io_handle_t handle;
+
+ int non_blocking;
+ int playback_started;
+ int offload_state;
+ pthread_cond_t offload_cond;
+ pthread_t offload_thread;
+ struct listnode offload_cmd_list;
+ bool offload_thread_blocked;
+
+ stream_callback_t offload_callback;
+ void *offload_cookie;
+ struct compr_gapless_mdata gapless_mdata;
+ int send_new_metadata;
+
+ struct audio_device *dev;
+};
+
+struct 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 standby;
+ int source;
+ int pcm_device_id;
+ int device;
+ audio_channel_mask_t channel_mask;
+ audio_usecase_t usecase;
+ bool enable_aec;
+ bool enable_ns;
+ audio_format_t format;
+
+ struct audio_device *dev;
+};
+
+typedef enum {
+ PCM_PLAYBACK,
+ PCM_CAPTURE,
+ VOICE_CALL,
+ VOIP_CALL
+} usecase_type_t;
+
+union stream_ptr {
+ struct stream_in *in;
+ struct stream_out *out;
+};
+
+struct audio_usecase {
+ struct listnode list;
+ audio_usecase_t id;
+ usecase_type_t type;
+ audio_devices_t devices;
+ snd_device_t out_snd_device;
+ snd_device_t in_snd_device;
+ union stream_ptr stream;
+};
+
+struct audio_device {
+ struct audio_hw_device device;
+ pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ struct mixer *mixer;
+ audio_mode_t mode;
+ audio_devices_t out_device;
+ struct stream_in *active_input;
+ struct stream_out *primary_output;
+ bool bluetooth_nrec;
+ bool screen_off;
+ int *snd_dev_ref_cnt;
+ struct listnode usecase_list;
+ struct audio_route *audio_route;
+ int acdb_settings;
+ bool speaker_lr_swap;
+ unsigned int cur_hdmi_channels;
+
+ void *platform;
+
+ void *visualizer_lib;
+ int (*visualizer_start_output)(audio_io_handle_t);
+ int (*visualizer_stop_output)(audio_io_handle_t);
+};
+
+static const char * const use_case_table[AUDIO_USECASE_MAX] = {
+ [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
+ [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
+ [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
+ [USECASE_AUDIO_RECORD] = "audio-record",
+ [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
+ [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
+ [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
+ [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
+ [USECASE_VOICE_CALL] = "voice-call",
+
+ [USECASE_VOICE2_CALL] = "voice2-call",
+ [USECASE_VOLTE_CALL] = "volte-call",
+ [USECASE_QCHAT_CALL] = "qchat-call",
+ [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
+ [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
+ [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
+ [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
+ [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
+ [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
+ [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
+ [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
+};
+
+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);
+
+void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out *stream);
+
+int select_devices(struct audio_device *adev,
+ audio_usecase_t uc_id);
+int disable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer);
+int disable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer);
+int enable_snd_device(struct audio_device *adev,
+ snd_device_t snd_device,
+ bool update_mixer);
+int enable_audio_route(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ bool update_mixer);
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+ audio_usecase_t uc_id);
+/*
+ * NOTE: when multiple mutexes have to be acquired, always take the
+ * stream_in or stream_out mutex first, followed by the audio_device mutex.
+ */
+
+#endif // QCOM_AUDIO_HW_H
diff --git a/hal_mpq/audio_stream_out.c b/hal_mpq/audio_stream_out.c
new file mode 100644
index 0000000..71eb2f1
--- /dev/null
+++ b/hal_mpq/audio_stream_out.c
@@ -0,0 +1,1157 @@
+/* audio_stream_out.c
+ **
+ ** Copyright 2008-2009 Wind River Systems
+ ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved
+ ** Not a Contribution, Apache license notifications and license are retained
+ ** for attribution purposes only.
+ **
+ ** 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_stream_out"
+/*#define LOG_NDEBUG 0*/
+/*#define VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <cutils/sched_policy.h>
+
+#include <system/thread_defs.h>
+#include "audio_hw.h"
+#include "platform_api.h"
+#include <platform.h>
+
+#include "sound/compress_params.h"
+
+#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
+#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
+/* ToDo: Check and update a proper value in msec */
+#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
+#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+
+struct pcm_config pcm_config_deep_buffer = {
+ .channels = 2,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
+ .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
+ .stop_threshold = INT_MAX,
+ .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
+};
+
+struct pcm_config pcm_config_low_latency = {
+ .channels = 2,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+ .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+ .stop_threshold = INT_MAX,
+ .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
+struct pcm_config pcm_config_hdmi_multi = {
+ .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
+ .period_size = HDMI_MULTI_PERIOD_SIZE,
+ .period_count = HDMI_MULTI_PERIOD_COUNT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+
+struct string_to_enum {
+ const char *name;
+ uint32_t value;
+};
+
+static const struct string_to_enum out_channels_name_to_enum_table[] = {
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+
+static bool is_supported_format(audio_format_t format)
+{
+ if (format == AUDIO_FORMAT_MP3 ||
+ format == AUDIO_FORMAT_AAC)
+ return true;
+
+ return false;
+}
+
+static int get_snd_codec_id(audio_format_t format)
+{
+ int id = 0;
+
+ switch (format) {
+ case AUDIO_FORMAT_MP3:
+ id = SND_AUDIOCODEC_MP3;
+ break;
+ case AUDIO_FORMAT_AAC:
+ id = SND_AUDIOCODEC_AAC;
+ break;
+ default:
+ ALOGE("%s: Unsupported audio format", __func__);
+ }
+
+ return id;
+}
+
+/* must be called with hw device mutex locked */
+static int read_hdmi_channel_masks(struct stream_out *out)
+{
+ int ret = 0;
+ int channels = platform_edid_get_max_channels(out->dev->platform);
+
+ switch (channels) {
+ /*
+ * Do not handle stereo output in Multi-channel cases
+ * Stereo case is handled in normal playback path
+ */
+ case 6:
+ ALOGV("%s: HDMI supports 5.1", __func__);
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+ break;
+ case 8:
+ ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__);
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+ out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
+ break;
+ default:
+ ALOGE("HDMI does not support multi channel playback");
+ ret = -ENOSYS;
+ break;
+ }
+ return ret;
+}
+
+/* must be called with out->lock locked */
+static int send_offload_cmd_l(struct stream_out* out, int command)
+{
+ struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
+
+ ALOGVV("%s %d", __func__, command);
+
+ cmd->cmd = command;
+ list_add_tail(&out->offload_cmd_list, &cmd->node);
+ pthread_cond_signal(&out->offload_cond);
+ return 0;
+}
+
+/* must be called iwth out->lock locked */
+static void stop_compressed_output_l(struct stream_out *out)
+{
+ out->offload_state = OFFLOAD_STATE_IDLE;
+ out->playback_started = 0;
+ out->send_new_metadata = 1;
+ if (out->compr != NULL) {
+ compress_stop(out->compr);
+ while (out->offload_thread_blocked) {
+ pthread_cond_wait(&out->cond, &out->lock);
+ }
+ }
+}
+
+static void *offload_thread_loop(void *context)
+{
+ struct stream_out *out = (struct stream_out *) context;
+ struct listnode *item;
+
+ out->offload_state = OFFLOAD_STATE_IDLE;
+ out->playback_started = 0;
+
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+ set_sched_policy(0, SP_FOREGROUND);
+ prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
+
+ ALOGV("%s", __func__);
+ pthread_mutex_lock(&out->lock);
+ for (;;) {
+ struct offload_cmd *cmd = NULL;
+ stream_callback_event_t event;
+ bool send_callback = false;
+
+ ALOGVV("%s offload_cmd_list %d out->offload_state %d",
+ __func__, list_empty(&out->offload_cmd_list),
+ out->offload_state);
+ if (list_empty(&out->offload_cmd_list)) {
+ ALOGV("%s SLEEPING", __func__);
+ pthread_cond_wait(&out->offload_cond, &out->lock);
+ ALOGV("%s RUNNING", __func__);
+ continue;
+ }
+
+ item = list_head(&out->offload_cmd_list);
+ cmd = node_to_item(item, struct offload_cmd, node);
+ list_remove(item);
+
+ ALOGVV("%s STATE %d CMD %d out->compr %p",
+ __func__, out->offload_state, cmd->cmd, out->compr);
+
+ if (cmd->cmd == OFFLOAD_CMD_EXIT) {
+ free(cmd);
+ break;
+ }
+
+ if (out->compr == NULL) {
+ ALOGE("%s: Compress handle is NULL", __func__);
+ pthread_cond_signal(&out->cond);
+ continue;
+ }
+ out->offload_thread_blocked = true;
+ pthread_mutex_unlock(&out->lock);
+ send_callback = false;
+ switch(cmd->cmd) {
+ case OFFLOAD_CMD_WAIT_FOR_BUFFER:
+ compress_wait(out->compr, -1);
+ send_callback = true;
+ event = STREAM_CBK_EVENT_WRITE_READY;
+ break;
+ case OFFLOAD_CMD_PARTIAL_DRAIN:
+ compress_next_track(out->compr);
+ compress_partial_drain(out->compr);
+ send_callback = true;
+ event = STREAM_CBK_EVENT_DRAIN_READY;
+ break;
+ case OFFLOAD_CMD_DRAIN:
+ compress_drain(out->compr);
+ send_callback = true;
+ event = STREAM_CBK_EVENT_DRAIN_READY;
+ break;
+ default:
+ ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
+ break;
+ }
+ pthread_mutex_lock(&out->lock);
+ out->offload_thread_blocked = false;
+ pthread_cond_signal(&out->cond);
+ if (send_callback) {
+ out->offload_callback(event, NULL, out->offload_cookie);
+ }
+ free(cmd);
+ }
+
+ pthread_cond_signal(&out->cond);
+ while (!list_empty(&out->offload_cmd_list)) {
+ item = list_head(&out->offload_cmd_list);
+ list_remove(item);
+ free(node_to_item(item, struct offload_cmd, node));
+ }
+ pthread_mutex_unlock(&out->lock);
+
+ return NULL;
+}
+
+static int create_offload_callback_thread(struct stream_out *out)
+{
+ pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
+ list_init(&out->offload_cmd_list);
+ pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
+ offload_thread_loop, out);
+ return 0;
+}
+
+static int destroy_offload_callback_thread(struct stream_out *out)
+{
+ pthread_mutex_lock(&out->lock);
+ stop_compressed_output_l(out);
+ send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
+
+ pthread_mutex_unlock(&out->lock);
+ pthread_join(out->offload_thread, (void **) NULL);
+ pthread_cond_destroy(&out->offload_cond);
+
+ return 0;
+}
+
+static bool allow_hdmi_channel_config(struct audio_device *adev)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ bool ret = true;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ /*
+ * If voice call is already existing, do not proceed further to avoid
+ * disabling/enabling both RX and TX devices, CSD calls, etc.
+ * Once the voice call done, the HDMI channels can be configured to
+ * max channels of remaining use cases.
+ */
+ if (usecase->id == USECASE_VOICE_CALL) {
+ ALOGD("%s: voice call is active, no change in HDMI channels",
+ __func__);
+ ret = false;
+ break;
+ } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+ ALOGD("%s: multi channel playback is active, "
+ "no change in HDMI channels", __func__);
+ ret = false;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+static int check_and_set_hdmi_channels(struct audio_device *adev,
+ unsigned int channels)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+
+ /* Check if change in HDMI channel config is allowed */
+ if (!allow_hdmi_channel_config(adev))
+ return 0;
+
+ if (channels == adev->cur_hdmi_channels) {
+ ALOGD("%s: Requested channels are same as current", __func__);
+ return 0;
+ }
+
+ platform_set_hdmi_channels(adev->platform, channels);
+ adev->cur_hdmi_channels = channels;
+
+ /*
+ * Deroute all the playback streams routed to HDMI so that
+ * the back end is deactivated. Note that backend will not
+ * be deactivated if any one stream is connected to it.
+ */
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK &&
+ usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ disable_audio_route(adev, usecase, true);
+ }
+ }
+
+ /*
+ * Enable all the streams disabled above. Now the HDMI backend
+ * will be activated with new channel configuration
+ */
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->type == PCM_PLAYBACK &&
+ usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ enable_audio_route(adev, usecase, true);
+ }
+ }
+
+ return 0;
+}
+
+static int stop_output_stream(struct stream_out *out)
+{
+ int i, ret = 0;
+ struct audio_usecase *uc_info;
+ struct audio_device *adev = out->dev;
+
+ ALOGV("%s: enter: usecase(%d: %s)", __func__,
+ out->usecase, use_case_table[out->usecase]);
+ uc_info = get_usecase_from_list(adev, out->usecase);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, out->usecase);
+ return -EINVAL;
+ }
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
+ adev->visualizer_stop_output != NULL)
+ adev->visualizer_stop_output(out->handle);
+
+ /* 1. Get and set stream specific mixer controls */
+ disable_audio_route(adev, uc_info, true);
+
+ /* 2. Disable the rx device */
+ disable_snd_device(adev, uc_info->out_snd_device, true);
+
+ list_remove(&uc_info->list);
+ free(uc_info);
+
+ /* Must be called after removing the usecase from list */
+ if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+ check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
+
+ ALOGV("%s: exit: status(%d)", __func__, ret);
+ return ret;
+}
+
+int start_output_stream(struct stream_out *out)
+{
+ int ret = 0;
+ struct audio_usecase *uc_info;
+ struct audio_device *adev = out->dev;
+
+ ALOGV("%s: enter: usecase(%d: %s) devices(%#x)",
+ __func__, out->usecase, use_case_table[out->usecase], out->devices);
+ out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+ if (out->pcm_device_id < 0) {
+ ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
+ __func__, out->pcm_device_id, out->usecase);
+ ret = -EINVAL;
+ goto error_config;
+ }
+
+ uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+ uc_info->id = out->usecase;
+ uc_info->type = PCM_PLAYBACK;
+ uc_info->stream.out = out;
+ uc_info->devices = out->devices;
+ uc_info->in_snd_device = SND_DEVICE_NONE;
+ uc_info->out_snd_device = SND_DEVICE_NONE;
+
+ /* This must be called before adding this usecase to the list */
+ if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+ check_and_set_hdmi_channels(adev, out->config.channels);
+
+ list_add_tail(&adev->usecase_list, &uc_info->list);
+
+ select_devices(adev, out->usecase);
+
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
+ __func__, 0, out->pcm_device_id);
+ if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ out->pcm = pcm_open(SOUND_CARD, out->pcm_device_id,
+ PCM_OUT | PCM_MONOTONIC, &out->config);
+ if (out->pcm && !pcm_is_ready(out->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+ ret = -EIO;
+ goto error_open;
+ }
+ } else {
+ out->pcm = NULL;
+ out->compr = compress_open(SOUND_CARD, out->pcm_device_id,
+ COMPRESS_IN, &out->compr_config);
+ if (out->compr && !is_compress_ready(out->compr)) {
+ ALOGE("%s: %s", __func__, compress_get_error(out->compr));
+ compress_close(out->compr);
+ out->compr = NULL;
+ ret = -EIO;
+ goto error_open;
+ }
+ if (out->offload_callback)
+ compress_nonblock(out->compr, out->non_blocking);
+
+ if (adev->visualizer_start_output != NULL)
+ adev->visualizer_start_output(out->handle);
+ }
+ ALOGV("%s: exit", __func__);
+ return 0;
+error_open:
+ stop_output_stream(out);
+error_config:
+ return ret;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ return out->sample_rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ return -ENOSYS;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
+ return out->compr_config.fragment_size;
+
+ return out->config.period_size * audio_stream_frame_size(stream);
+}
+
+static uint32_t out_get_channels(const struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ return out->channel_mask;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ return out->format;
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+
+ ALOGV("%s: enter: usecase(%d: %s)", __func__,
+ out->usecase, use_case_table[out->usecase]);
+ if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ /* Ignore standby in case of voip call because the voip output
+ * stream is closed in adev_close_output_stream()
+ */
+ ALOGV("%s: Ignore Standby in VOIP call", __func__);
+ return 0;
+ }
+
+ pthread_mutex_lock(&out->lock);
+ pthread_mutex_lock(&adev->lock);
+ if (!out->standby) {
+ out->standby = true;
+ if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (out->pcm) {
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+ }
+ } else {
+ stop_compressed_output_l(out);
+ out->gapless_mdata.encoder_delay = 0;
+ out->gapless_mdata.encoder_padding = 0;
+ if (out->compr != NULL) {
+ compress_close(out->compr);
+ out->compr = NULL;
+ }
+ }
+ stop_output_stream(out);
+ }
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ ALOGV("%s: exit", __func__);
+ return 0;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+ return 0;
+}
+
+static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
+{
+ int ret = 0;
+ char value[32];
+ struct compr_gapless_mdata tmp_mdata;
+
+ if (!out || !parms) {
+ return -EINVAL;
+ }
+
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
+ if (ret >= 0) {
+ tmp_mdata.encoder_delay = atoi(value); //whats a good limit check?
+ } else {
+ return -EINVAL;
+ }
+
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
+ if (ret >= 0) {
+ tmp_mdata.encoder_padding = atoi(value);
+ } else {
+ return -EINVAL;
+ }
+
+ out->gapless_mdata = tmp_mdata;
+ out->send_new_metadata = 1;
+ ALOGV("%s new encoder delay %u and padding %u", __func__,
+ out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
+
+ return 0;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ struct audio_usecase *usecase;
+ struct listnode *node;
+ struct str_parms *parms;
+ char value[32];
+ int ret, val = 0;
+ bool select_new_device = false;
+
+ ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
+ __func__, out->usecase, use_case_table[out->usecase], kvpairs);
+ 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(&out->lock);
+ pthread_mutex_lock(&adev->lock);
+
+ /*
+ * When HDMI cable is unplugged the music playback is paused and
+ * the policy manager sends routing=0. But the audioflinger
+ * continues to write data until standby time (3sec).
+ * As the HDMI core is turned off, the write gets blocked.
+ * Avoid this by routing audio to speaker until standby.
+ */
+ if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL &&
+ val == AUDIO_DEVICE_NONE) {
+ val = AUDIO_DEVICE_OUT_SPEAKER;
+ }
+
+ /*
+ * select_devices() call below switches all the usecases on the same
+ * backend to the new device. Refer to check_usecases_codec_backend() in
+ * the select_devices(). But how do we undo this?
+ *
+ * For example, music playback is active on headset (deep-buffer usecase)
+ * and if we go to ringtones and select a ringtone, low-latency usecase
+ * will be started on headset+speaker. As we can't enable headset+speaker
+ * and headset devices at the same time, select_devices() switches the music
+ * playback to headset+speaker while starting low-lateny usecase for ringtone.
+ * So when the ringtone playback is completed, how do we undo the same?
+ *
+ * We are relying on the out_set_parameters() call on deep-buffer output,
+ * once the ringtone playback is ended.
+ * NOTE: We should not check if the current devices are same as new devices.
+ * Because select_devices() must be called to switch back the music
+ * playback to headset.
+ */
+ if (val != 0) {
+ out->devices = val;
+
+ if (!out->standby)
+ select_devices(adev, out->usecase);
+ }
+
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ }
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ parse_compress_metadata(out, parms);
+ }
+
+ str_parms_destroy(parms);
+ ALOGV("%s: exit: code(%d)", __func__, ret);
+ return ret;
+}
+
+static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct str_parms *query = str_parms_create_str(keys);
+ char *str;
+ char value[256];
+ struct str_parms *reply = str_parms_create();
+ size_t i, j;
+ int ret;
+ bool first = true;
+ ALOGV("%s: enter: keys - %s", __func__, keys);
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
+ if (ret >= 0) {
+ value[0] = '\0';
+ i = 0;
+ while (out->supported_channel_masks[i] != 0) {
+ for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) {
+ if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
+ if (!first) {
+ strlcat(value, "|", sizeof(value));
+ }
+ strlcat(value, out_channels_name_to_enum_table[j].name, sizeof(value));
+ first = false;
+ break;
+ }
+ }
+ i++;
+ }
+ str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
+ str = str_parms_to_str(reply);
+ }
+ str_parms_destroy(query);
+ str_parms_destroy(reply);
+ ALOGV("%s: exit: returns - %s", __func__, str);
+ return str;
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
+ return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+
+ return (out->config.period_count * out->config.period_size * 1000) /
+ (out->config.rate);
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ int volume[2];
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+ /* only take left channel into account: the API is for stereo anyway */
+ out->muted = (left == 0.0f);
+ return 0;
+ } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ const char *mixer_ctl_name = "Compress Playback Volume";
+ struct audio_device *adev = out->dev;
+ struct mixer_ctl *ctl;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
+ volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
+ mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
+ return 0;
+ }
+
+ return -ENOSYS;
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
+ size_t bytes)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ ssize_t ret = 0;
+
+ pthread_mutex_lock(&out->lock);
+ if (out->standby) {
+ out->standby = false;
+ pthread_mutex_lock(&adev->lock);
+ ret = start_output_stream(out);
+ pthread_mutex_unlock(&adev->lock);
+ /* ToDo: If use case is compress offload should return 0 */
+ if (ret != 0) {
+ out->standby = true;
+ goto exit;
+ }
+ }
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes);
+ if (out->send_new_metadata) {
+ ALOGVV("send new gapless metadata");
+ compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
+ out->send_new_metadata = 0;
+ }
+
+ ret = compress_write(out->compr, buffer, bytes);
+ ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret);
+ if (ret >= 0 && ret < (ssize_t)bytes) {
+ send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
+ }
+ if (!out->playback_started) {
+ compress_start(out->compr);
+ out->playback_started = 1;
+ out->offload_state = OFFLOAD_STATE_PLAYING;
+ }
+ pthread_mutex_unlock(&out->lock);
+ return ret;
+ } else {
+ if (out->pcm) {
+ if (out->muted)
+ memset((void *)buffer, 0, bytes);
+ ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
+ ret = pcm_write(out->pcm, (void *)buffer, bytes);
+ if (ret == 0)
+ out->written += bytes / (out->config.channels * sizeof(short));
+ }
+ }
+
+exit:
+ pthread_mutex_unlock(&out->lock);
+
+ if (ret != 0) {
+ if (out->pcm)
+ ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm));
+ out_standby(&out->stream.common);
+ usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
+ out_get_sample_rate(&out->stream.common));
+ }
+ return bytes;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ *dsp_frames = 0;
+ if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
+ pthread_mutex_lock(&out->lock);
+ if (out->compr != NULL) {
+ compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
+ &out->sample_rate);
+ ALOGVV("%s rendered frames %d sample_rate %d",
+ __func__, *dsp_frames, out->sample_rate);
+ }
+ pthread_mutex_unlock(&out->lock);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t 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_get_presentation_position(const struct audio_stream_out *stream,
+ uint64_t *frames, struct timespec *timestamp)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ int ret = -1;
+ unsigned long dsp_frames;
+
+ pthread_mutex_lock(&out->lock);
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (out->compr != NULL) {
+ compress_get_tstamp(out->compr, &dsp_frames,
+ &out->sample_rate);
+ ALOGVV("%s rendered frames %ld sample_rate %d",
+ __func__, dsp_frames, out->sample_rate);
+ *frames = dsp_frames;
+ ret = 0;
+ /* this is the best we can do */
+ clock_gettime(CLOCK_MONOTONIC, timestamp);
+ }
+ } else {
+ if (out->pcm) {
+ size_t 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;
+ // This adjustment accounts for buffering after app processor.
+ // It is based on estimated DSP latency per use case, rather than exact.
+ signed_frames -=
+ (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL);
+
+ // It would be unusual for this value to be negative, but check just in case ...
+ if (signed_frames >= 0) {
+ *frames = signed_frames;
+ ret = 0;
+ }
+ }
+ }
+ }
+
+ pthread_mutex_unlock(&out->lock);
+
+ return ret;
+}
+
+static int out_set_callback(struct audio_stream_out *stream,
+ stream_callback_t callback, void *cookie)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ ALOGV("%s", __func__);
+ pthread_mutex_lock(&out->lock);
+ out->offload_callback = callback;
+ out->offload_cookie = cookie;
+ pthread_mutex_unlock(&out->lock);
+ return 0;
+}
+
+static int out_pause(struct audio_stream_out* stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ int status = -ENOSYS;
+ ALOGV("%s", __func__);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ pthread_mutex_lock(&out->lock);
+ if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
+ status = compress_pause(out->compr);
+ out->offload_state = OFFLOAD_STATE_PAUSED;
+ }
+ pthread_mutex_unlock(&out->lock);
+ }
+ return status;
+}
+
+static int out_resume(struct audio_stream_out* stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ int status = -ENOSYS;
+ ALOGV("%s", __func__);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ status = 0;
+ pthread_mutex_lock(&out->lock);
+ if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
+ status = compress_resume(out->compr);
+ out->offload_state = OFFLOAD_STATE_PLAYING;
+ }
+ pthread_mutex_unlock(&out->lock);
+ }
+ return status;
+}
+
+static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ int status = -ENOSYS;
+ ALOGV("%s", __func__);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ pthread_mutex_lock(&out->lock);
+ if (type == AUDIO_DRAIN_EARLY_NOTIFY)
+ status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
+ else
+ status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
+ pthread_mutex_unlock(&out->lock);
+ }
+ return status;
+}
+
+static int out_flush(struct audio_stream_out* stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ ALOGV("%s", __func__);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ pthread_mutex_lock(&out->lock);
+ stop_compressed_output_l(out);
+ pthread_mutex_unlock(&out->lock);
+ return 0;
+ }
+ return -ENOSYS;
+}
+
+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 audio_device *adev = (struct audio_device *)dev;
+ struct stream_out *out;
+ int i, ret;
+
+ ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
+ __func__, config->sample_rate, config->channel_mask, devices, flags);
+ *stream_out = NULL;
+ out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
+
+ if (devices == AUDIO_DEVICE_NONE)
+ devices = AUDIO_DEVICE_OUT_SPEAKER;
+
+ out->flags = flags;
+ out->devices = devices;
+ out->dev = adev;
+ out->format = config->format;
+ out->sample_rate = config->sample_rate;
+ out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
+ out->handle = handle;
+
+ /* Init use case and pcm_config */
+ if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT &&
+ out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ pthread_mutex_lock(&adev->lock);
+ ret = read_hdmi_channel_masks(out);
+ pthread_mutex_unlock(&adev->lock);
+ if (ret != 0)
+ goto error_open;
+
+ if (config->sample_rate == 0)
+ config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ if (config->channel_mask == 0)
+ config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+
+ out->channel_mask = config->channel_mask;
+ out->sample_rate = config->sample_rate;
+ out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
+ out->config = pcm_config_hdmi_multi;
+ out->config.rate = config->sample_rate;
+ out->config.channels = popcount(out->channel_mask);
+ out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
+ config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
+ ALOGE("%s: Unsupported Offload information", __func__);
+ ret = -EINVAL;
+ goto error_open;
+ }
+ if (!is_supported_format(config->offload_info.format)) {
+ ALOGE("%s: Unsupported audio format", __func__);
+ ret = -EINVAL;
+ goto error_open;
+ }
+
+ out->compr_config.codec = (struct snd_codec *)
+ calloc(1, sizeof(struct snd_codec));
+
+ out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
+ if (config->offload_info.channel_mask)
+ out->channel_mask = config->offload_info.channel_mask;
+ else if (config->channel_mask)
+ out->channel_mask = config->channel_mask;
+ out->format = config->offload_info.format;
+ out->sample_rate = config->offload_info.sample_rate;
+
+ out->stream.set_callback = out_set_callback;
+ out->stream.pause = out_pause;
+ out->stream.resume = out_resume;
+ out->stream.drain = out_drain;
+ out->stream.flush = out_flush;
+
+ out->compr_config.codec->id =
+ get_snd_codec_id(config->offload_info.format);
+ out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+ out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+ out->compr_config.codec->sample_rate =
+ compress_get_alsa_rate(config->offload_info.sample_rate);
+ out->compr_config.codec->bit_rate =
+ config->offload_info.bit_rate;
+ out->compr_config.codec->ch_in =
+ popcount(config->channel_mask);
+ out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
+
+ if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
+ out->non_blocking = 1;
+
+ out->send_new_metadata = 1;
+ create_offload_callback_thread(out);
+ ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
+ __func__, config->offload_info.version,
+ config->offload_info.bit_rate);
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
+ out->config = pcm_config_low_latency;
+ out->sample_rate = out->config.rate;
+ } else {
+ out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+ out->config = pcm_config_deep_buffer;
+ out->sample_rate = out->config.rate;
+ }
+
+ if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ if(adev->primary_output == NULL)
+ adev->primary_output = out;
+ else {
+ ALOGE("%s: Primary output is already opened", __func__);
+ ret = -EEXIST;
+ goto error_open;
+ }
+ }
+
+ /* Check if this usecase is already existing */
+ pthread_mutex_lock(&adev->lock);
+ if (get_usecase_from_list(adev, out->usecase) != NULL) {
+ ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
+ pthread_mutex_unlock(&adev->lock);
+ ret = -EEXIST;
+ goto error_open;
+ }
+ pthread_mutex_unlock(&adev->lock);
+
+ 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->standby = 1;
+ /* out->muted = false; by calloc() */
+ /* out->written = 0; by calloc() */
+
+ pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
+ pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
+
+ config->format = out->stream.common.get_format(&out->stream.common);
+ config->channel_mask = out->stream.common.get_channels(&out->stream.common);
+ config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
+
+ *stream_out = &out->stream;
+ ALOGV("%s: exit", __func__);
+ return 0;
+
+error_open:
+ free(out);
+ *stream_out = NULL;
+ ALOGD("%s: exit: ret %d", __func__, ret);
+ return ret;
+}
+
+void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ int ret = 0;
+
+ ALOGV("%s: enter", __func__);
+ out_standby(&stream->common);
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ destroy_offload_callback_thread(out);
+
+ if (out->compr_config.codec != NULL)
+ free(out->compr_config.codec);
+ }
+ pthread_cond_destroy(&out->cond);
+ pthread_mutex_destroy(&out->lock);
+ free(stream);
+ ALOGV("%s: exit", __func__);
+}
diff --git a/hal_mpq/mpq8092/hw_info.c b/hal_mpq/mpq8092/hw_info.c
new file mode 100644
index 0000000..97b7804
--- /dev/null
+++ b/hal_mpq/mpq8092/hw_info.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "hardware_info"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+
+struct hardware_info {
+ char name[HW_INFO_ARRAY_MAX_SIZE];
+ char type[HW_INFO_ARRAY_MAX_SIZE];
+ /* variables for handling target variants */
+ uint32_t num_snd_devices;
+ char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
+ snd_device_t *snd_devices;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define LITERAL_TO_STRING(x) #x
+#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
+ " ASSERT_FATAL(" #condition ") failed.")
+
+static const snd_device_t tabla_cdp_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+};
+
+static const snd_device_t taiko_fluid_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static const snd_device_t taiko_CDP_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t taiko_liquid_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_IN_SPEAKER_MIC,
+ SND_DEVICE_IN_HEADSET_MIC,
+ SND_DEVICE_IN_VOICE_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+ SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+ SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+ SND_DEVICE_IN_QUAD_MIC,
+ SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+ SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+};
+
+static const snd_device_t taiko_DB_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_IN_SPEAKER_MIC,
+ SND_DEVICE_IN_HEADSET_MIC,
+ SND_DEVICE_IN_QUAD_MIC,
+};
+
+static const snd_device_t tapan_lite_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t tapan_skuf_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ /*SND_DEVICE_OUT_SPEAKER_AND_ANC_FB_HEADSET,*/
+};
+
+static const snd_device_t tapan_lite_skuf_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+};
+
+static const snd_device_t helicon_skuab_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+};
+
+static void update_hardware_info_8092(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "mpq8092-tabla-cdp-snd-card")) {
+ strlcpy(hw_info->type, "cdp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "mpq8092", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8084 device", __func__);
+ }
+}
+
+static void update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card")) {
+ strlcpy(hw_info->type, "mtp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "apq8084-taiko-cdp-snd-card")) {
+ strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "apq8084", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices);
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "apq8084-taiko-liquid-snd-card")) {
+ strlcpy(hw_info->type , " liquid", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "apq8084", sizeof(hw_info->type));
+ hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices);
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8084 device", __func__);
+ }
+}
+
+static void update_hardware_info_8974(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "msm8974-taiko-mtp-snd-card")) {
+ strlcpy(hw_info->type, " mtp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8974-taiko-cdp-snd-card")) {
+ strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_CDP_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_CDP_variant_devices);
+ strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8974-taiko-fluid-snd-card")) {
+ strlcpy(hw_info->type, " fluid", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *) taiko_fluid_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_fluid_variant_devices);
+ strlcpy(hw_info->dev_extn, "-fluid", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8974-taiko-liquid-snd-card")) {
+ strlcpy(hw_info->type, " liquid", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_liquid_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_liquid_variant_devices);
+ strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "apq8074-taiko-db-snd-card")) {
+ strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8974", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)taiko_DB_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(taiko_DB_variant_devices);
+ strlcpy(hw_info->dev_extn, "-DB", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8974 device", __func__);
+ }
+}
+
+static void update_hardware_info_8610(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "msm8x10-snd-card")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8x10-skuab-snd-card")) {
+ strlcpy(hw_info->type, "skuab", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)helicon_skuab_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(helicon_skuab_variant_devices);
+ strlcpy(hw_info->dev_extn, "-skuab", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8x10-skuaa-snd-card")) {
+ strlcpy(hw_info->type, " skuaa", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8x10", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8x10 device", __func__);
+ }
+}
+
+static void update_hardware_info_8226(struct hardware_info *hw_info, const char *snd_card_name)
+{
+ if (!strcmp(snd_card_name, "msm8226-tapan-snd-card")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8226-tapan9302-snd-card")) {
+ strlcpy(hw_info->type, "tapan_lite", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)tapan_lite_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_variant_devices);
+ strlcpy(hw_info->dev_extn, "-lite", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8226-tapan-skuf-snd-card")) {
+ strlcpy(hw_info->type, " skuf", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *) tapan_skuf_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tapan_skuf_variant_devices);
+ strlcpy(hw_info->dev_extn, "-skuf", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8226-tapan9302-skuf-snd-card")) {
+ strlcpy(hw_info->type, " tapan9302-skuf", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8226", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)tapan_lite_skuf_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tapan_lite_skuf_variant_devices);
+ strlcpy(hw_info->dev_extn, "-skuf-lite", sizeof(hw_info->dev_extn));
+ } else {
+ ALOGW("%s: Not an 8x26 device", __func__);
+ }
+}
+
+void *hw_info_init(const char *snd_card_name)
+{
+ struct hardware_info *hw_info;
+
+ hw_info = malloc(sizeof(struct hardware_info));
+
+ if(strstr(snd_card_name, "mpq8092") ||
+ strstr(snd_card_name, "mpq8092")) {
+ ALOGV("8092 - variant soundcard");
+ update_hardware_info_8092(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "msm8974") ||
+ strstr(snd_card_name, "apq8074")) {
+ ALOGV("8974 - variant soundcard");
+ update_hardware_info_8974(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "msm8226")) {
+ ALOGV("8x26 - variant soundcard");
+ update_hardware_info_8226(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "msm8x10")) {
+ ALOGV("8x10 - variant soundcard");
+ update_hardware_info_8610(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "apq8084")) {
+ ALOGV("8084 - variant soundcard");
+ update_hardware_info_8084(hw_info, snd_card_name);
+ } else {
+ ALOGE("%s: Unupported target %s:",__func__, snd_card_name);
+ CHECK(0);
+ free(hw_info);
+ hw_info = NULL;
+ }
+
+ return hw_info;
+}
+
+void hw_info_deinit(void *hw_info)
+{
+ struct hardware_info *my_data = (struct hardware_info*) hw_info;
+
+ if(!my_data)
+ free(my_data);
+}
+
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+ char *device_name)
+{
+ struct hardware_info *my_data = (struct hardware_info*) hw_info;
+ uint32_t i = 0;
+
+ snd_device_t *snd_devices =
+ (snd_device_t *) my_data->snd_devices;
+
+ if(snd_devices != NULL) {
+ for (i = 0; i < my_data->num_snd_devices; i++) {
+ if (snd_device == (snd_device_t)snd_devices[i]) {
+ ALOGV("extract dev_extn device %d, extn = %s",
+ (snd_device_t)snd_devices[i], my_data->dev_extn);
+ CHECK(strlcat(device_name, my_data->dev_extn,
+ DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE);
+ break;
+ }
+ }
+ }
+ ALOGD("%s : device_name = %s", __func__,device_name);
+}
diff --git a/hal_mpq/mpq8092/platform.c b/hal_mpq/mpq8092/platform.c
new file mode 100644
index 0000000..d7d67d5
--- /dev/null
+++ b/hal_mpq/mpq8092/platform.c
@@ -0,0 +1,1272 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 "msm8974_platform"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <cutils/str_parms.h>
+#include <audio_hw.h>
+#include <platform_api.h>
+#include "platform.h"
+
+#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
+
+/*
+ * This file will have a maximum of 38 bytes:
+ *
+ * 4 bytes: number of audio blocks
+ * 4 bytes: total length of Short Audio Descriptor (SAD) blocks
+ * Maximum 10 * 3 bytes: SAD blocks
+ */
+#define MAX_SAD_BLOCKS 10
+#define SAD_BLOCK_SIZE 3
+
+/* EDID format ID for LPCM audio */
+#define EDID_FORMAT_LPCM 1
+
+/* Retry for delay in FW loading*/
+#define RETRY_NUMBER 10
+#define RETRY_US 500000
+
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
+
+#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence"
+#define AUDIO_PARAMETER_KEY_BTSCO "bt_samplerate"
+#define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable"
+
+struct audio_block_header
+{
+ int reserved;
+ int length;
+};
+
+/* Audio calibration related functions */
+typedef void (*acdb_deallocate_t)();
+typedef int (*acdb_init_t)();
+typedef void (*acdb_send_audio_cal_t)(int, int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+
+struct platform_data {
+ struct audio_device *adev;
+ bool fluence_in_spkr_mode;
+ bool fluence_in_voice_call;
+ bool fluence_in_voice_rec;
+ bool fluence_in_audio_rec;
+ int fluence_type;
+ int btsco_sample_rate;
+ bool slowtalk;
+ /* Audio calibration related functions */
+ void *acdb_handle;
+ acdb_init_t acdb_init;
+ acdb_deallocate_t acdb_deallocate;
+ acdb_send_audio_cal_t acdb_send_audio_cal;
+ acdb_send_voice_cal_t acdb_send_voice_cal;
+
+ void *hw_info;
+ struct csd_data *csd;
+};
+
+static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+ [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
+ DEEP_BUFFER_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+ LOWLATENCY_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+ MULTIMEDIA2_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
+ {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
+ [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
+ [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+ LOWLATENCY_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
+ MULTIMEDIA2_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
+ [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
+ [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
+ [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
+ [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
+ [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE},
+ [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+ AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE,
+ INCALL_MUSIC_UPLINK_PCM_DEVICE},
+ [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE,
+ INCALL_MUSIC_UPLINK2_PCM_DEVICE},
+ [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
+ [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
+};
+
+/* Array to store sound devices */
+static const char * const device_table[SND_DEVICE_MAX] = {
+ [SND_DEVICE_NONE] = "none",
+ /* Playback sound devices */
+ [SND_DEVICE_OUT_HANDSET] = "handset",
+ [SND_DEVICE_OUT_SPEAKER] = "speaker",
+ [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
+ [SND_DEVICE_OUT_HEADPHONES] = "headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+ [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
+ [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
+ [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
+ [SND_DEVICE_OUT_HDMI] = "hdmi",
+ [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
+ [SND_DEVICE_OUT_BT_SCO] = "bt-sco-headset",
+ [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
+ [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
+ [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
+ [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+ [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
+ [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
+ [SND_DEVICE_OUT_TRANSMISSION_FM] = "transmission-fm",
+ [SND_DEVICE_OUT_ANC_HEADSET] = "anc-headphones",
+ [SND_DEVICE_OUT_ANC_FB_HEADSET] = "anc-fb-headphones",
+ [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = "voice-anc-headphones",
+ [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = "voice-anc-fb-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
+ [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
+ [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+
+ /* Capture sound devices */
+ [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_DMIC] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_NS] = "dmic-endfire",
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = "dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_MIC] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_NS] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = "speaker-mic",
+ [SND_DEVICE_IN_SPEAKER_DMIC] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_NS] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = "speaker-dmic-endfire",
+ [SND_DEVICE_IN_HEADSET_MIC] = "headset-mic",
+ [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = "headset-mic",
+ [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic",
+ [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic",
+ [SND_DEVICE_IN_HDMI_MIC] = "hdmi-mic",
+ [SND_DEVICE_IN_BT_SCO_MIC] = "bt-sco-mic",
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
+ [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
+ [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
+ [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
+ [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
+ [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+ [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
+ [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
+ [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
+ [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+ [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
+ [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm",
+ [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic",
+ [SND_DEVICE_IN_QUAD_MIC] = "quad-mic",
+ [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
+ [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
+ [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+};
+
+/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
+static const int acdb_device_table[SND_DEVICE_MAX] = {
+ [SND_DEVICE_NONE] = -1,
+ [SND_DEVICE_OUT_HANDSET] = 7,
+ [SND_DEVICE_OUT_SPEAKER] = 14,
+ [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
+ [SND_DEVICE_OUT_HEADPHONES] = 10,
+ [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+ [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
+ [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+ [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
+ [SND_DEVICE_OUT_HDMI] = 18,
+ [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
+ [SND_DEVICE_OUT_BT_SCO] = 22,
+ [SND_DEVICE_OUT_BT_SCO_WB] = 39,
+ [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
+ [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
+ [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+ [SND_DEVICE_OUT_AFE_PROXY] = 0,
+ [SND_DEVICE_OUT_USB_HEADSET] = 0,
+ [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
+ [SND_DEVICE_OUT_TRANSMISSION_FM] = 0,
+ [SND_DEVICE_OUT_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_ANC_FB_HEADSET] = 27,
+ [SND_DEVICE_OUT_VOICE_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
+ [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
+ [SND_DEVICE_OUT_ANC_HANDSET] = 103,
+ [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
+
+ [SND_DEVICE_IN_HANDSET_MIC] = 4,
+ [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
+ [SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
+ [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
+ [SND_DEVICE_IN_HANDSET_DMIC] = 41,
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC] = 109,
+ [SND_DEVICE_IN_HANDSET_DMIC_NS] = 110,
+ [SND_DEVICE_IN_HANDSET_DMIC_AEC_NS] = 111,
+ [SND_DEVICE_IN_SPEAKER_MIC] = 11,
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC] = 112,
+ [SND_DEVICE_IN_SPEAKER_MIC_NS] = 113,
+ [SND_DEVICE_IN_SPEAKER_MIC_AEC_NS] = 114,
+ [SND_DEVICE_IN_SPEAKER_DMIC] = 43,
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC] = 115,
+ [SND_DEVICE_IN_SPEAKER_DMIC_NS] = 116,
+ [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS] = 117,
+ [SND_DEVICE_IN_HEADSET_MIC] = 8,
+ [SND_DEVICE_IN_HEADSET_MIC_FLUENCE] = 47,
+ [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
+ [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
+ [SND_DEVICE_IN_HDMI_MIC] = 4,
+ [SND_DEVICE_IN_BT_SCO_MIC] = 21,
+ [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
+ [SND_DEVICE_IN_CAMCORDER_MIC] = 4,
+ [SND_DEVICE_IN_VOICE_DMIC] = 41,
+ [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
+ [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
+ [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
+ [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+ [SND_DEVICE_IN_VOICE_REC_MIC] = 4,
+ [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
+ [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
+ [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41,
+ [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+ [SND_DEVICE_IN_CAPTURE_FM] = 0,
+ [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104,
+ [SND_DEVICE_IN_QUAD_MIC] = 46,
+ [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
+ [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
+ [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+};
+
+#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
+#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
+
+static int set_echo_reference(struct mixer *mixer, const char* ec_ref)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "EC_REF_RX";
+
+ ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("Setting EC Reference: %s", ec_ref);
+ mixer_ctl_set_enum_by_string(ctl, ec_ref);
+ return 0;
+}
+
+static struct csd_data *open_csd_client()
+{
+ struct csd_data *csd = calloc(1, sizeof(struct csd_data));
+
+ csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+ if (csd->csd_client == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+ goto error;
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+ csd->deinit = (deinit_t)dlsym(csd->csd_client,
+ "csd_client_deinit");
+ if (csd->deinit == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+ dlerror());
+ goto error;
+ }
+ csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+ "csd_client_disable_device");
+ if (csd->disable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_disable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+ "csd_client_enable_device");
+ if (csd->enable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_enable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+ "csd_client_start_voice");
+ if (csd->start_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+ "csd_client_stop_voice");
+ if (csd->stop_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->volume = (volume_t)dlsym(csd->csd_client,
+ "csd_client_volume");
+ if (csd->volume == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_volume",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+ "csd_client_mic_mute");
+ if (csd->mic_mute == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+ "csd_client_slow_talk");
+ if (csd->slow_talk == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+ "csd_client_start_playback");
+ if (csd->start_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+ "csd_client_stop_playback");
+ if (csd->stop_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_record = (start_record_t)dlsym(csd->csd_client,
+ "csd_client_start_record");
+ if (csd->start_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+ "csd_client_stop_record");
+ if (csd->stop_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+ if (csd->init == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_init",
+ __func__, dlerror());
+ goto error;
+ } else {
+ csd->init();
+ }
+ }
+ return csd;
+
+error:
+ free(csd);
+ csd = NULL;
+ return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+ if (csd != NULL) {
+ csd->deinit();
+ dlclose(csd->csd_client);
+ free(csd);
+ csd = NULL;
+ }
+}
+
+void *platform_init(struct audio_device *adev)
+{
+ char platform[PROPERTY_VALUE_MAX];
+ char baseband[PROPERTY_VALUE_MAX];
+ char value[PROPERTY_VALUE_MAX];
+ struct platform_data *my_data;
+ int retry_num = 0;
+ const char *snd_card_name;
+
+ adev->mixer = mixer_open(MIXER_CARD);
+
+ while (!adev->mixer && retry_num < RETRY_NUMBER) {
+ usleep(RETRY_US);
+ adev->mixer = mixer_open(MIXER_CARD);
+ retry_num++;
+ }
+
+ if (!adev->mixer) {
+ ALOGE("Unable to open the mixer, aborting.");
+ return NULL;
+ }
+
+ adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH);
+
+ if (!adev->audio_route) {
+ ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+ return NULL;
+ }
+
+ my_data = calloc(1, sizeof(struct platform_data));
+
+ snd_card_name = mixer_get_name(adev->mixer);
+ my_data->hw_info = hw_info_init(snd_card_name);
+ if (!my_data->hw_info) {
+ ALOGE("%s: Failed to init hardware info", __func__);
+ }
+
+ my_data->adev = adev;
+ my_data->btsco_sample_rate = SAMPLE_RATE_8KHZ;
+ my_data->fluence_in_spkr_mode = false;
+ my_data->fluence_in_voice_call = false;
+ my_data->fluence_in_voice_rec = false;
+ my_data->fluence_in_audio_rec = false;
+ my_data->fluence_type = FLUENCE_NONE;
+
+ property_get("ro.qc.sdk.audio.fluencetype", value, "");
+ if (!strncmp("fluencepro", value, sizeof("fluencepro"))) {
+ my_data->fluence_type = FLUENCE_QUAD_MIC | FLUENCE_DUAL_MIC;
+ } else if (!strncmp("fluence", value, sizeof("fluence"))) {
+ my_data->fluence_type = FLUENCE_DUAL_MIC;
+ } else {
+ my_data->fluence_type = FLUENCE_NONE;
+ }
+
+ if (my_data->fluence_type != FLUENCE_NONE) {
+ property_get("persist.audio.fluence.voicecall",value,"");
+ if (!strncmp("true", value, sizeof("true"))) {
+ my_data->fluence_in_voice_call = true;
+ }
+
+ property_get("persist.audio.fluence.voicerec",value,"");
+ if (!strncmp("true", value, sizeof("true"))) {
+ my_data->fluence_in_voice_rec = true;
+ }
+
+ property_get("persist.audio.fluence.audiorec",value,"");
+ if (!strncmp("true", value, sizeof("true"))) {
+ my_data->fluence_in_audio_rec = true;
+ }
+
+ property_get("persist.audio.fluence.speaker",value,"");
+ if (!strncmp("true", value, sizeof("true"))) {
+ my_data->fluence_in_spkr_mode = true;
+ }
+ }
+
+ my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+ if (my_data->acdb_handle == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+ my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_deallocate_ACDB");
+ my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_send_audio_cal");
+ if (!my_data->acdb_send_audio_cal)
+ ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s",
+ __func__, LIB_ACDB_LOADER);
+ my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_send_voice_cal");
+ my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_init_ACDB");
+ if (my_data->acdb_init == NULL)
+ ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
+ else
+ my_data->acdb_init();
+ }
+
+ /* If platform is apq8084 and baseband is MDM, load CSD Client specific
+ * symbols. Voice call is handled by MDM and apps processor talks to
+ * MDM through CSD Client
+ */
+ property_get("ro.board.platform", platform, "");
+ property_get("ro.baseband", baseband, "");
+ if (!strncmp("apq8084", platform, sizeof("apq8084")) &&
+ !strncmp("mdm", baseband, sizeof("mdm"))) {
+ my_data->csd = open_csd_client();
+ }
+
+ return my_data;
+}
+
+void platform_deinit(void *platform)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ hw_info_deinit(my_data->hw_info);
+ close_csd_client(my_data->csd);
+
+ free(platform);
+}
+
+const char *platform_get_snd_device_name(snd_device_t snd_device)
+{
+ if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+ return device_table[snd_device];
+ else
+ return "";
+}
+
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+ char *device_name)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+
+ if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+ strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+ hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+ } else {
+ strlcpy(device_name, "", DEVICE_NAME_MAX_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+{
+ if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
+ strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
+ strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
+ else if(snd_device == SND_DEVICE_OUT_BT_SCO)
+ strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
+ else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
+ strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_HDMI)
+ strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
+ strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_AFE_PROXY)
+ strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_USB_HEADSET)
+ strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)
+ strlcat(mixer_path, " speaker-and-usb-headphones",
+ MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC)
+ strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
+ strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH);
+ else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM)
+ strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH);
+}
+
+int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
+{
+ int device_id;
+ if (device_type == PCM_PLAYBACK)
+ device_id = pcm_device_table[usecase][0];
+ else
+ device_id = pcm_device_table[usecase][1];
+ return device_id;
+}
+
+int platform_send_audio_calibration(void *platform, snd_device_t snd_device)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_dev_id, acdb_dev_type;
+
+ acdb_dev_id = acdb_device_table[snd_device];
+ if (acdb_dev_id < 0) {
+ ALOGE("%s: Could not find acdb id for device(%d)",
+ __func__, snd_device);
+ return -EINVAL;
+ }
+ if (my_data->acdb_send_audio_cal) {
+ ("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+ __func__, snd_device, acdb_dev_id);
+ if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+ snd_device < SND_DEVICE_OUT_END)
+ acdb_dev_type = ACDB_DEV_TYPE_OUT;
+ else
+ acdb_dev_type = ACDB_DEV_TYPE_IN;
+ my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type);
+ }
+ return 0;
+}
+
+int platform_switch_voice_call_device_pre(void *platform)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL &&
+ my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+ /* This must be called before disabling mixer controls on APQ side */
+ ret = my_data->csd->disable_device();
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_switch_voice_call_device_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_rx_id, acdb_tx_id;
+
+ if (my_data->acdb_send_voice_cal == NULL) {
+ ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
+ } else {
+ acdb_rx_id = acdb_device_table[out_snd_device];
+ acdb_tx_id = acdb_device_table[in_snd_device];
+
+ if (acdb_rx_id > 0 && acdb_tx_id > 0)
+ my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id);
+ else
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
+ }
+
+ return 0;
+}
+
+int platform_switch_voice_call_usecase_route_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_rx_id, acdb_tx_id;
+ int ret = 0;
+
+ acdb_rx_id = acdb_device_table[out_snd_device];
+ acdb_tx_id = acdb_device_table[in_snd_device];
+
+ if (my_data->csd != NULL) {
+ if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+ ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+ my_data->adev->acdb_settings);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device, failed, error %d",
+ __func__, ret);
+ }
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
+ }
+ }
+ return ret;
+}
+
+int platform_start_voice_call(void *platform, uint32_t vsid)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_stop_voice_call(void *platform, uint32_t vsid)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_set_voice_volume(void *platform, int volume)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voice Rx Gain";
+ int vol_index = 0, ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+ // Voice volume levels are mapped to adsp volume levels as follows.
+ // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1 0 -> 0
+ // But this values don't changed in kernel. So, below change is need.
+ vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
+ set_values[0] = vol_index;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("Setting voice volume index: %d", set_values[0]);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->volume(ALL_SESSION_VSID, volume);
+ if (ret < 0) {
+ ALOGE("%s: csd_volume error %d", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_set_mic_mute(void *platform, bool state)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voice Tx Mute";
+ int ret = 0;
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID,
+ DEFAULT_VOLUME_RAMP_DURATION_MS};
+
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("Setting voice mute state: %d", state);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state);
+ if (ret < 0) {
+ ALOGE("%s: csd_mic_mute error %d", __func__, ret);
+ }
+ }
+ return ret;
+}
+
+snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ audio_mode_t mode = adev->mode;
+ snd_device_t snd_device = SND_DEVICE_NONE;
+
+ audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+ AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+ int channel_count = popcount(channel_mask);
+
+ ALOGV("%s: enter: output devices(%#x)", __func__, devices);
+ if (devices == AUDIO_DEVICE_NONE ||
+ devices & AUDIO_DEVICE_BIT_IN) {
+ ALOGV("%s: Invalid output devices (%#x)", __func__, devices);
+ goto exit;
+ }
+
+ if (popcount(devices) == 2) {
+ if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+ } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+ } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+ } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_SPEAKER)) {
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
+ } else {
+ ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+ goto exit;
+ }
+ if (snd_device != SND_DEVICE_NONE) {
+ goto exit;
+ }
+ }
+
+ if (popcount(devices) != 1) {
+ ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+ goto exit;
+ }
+
+ if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_OUT_HEADPHONES;
+ } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (adev->speaker_lr_swap)
+ snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+ else
+ snd_device = SND_DEVICE_OUT_SPEAKER;
+ } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+ else
+ snd_device = SND_DEVICE_OUT_BT_SCO;
+ } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ snd_device = SND_DEVICE_OUT_HDMI ;
+ } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_OUT_USB_HEADSET;
+ } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+ snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
+ } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+ snd_device = SND_DEVICE_OUT_HANDSET;
+ } else {
+ ALOGE("%s: Unknown device(s) %#x", __func__, devices);
+ }
+exit:
+ ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]);
+ return snd_device;
+}
+
+snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ audio_source_t source = (adev->active_input == NULL) ?
+ AUDIO_SOURCE_DEFAULT : adev->active_input->source;
+
+ audio_mode_t mode = adev->mode;
+ audio_devices_t in_device = ((adev->active_input == NULL) ?
+ AUDIO_DEVICE_NONE : adev->active_input->device)
+ & ~AUDIO_DEVICE_BIT_IN;
+ audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
+ AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
+ snd_device_t snd_device = SND_DEVICE_NONE;
+ int channel_count = popcount(channel_mask);
+
+ ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
+ __func__, out_device, in_device);
+ if (source == AUDIO_SOURCE_CAMCORDER) {
+ if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+ in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ snd_device = SND_DEVICE_IN_CAMCORDER_MIC;
+ }
+ } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+ if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (channel_count == 2) {
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else if (adev->active_input->enable_ns)
+ snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
+ else if (my_data->fluence_type != FLUENCE_NONE &&
+ my_data->fluence_in_voice_rec) {
+ snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else {
+ snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
+ }
+ }
+ } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ if (out_device & AUDIO_DEVICE_OUT_SPEAKER)
+ in_device = AUDIO_DEVICE_IN_BACK_MIC;
+ if (adev->active_input) {
+ if (adev->active_input->enable_aec &&
+ adev->active_input->enable_ns) {
+ if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+ my_data->fluence_in_spkr_mode) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
+ } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+ }
+ set_echo_reference(adev->mixer, "SLIM_RX");
+ } else if (adev->active_input->enable_aec) {
+ if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
+ } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_AEC;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+ }
+ set_echo_reference(adev->mixer, "SLIM_RX");
+ } else if (adev->active_input->enable_ns) {
+ if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
+ } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC_NS;
+ adev->acdb_settings |= DMIC_FLAG;
+ } else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
+ }
+ set_echo_reference(adev->mixer, "NONE");
+ } else
+ set_echo_reference(adev->mixer, "NONE");
+ }
+ } else if (source == AUDIO_SOURCE_MIC) {
+ if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
+ channel_count == 1 ) {
+ if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
+ my_data->fluence_in_audio_rec)
+ snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+ }
+ } else if (source == AUDIO_SOURCE_FM_RX ||
+ source == AUDIO_SOURCE_FM_RX_A2DP) {
+ snd_device = SND_DEVICE_IN_CAPTURE_FM;
+ } else if (source == AUDIO_SOURCE_DEFAULT) {
+ goto exit;
+ }
+
+
+ if (snd_device != SND_DEVICE_NONE) {
+ goto exit;
+ }
+
+ if (in_device != AUDIO_DEVICE_NONE &&
+ !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
+ !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
+ if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ if (channel_count == 2)
+ snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
+ else
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ else
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
+ snd_device = SND_DEVICE_IN_HDMI_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
+ in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_FM_RX) {
+ snd_device = SND_DEVICE_IN_CAPTURE_FM;
+ } else {
+ ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
+ ALOGW("%s: Using default handset-mic", __func__);
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ }
+ } else {
+ if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ snd_device = SND_DEVICE_IN_HEADSET_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (channel_count > 1)
+ snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
+ else
+ snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
+ if (my_data->btsco_sample_rate == SAMPLE_RATE_16KHZ)
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+ else
+ snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ snd_device = SND_DEVICE_IN_HDMI_MIC;
+ } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+ } else {
+ ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
+ ALOGW("%s: Using default handset-mic", __func__);
+ snd_device = SND_DEVICE_IN_HANDSET_MIC;
+ }
+ }
+exit:
+ ALOGV("%s: exit: in_snd_device(%s)", __func__, device_table[snd_device]);
+ return snd_device;
+}
+
+int platform_set_hdmi_channels(void *platform, int channel_count)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *channel_cnt_str = NULL;
+ const char *mixer_ctl_name = "HDMI_RX Channels";
+ switch (channel_count) {
+ case 8:
+ channel_cnt_str = "Eight"; break;
+ case 7:
+ channel_cnt_str = "Seven"; break;
+ case 6:
+ channel_cnt_str = "Six"; break;
+ case 5:
+ channel_cnt_str = "Five"; break;
+ case 4:
+ channel_cnt_str = "Four"; break;
+ case 3:
+ channel_cnt_str = "Three"; break;
+ default:
+ channel_cnt_str = "Two"; break;
+ }
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ ALOGV("HDMI channel count: %s", channel_cnt_str);
+ mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+ return 0;
+}
+
+int platform_edid_get_max_channels(void *platform)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+ char *sad = block;
+ int num_audio_blocks;
+ int channel_count;
+ int max_channels = 0;
+ int i, ret, count;
+
+ struct mixer_ctl *ctl;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+ return 0;
+ }
+
+ mixer_ctl_update(ctl);
+
+ count = mixer_ctl_get_num_values(ctl);
+
+ /* Read SAD blocks, clamping the maximum size for safety */
+ if (count > (int)sizeof(block))
+ count = (int)sizeof(block);
+
+ ret = mixer_ctl_get_array(ctl, block, count);
+ if (ret != 0) {
+ ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+ return 0;
+ }
+
+ /* Calculate the number of SAD blocks */
+ num_audio_blocks = count / SAD_BLOCK_SIZE;
+
+ for (i = 0; i < num_audio_blocks; i++) {
+ /* Only consider LPCM blocks */
+ if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
+ sad += 3;
+ continue;
+ }
+
+ channel_count = (sad[0] & 0x7) + 1;
+ if (channel_count > max_channels)
+ max_channels = channel_count;
+
+ /* Advance to next block */
+ sad += 3;
+ }
+
+ return max_channels;
+}
+
+static int platform_set_slowtalk(struct platform_data *my_data, bool state)
+{
+ int ret = 0;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Slowtalk Enable";
+ uint32_t set_values[ ] = {0,
+ ALL_SESSION_VSID};
+
+ set_values[0] = state;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ } else {
+ ALOGV("Setting slowtalk state: %d", state);
+ ret = mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+ my_data->slowtalk = state;
+ }
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
+ return ret;
+}
+
+int platform_set_parameters(void *platform, struct str_parms *parms)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ char *str;
+ char value[32];
+ int val;
+ int ret = 0;
+
+ ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
+
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val);
+ if (ret >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO);
+ my_data->btsco_sample_rate = val;
+ }
+
+ ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val);
+ if (ret >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
+ ret = platform_set_slowtalk(my_data, val);
+ if (ret)
+ ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
+ }
+
+ ALOGV("%s: exit with code(%d)", __func__, ret);
+ return ret;
+}
+
+int platform_set_incall_recoding_session_id(void *platform,
+ uint32_t session_id)
+{
+ int ret = 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "Voc VSID";
+ int num_ctl_values;
+ int i;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ } else {
+ num_ctl_values = mixer_ctl_get_num_values(ctl);
+ for (i = 0; i < num_ctl_values; i++) {
+ if (mixer_ctl_set_value(ctl, i, session_id)) {
+ ALOGV("Error: invalid session_id: %x", session_id);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void platform_get_parameters(void *platform,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ char *str = NULL;
+ char value[256] = {0};
+ int ret;
+ int fluence_type;
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE,
+ value, sizeof(value));
+ if (ret >= 0) {
+ if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+ strlcpy(value, "fluencepro", sizeof(value));
+ } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+ strlcpy(value, "fluence", sizeof(value));
+ } else {
+ strlcpy(value, "none", sizeof(value));
+ }
+
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value);
+ }
+
+ memset(value, 0, sizeof(value));
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
+ value, sizeof(value));
+ if (ret >= 0) {
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SLOWTALK,
+ my_data->slowtalk);
+ }
+
+ ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply));
+}
+
+/* Delay in Us */
+int64_t platform_render_latency(audio_usecase_t usecase)
+{
+ switch (usecase) {
+ case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+ return DEEP_BUFFER_PLATFORM_DELAY;
+ case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+ return LOW_LATENCY_PLATFORM_DELAY;
+ default:
+ return 0;
+ }
+}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+ ALOGV("%s: input source :%d", __func__, source);
+ if(source == AUDIO_SOURCE_FM_RX_A2DP)
+ usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
+ return usecase;
+}
diff --git a/hal_mpq/mpq8092/platform.h b/hal_mpq/mpq8092/platform.h
new file mode 100644
index 0000000..7559258
--- /dev/null
+++ b/hal_mpq/mpq8092/platform.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_PLATFORM_H
+#define QCOM_AUDIO_PLATFORM_H
+
+enum {
+ FLUENCE_NONE,
+ FLUENCE_DUAL_MIC = 0x1,
+ FLUENCE_QUAD_MIC = 0x2,
+};
+
+/*
+ * Below are the devices for which is back end is same, SLIMBUS_0_RX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
+ (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
+ AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+
+/* Sound devices specific to the platform
+ * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
+ * devices to enable corresponding mixer paths
+ */
+enum {
+ SND_DEVICE_NONE = 0,
+
+ /* Playback devices */
+ SND_DEVICE_MIN,
+ SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
+ SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
+ SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_REVERSE,
+ SND_DEVICE_OUT_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_HANDSET,
+ SND_DEVICE_OUT_VOICE_SPEAKER,
+ SND_DEVICE_OUT_VOICE_HEADPHONES,
+ SND_DEVICE_OUT_HDMI,
+ SND_DEVICE_OUT_SPEAKER_AND_HDMI,
+ SND_DEVICE_OUT_BT_SCO,
+ SND_DEVICE_OUT_BT_SCO_WB,
+ SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+ SND_DEVICE_OUT_AFE_PROXY,
+ SND_DEVICE_OUT_USB_HEADSET,
+ SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+ SND_DEVICE_OUT_TRANSMISSION_FM,
+ SND_DEVICE_OUT_ANC_HEADSET,
+ SND_DEVICE_OUT_ANC_FB_HEADSET,
+ SND_DEVICE_OUT_VOICE_ANC_HEADSET,
+ SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET,
+ SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
+ SND_DEVICE_OUT_ANC_HANDSET,
+ SND_DEVICE_OUT_SPEAKER_PROTECTED,
+ SND_DEVICE_OUT_END,
+
+ /*
+ * Note: IN_BEGIN should be same as OUT_END because total number of devices
+ * SND_DEVICES_MAX should not exceed MAX_RX + MAX_TX devices.
+ */
+ /* Capture devices */
+ SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
+ SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN,
+ SND_DEVICE_IN_HANDSET_MIC_AEC,
+ SND_DEVICE_IN_HANDSET_MIC_NS,
+ SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC,
+ SND_DEVICE_IN_HANDSET_DMIC_AEC,
+ SND_DEVICE_IN_HANDSET_DMIC_NS,
+ SND_DEVICE_IN_HANDSET_DMIC_AEC_NS,
+ SND_DEVICE_IN_SPEAKER_MIC,
+ SND_DEVICE_IN_SPEAKER_MIC_AEC,
+ SND_DEVICE_IN_SPEAKER_MIC_NS,
+ SND_DEVICE_IN_SPEAKER_MIC_AEC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC,
+ SND_DEVICE_IN_SPEAKER_DMIC_AEC,
+ SND_DEVICE_IN_SPEAKER_DMIC_NS,
+ SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS,
+ SND_DEVICE_IN_HEADSET_MIC,
+ SND_DEVICE_IN_HEADSET_MIC_FLUENCE,
+ SND_DEVICE_IN_VOICE_SPEAKER_MIC,
+ SND_DEVICE_IN_VOICE_HEADSET_MIC,
+ SND_DEVICE_IN_HDMI_MIC,
+ SND_DEVICE_IN_BT_SCO_MIC,
+ SND_DEVICE_IN_BT_SCO_MIC_WB,
+ SND_DEVICE_IN_CAMCORDER_MIC,
+ SND_DEVICE_IN_VOICE_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+ SND_DEVICE_IN_VOICE_SPEAKER_QMIC,
+ SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
+ SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
+ SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
+ SND_DEVICE_IN_VOICE_REC_MIC,
+ SND_DEVICE_IN_VOICE_REC_MIC_NS,
+ SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+ SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+ SND_DEVICE_IN_USB_HEADSET_MIC,
+ SND_DEVICE_IN_CAPTURE_FM,
+ SND_DEVICE_IN_AANC_HANDSET_MIC,
+ SND_DEVICE_IN_QUAD_MIC,
+ SND_DEVICE_IN_HANDSET_STEREO_DMIC,
+ SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
+ SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+ SND_DEVICE_IN_END,
+
+ SND_DEVICE_MAX = SND_DEVICE_IN_END,
+
+};
+
+#define MIXER_CARD 0
+#define SOUND_CARD 0
+
+#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+
+#define ALL_SESSION_VSID 0xFFFFFFFF
+#define DEFAULT_MUTE_RAMP_DURATION 500
+#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
+#define MIXER_PATH_MAX_LENGTH 100
+
+#define MAX_VOL_INDEX 5
+#define MIN_VOL_INDEX 0
+#define percent_to_index(val, min, max) \
+ ((val) * ((max) - (min)) * 0.01 + (min) + .5)
+
+/*
+ * tinyAlsa library interprets period size as number of frames
+ * one frame = channel_count * sizeof (pcm sample)
+ * so if format = 16-bit PCM and channels = Stereo, frame size = 2 ch * 2 = 4 bytes
+ * DEEP_BUFFER_OUTPUT_PERIOD_SIZE = 1024 means 1024 * 4 = 4096 bytes
+ * We should take care of returning proper size when AudioFlinger queries for
+ * the buffer size of an input/output stream
+ */
+#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 8
+#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
+#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
+
+#define HDMI_MULTI_PERIOD_SIZE 336
+#define HDMI_MULTI_PERIOD_COUNT 8
+#define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
+#define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2)
+
+#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
+#define AUDIO_CAPTURE_PERIOD_COUNT 2
+
+#define DEVICE_NAME_MAX_SIZE 128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
+#define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
+#define MULTIMEDIA2_PCM_DEVICE 1
+#define FM_PLAYBACK_PCM_DEVICE 5
+#define FM_CAPTURE_PCM_DEVICE 6
+#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
+#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22
+#define PLAYBACK_OFFLOAD_DEVICE 9
+#define COMPRESS_VOIP_CALL_PCM_DEVICE 3
+
+#define LOWLATENCY_PCM_DEVICE 15
+#define COMPRESS_CAPTURE_DEVICE 19
+
+#ifdef PLATFORM_MSM8x26
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 14
+#define VOLTE_CALL_PCM_DEVICE 17
+#define QCHAT_CALL_PCM_DEVICE 18
+#elif PLATFORM_APQ8084
+#define VOICE_CALL_PCM_DEVICE 20
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 21
+#define QCHAT_CALL_PCM_DEVICE 06
+#else
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#endif
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+/* CSD-CLIENT related functions */
+typedef int (*init_t)();
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int);
+typedef int (*mic_mute_t)(uint32_t, int);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t, int);
+/* CSD Client structure */
+struct csd_data {
+ void *csd_client;
+ init_t init;
+ deinit_t deinit;
+ disable_device_t disable_device;
+ enable_device_t enable_device;
+ volume_t volume;
+ mic_mute_t mic_mute;
+ slow_talk_t slow_talk;
+ start_voice_t start_voice;
+ stop_voice_t stop_voice;
+ start_playback_t start_playback;
+ stop_playback_t stop_playback;
+ start_record_t start_record;
+ stop_record_t stop_record;
+};
+
+void *hw_info_init(const char *snd_card_name);
+void hw_info_deinit(void *hw_info);
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+ char *device_name);
+
+#define SAMPLES_PER_CHANNEL 1536*2
+#define MAX_INPUT_CHANNELS_SUPPORTED 8
+#define FACTOR_FOR_BUFFERING 2
+#define STEREO_CHANNELS 2
+#define MAX_OUTPUT_CHANNELS_SUPPORTED 8
+
+#define PCM_2CH_OUT 0
+#define PCM_MCH_OUT 1
+#define SPDIF_OUT 2
+#define COMPRESSED_OUT 2 // should be same as SPDIF_OUT
+#define TRANSCODE_OUT 3
+#define FACTOR_FOR_BUFFERING 2
+
+struct audio_bitstream_sm {
+ int buffering_factor;
+ int buffering_factor_cnt;
+ // Buffer pointers for input and output
+ char *inp_buf;
+ char *inp_buf_curr_ptr;
+ char *inp_buf_write_ptr;
+
+ char *enc_out_buf;
+ char *enc_out_buf_write_ptr;
+
+ char *pcm_2_out_buf;
+ char *pcm_2_out_buf_write_ptr;
+
+ char *pcm_mch_out_buf;
+ char *pcm_mch_out_buf_write_ptr;
+
+ char *passt_out_buf;
+ char *passt_out_buf_write_ptr;
+};
+
+#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal_mpq/platform_api.h b/hal_mpq/platform_api.h
new file mode 100644
index 0000000..44ad790
--- /dev/null
+++ b/hal_mpq/platform_api.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QCOM_AUDIO_PLATFORM_API_H
+#define QCOM_AUDIO_PLATFORM_API_H
+
+void *platform_init(struct audio_device *adev);
+void platform_deinit(void *platform);
+const char *platform_get_snd_device_name(snd_device_t snd_device);
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+ char *device_name);
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
+int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
+int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
+int platform_switch_voice_call_device_pre(void *platform);
+int platform_switch_voice_call_device_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device);
+int platform_switch_voice_call_usecase_route_post(void *platform,
+ snd_device_t out_snd_device,
+ snd_device_t in_snd_device);
+int platform_start_voice_call(void *platform, uint32_t vsid);
+int platform_stop_voice_call(void *platform, uint32_t vsid);
+int platform_set_voice_volume(void *platform, int volume);
+int platform_set_mic_mute(void *platform, bool state);
+snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
+snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
+int platform_set_hdmi_channels(void *platform, int channel_count);
+int platform_edid_get_max_channels(void *platform);
+void platform_get_parameters(void *platform, struct str_parms *query,
+ struct str_parms *reply);
+int platform_set_parameters(void *platform, struct str_parms *parms);
+int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id);
+
+/* returns the latency for a usecase in Us */
+int64_t platform_render_latency(audio_usecase_t usecase);
+int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
+
+#endif // QCOM_AUDIO_PLATFORM_API_H
diff --git a/mm-audio/Android.mk b/mm-audio/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/mm-audio/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mm-audio/Makefile b/mm-audio/Makefile
new file mode 100644
index 0000000..2be93e9
--- /dev/null
+++ b/mm-audio/Makefile
@@ -0,0 +1,10 @@
+all:
+ @echo "invoking omxaudio make"
+ $(MAKE) -C adec-mp3
+ $(MAKE) -C adec-aac
+ $(MAKE) -C aenc-aac
+
+install:
+ $(MAKE) -C adec-mp3 install
+ $(MAKE) -C adec-aac install
+ $(MAKE) -C aenc-aac install
diff --git a/mm-audio/Makefile.am b/mm-audio/Makefile.am
new file mode 100644
index 0000000..e423acb
--- /dev/null
+++ b/mm-audio/Makefile.am
@@ -0,0 +1,5 @@
+# Makefile.am - Automake script for mm-omxaudio
+#
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = adec-aac adec-mp3 aenc-aac
diff --git a/mm-audio/adec-aac/Android.mk b/mm-audio/adec-aac/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/mm-audio/adec-aac/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mm-audio/adec-aac/Makefile b/mm-audio/adec-aac/Makefile
new file mode 100644
index 0000000..169fdc6
--- /dev/null
+++ b/mm-audio/adec-aac/Makefile
@@ -0,0 +1,6 @@
+all:
+ @echo "invoking adec-aac make"
+ $(MAKE) -C qdsp6
+
+install:
+ $(MAKE) -C qdsp6 install
diff --git a/mm-audio/adec-aac/Makefile.am b/mm-audio/adec-aac/Makefile.am
new file mode 100644
index 0000000..24c1af2
--- /dev/null
+++ b/mm-audio/adec-aac/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = qdsp6
diff --git a/mm-audio/adec-aac/sw/Android.mk b/mm-audio/adec-aac/sw/Android.mk
new file mode 100644
index 0000000..12a91b1
--- /dev/null
+++ b/mm-audio/adec-aac/sw/Android.mk
@@ -0,0 +1,58 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+ifneq ($(BUILD_WITHOUT_PV),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxAacDec-def := -g -O3
+libOmxAacDec-def += -DQC_MODIFIED
+libOmxAacDec-def += -D_ANDROID_
+libOmxAacDec-def += -D_ENABLE_QC_MSG_LOG_
+libOmxAacDec-def += -DVERBOSE
+libOmxAacDec-def += -D_DEBUG
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+libOmxAacDec-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-adec-omxaac-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+mm-aac-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+mm-aac-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+mm-aac-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \
+ $(PV_TOP)/codecs_v2/omx/omx_common/include \
+ $(PV_TOP)/extern_libs_v2/khronos/openmax/include \
+ $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \
+ $(PV_TOP)/codecs_v2/omx/omx_aac/include \
+ $(PV_TOP)/codecs_v2/audio/aac/dec/include \
+
+LOCAL_MODULE := sw-adec-omxaac-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAacDec-def)
+LOCAL_C_INCLUDES := $(mm-aac-dec-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libopencore_common
+LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libomx_aacdec_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+
+LOCAL_SRC_FILES := test/omx_aac_dec_test.c
+
+include $(BUILD_EXECUTABLE)
+endif
+
+endif #BUILD_WITHOUT_PV
+endif #BUILD_TINY_ANDROID
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c b/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c
new file mode 100644
index 0000000..e591cdd
--- /dev/null
+++ b/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c
@@ -0,0 +1,1302 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+
+
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdint.h>
+#include <linux/ioctl.h>
+#include <linux/msm_audio.h>
+#define SAMPLE_RATE 16000
+#define STEREO 2
+uint32_t samplerate = 16000;
+uint32_t channels = 2;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t filewrite = 0;
+uint32_t configbufsize = 0;
+uint32_t sbr_ps_enabled = 0; //if 0, then both not enabled. if 1 only sbr enabled, if 2 both enabled.
+#define DEBUG_PRINT printf
+uint32_t flushinprogress = 0;
+uint32_t bsac = 0;
+int start_done = 0;
+
+#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/
+
+ int m_pcmdrv_fd;
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+pthread_mutex_t lock;
+pthread_cond_t cond;
+pthread_mutex_t elock;
+pthread_cond_t econd;
+pthread_mutex_t lock1;
+pthread_mutexattr_t lock1_attr;
+pthread_cond_t fcond;
+pthread_mutex_t etb_lock;
+pthread_mutex_t etb_lock1;
+pthread_cond_t etb_cond;
+pthread_mutexattr_t etb_lock_attr;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+OMX_AUDIO_PARAM_AACPROFILETYPE aacparam;
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+OMX_PORT_PARAM_TYPE portParam;
+OMX_ERRORTYPE error;
+int bReconfigureOutputPort = 0;
+
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+static int bFileclose = 0;
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+static unsigned totaldatalen = 0;
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+volatile int etb_event_is_done = 0;
+int ebd_cnt;
+int bOutputEosReached = 0;
+int bInputEosReached = 0;
+int bEosOnInputBuf = 0;
+int bEosOnOutputBuf = 0;
+static int etb_done = 0;
+#ifdef AUDIOV2
+unsigned short session_id;
+unsigned short session_id_hpcm;
+int device_id;
+int control = 0;
+const char *device="speaker_stereo_rx";
+int devmgr_fd;
+#endif
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+const char out_filename[512];
+
+
+OMX_U8* pBuffer_tmp = NULL;
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* aac_dec_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Decoder(char*);
+int Play_Decoder();
+void process_portreconfig();
+OMX_STRING aud_comp;
+
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *aac_dec_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static void write_devctlcmd(int fd, const void *buf, int param);
+
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock1);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock1);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock1);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+
+ int bufCnt=0;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+
+ switch(eEvent) {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventCmdComplete \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("Recieved DISABLE Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("******************************************\n");
+ }
+ else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved ENABLE Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved FLUSH Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventError \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("\n OMX_ErrorInvalidState \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(aac_dec_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(aac_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Deinitialized \n");
+ DEBUG_PRINT("*********************************************\n");
+ exit(0);
+ }
+ else if(OMX_ErrorComponentSuspended == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Received Suspend Event \n");
+ DEBUG_PRINT("*********************************************\n");
+ }
+ break;
+
+
+ case OMX_EventPortSettingsChanged:
+ bReconfigureOutputPort = 1;
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ DEBUG_PRINT("*********************************************\n");
+ event_complete();
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("\n *********************************************\n");
+ DEBUG_PRINT("\n OMX_EventBufferFlag \n");
+ DEBUG_PRINT("\n *********************************************\n");
+
+ bOutputEosReached = true;
+
+ event_complete();
+ break;
+
+ case OMX_EventComponentResumed:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Received Suspend Event \n");
+ DEBUG_PRINT("*********************************************\n");
+ break;
+
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ unsigned int i=0;
+ int bytes_writen = 0;
+ static int count = 0;
+ static int copy_done = 0;
+ static int length_filled = 0;
+ static int spill_length = 0;
+ static int pcm_buf_size = 4800;
+ static unsigned int pcm_buf_count = 2;
+ struct msm_audio_config drv_pcm_config;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(flushinprogress == 1)
+ {
+ DEBUG_PRINT(" FillBufferDone: flush is in progress so hold the buffers\n");
+ return OMX_ErrorNone;
+ }
+ if(count == 0 && pcmplayback)
+ {
+ DEBUG_PRINT(" open pcm device \n");
+ m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR);
+ if (m_pcmdrv_fd < 0)
+ {
+ DEBUG_PRINT("Cannot open audio device\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("Open pcm device successfull\n");
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ drv_pcm_config.sample_rate = samplerate; //SAMPLE_RATE; //m_adec_param.nSampleRate;
+ drv_pcm_config.channel_count = channels; /* 1-> mono 2-> stereo*/
+ ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ pcm_buf_size = drv_pcm_config.buffer_size;
+ pcm_buf_count = drv_pcm_config.buffer_count;
+#ifdef AUDIOV2
+ ioctl(m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &session_id_hpcm);
+ DEBUG_PRINT("session id 0x%x \n", session_id_hpcm);
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id_hpcm);
+ }
+ else
+ {
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ device_id = 2;
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+ if (msm_route_stream(1, session_id_hpcm,device_id, 1))
+ {
+ DEBUG_PRINT("could not set stream routing\n");
+ return -1;
+ }
+ }
+#endif
+ }
+ pBuffer_tmp= (OMX_U8*)malloc(pcm_buf_count*sizeof(OMX_U8)*pcm_buf_size);
+ if (pBuffer_tmp == NULL)
+ {
+ return -1;
+ }
+ else
+ {
+ memset(pBuffer_tmp, 0, pcm_buf_count*pcm_buf_size);
+ }
+ }
+ DEBUG_PRINT(" FillBufferDone #%d size %lu\n", count++,pBuffer->nFilledLen);
+ if(bEosOnOutputBuf)
+ return OMX_ErrorNone;
+ if(filewrite == 1)
+ {
+ bytes_writen =
+ fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,outputBufferFile);
+ DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen);
+ totaldatalen += bytes_writen ;
+ }
+
+#ifdef PCM_PLAYBACK
+ if(pcmplayback && pBuffer->nFilledLen)
+ {
+ if(start_done == 0)
+ {
+ if((length_filled+pBuffer->nFilledLen)>=(pcm_buf_count*pcm_buf_size))
+ {
+ spill_length = (pBuffer->nFilledLen-(pcm_buf_count*pcm_buf_size)+length_filled);
+ memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, ((pcm_buf_count*pcm_buf_size)-length_filled));
+
+ length_filled = (pcm_buf_count*pcm_buf_size);
+ copy_done = 1;
+ }
+ else
+ {
+ memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, pBuffer->nFilledLen);
+ length_filled +=pBuffer->nFilledLen;
+ }
+ if (copy_done == 1)
+ {
+ for (i=0; i<pcm_buf_count; i++)
+ {
+ if (write(m_pcmdrv_fd, pBuffer_tmp+i*pcm_buf_size, pcm_buf_size ) != pcm_buf_size)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+
+ }
+ DEBUG_PRINT("AUDIO_START called for PCM \n");
+ ioctl(m_pcmdrv_fd, AUDIO_START, 0);
+ if (spill_length != 0)
+ {
+ if (write(m_pcmdrv_fd, pBuffer->pBuffer+((pBuffer->nFilledLen)-spill_length), spill_length) != spill_length)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+ }
+
+ copy_done = 0;
+ start_done = 1;
+
+ }
+ }
+ else
+ {
+ if (write(m_pcmdrv_fd, pBuffer->pBuffer, pBuffer->nFilledLen ) !=
+ (ssize_t)pBuffer->nFilledLen)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return OMX_ErrorNone;
+ }
+ }
+ DEBUG_PRINT(" FillBufferDone: writing data to pcm device for play succesfull \n");
+ }
+#endif // PCM_PLAYBACK
+
+
+ if(pBuffer->nFlags != OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT(" FBD calling FTB");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+ }
+ else
+ {
+ DEBUG_PRINT(" FBD EOS REACHED...........\n");
+ bEosOnOutputBuf = true;
+
+ }
+ return OMX_ErrorNone;
+
+}
+
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+ DEBUG_PRINT("\nFunction %s cnt[%d], used_ip_buf_cnt[%d]\n", __FUNCTION__, ebd_cnt,used_ip_buf_cnt);
+ DEBUG_PRINT("\nFunction %s %p %lu\n", __FUNCTION__, pBuffer,pBuffer->nFilledLen);
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock);
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock);
+ }
+
+
+ if(bEosOnInputBuf)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }else if (bFlushing == true) {
+ DEBUG_PRINT("omx_aac_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (used_ip_buf_cnt == 0) {
+ //fseek(inputBufferFile, 0, 0);
+ bFlushing = false;
+ } else {
+ DEBUG_PRINT("omx_aac_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ return OMX_ErrorNone;
+ }
+ }
+
+ if((readBytes = Read_Buffer(pBuffer)) > 0) {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else{
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ //bInputEosReached = true;
+ bEosOnInputBuf = true;
+ pBuffer->nFilledLen = 0;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id) {
+
+ /* Flush */
+
+
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(aac_dec_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ } else if (sig_id == SIGUSR2) {
+ if (bPause == true) {
+ DEBUG_PRINT("%s resume playback\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ } else {
+ DEBUG_PRINT("%s pause playback\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+ struct sigaction sa;
+
+
+ struct wav_header hdr;
+ int bytes_writen = 0;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+ pthread_mutexattr_init(&lock1_attr);
+ pthread_mutex_init(&lock1, &lock1_attr);
+
+ if (argc >= 6) {
+ in_filename = argv[1];
+ samplerate = atoi(argv[2]);
+ channels = atoi(argv[3]);
+ pcmplayback = atoi(argv[4]);
+ filewrite = atoi(argv[5]);
+ strlcpy((char *)out_filename,argv[1],sizeof((char *)out_filename));
+ strlcat((char *)out_filename,".wav",sizeof((char *)out_filename));
+ } else {
+
+ DEBUG_PRINT(" invalid format: \n");
+ DEBUG_PRINT("ex: ./sw-adec-omxaac-test AACINPUTFILE SAMPFREQ CHANNEL PCMPLAYBACK FILEWRITE\n");
+ DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ return 0;
+ }
+
+ aud_comp = "OMX.PV.aacdec";
+
+ if(Init_Decoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ if(Play_Decoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+
+ printf("before wait_for_event\n");
+ if(bReconfigureOutputPort)
+ {
+ wait_for_event();
+ }
+ if(bOutputEosReached) {
+
+ /******************************************************************/
+ #ifdef PCM_PLAYBACK
+ if(pcmplayback == 1)
+ {
+ sleep(1);
+ ioctl(m_pcmdrv_fd, AUDIO_STOP, 0);
+
+#ifdef AUDIOV2
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id_hpcm);
+ }
+ else
+ {
+ if (msm_route_stream(1, session_id_hpcm, device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ }
+ }
+#endif
+ if(m_pcmdrv_fd >= 0) {
+ close(m_pcmdrv_fd);
+ m_pcmdrv_fd = -1;
+ DEBUG_PRINT(" PCM device closed succesfully \n");
+ }
+ else
+ {
+ DEBUG_PRINT(" PCM device close failure \n");
+ }
+ }
+ #endif // PCM_PLAYBACK
+
+ if(filewrite == 1)
+ {
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channels;//2;
+ hdr.sample_rate = samplerate; //SAMPLE_RATE; //44100;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",totaldatalen);
+ hdr.data_sz = totaldatalen;
+ hdr.riff_sz = totaldatalen + 8 + 16 + 8;
+ fseek(outputBufferFile, 0L , SEEK_SET);
+ bytes_writen = fwrite(&hdr,1,sizeof(hdr),outputBufferFile);
+ if (bytes_writen <= 0) {
+ DEBUG_PRINT("Invalid Wav header write failed\n");
+ }
+ bFileclose = 1;
+ fclose(outputBufferFile);
+ }
+ /************************************************************************************/
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+ DEBUG_PRINT("\nMoving the decoder to loaded state \n");
+ OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(aac_dec_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(aac_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+ ebd_cnt=0;
+ wait_for_event();
+ ebd_cnt=0;
+ bOutputEosReached = false;
+ bInputEosReached = false;
+ bEosOnInputBuf = 0;
+ bEosOnOutputBuf = 0;
+ result = OMX_FreeHandle(aac_dec_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+ aac_dec_handle = NULL;
+#ifdef AUDIOV2
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id);
+ close(devmgr_fd);
+ }
+ else
+ {
+ if (msm_route_stream(1,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ }
+#endif
+ /* Deinit OpenMAX */
+
+ OMX_Deinit();
+
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ pthread_cond_destroy(&etb_cond);
+ pthread_mutex_destroy(&etb_lock);
+ pthread_mutex_destroy(&etb_lock1);
+ etb_done = 0;
+ bReconfigureOutputPort = 0;
+ if (pBuffer_tmp)
+ {
+ free(pBuffer_tmp);
+ pBuffer_tmp =NULL;
+ }
+
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+ return 0;
+}
+
+int Init_Decoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ typedef OMX_U8* OMX_U8_PTR;
+ char *role ="audio_decoder.aac";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Aac_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total);
+
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&aac_dec_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component);
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(aac_dec_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+ return 0;
+}
+
+int Play_Decoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file()) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+
+ /* Configuration of Input Port definition */
+
+ /* Query the decoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nDec: Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nDec: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir) {
+ DEBUG_PRINT ("\nDec: Expect Input Port\n");
+ return -1;
+ }
+
+ inputportFmt.nBufferCountActual = inputportFmt.nBufferCountMin + 5;
+ OMX_SetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ OMX_GetExtensionIndex(aac_dec_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(aac_dec_handle,index,&streaminfoparam);
+#ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ devmgr_fd = open("/data/omx_devmgr", O_WRONLY);
+ if(devmgr_fd >= 0)
+ {
+ control = 0;
+ write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id);
+ }
+ else
+ {
+ /*control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ device_id = 2;
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+
+ if (msm_route_stream(1,session_id,device_id, 1))
+ {
+ perror("could not set stream routing\n");
+ return -1;
+ }
+ */
+ }
+#endif
+ /* Configuration of Ouput Port definition */
+
+ /* Query the decoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nDec: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nDec: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir) {
+ DEBUG_PRINT ("\nDec: Expect Output Port\n");
+ return -1;
+ }
+
+ outputportFmt.nBufferCountActual = outputportFmt.nBufferCountMin + 3;
+ OMX_SetParameter(aac_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+
+ CONFIG_VERSION_SIZE(aacparam);
+ aacparam.nPortIndex = 0;
+ aacparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/
+ aacparam.nBitRate = samplerate; //SAMPLE_RATE;
+ aacparam.nSampleRate = samplerate; //SAMPLE_RATE;
+ aacparam.eChannelMode = OMX_AUDIO_ChannelModeStereo;
+ if (sbr_ps_enabled == 0 )
+ aacparam.eAACProfile = OMX_AUDIO_AACObjectLC;
+ else if (sbr_ps_enabled == 1 )
+ aacparam.eAACProfile = OMX_AUDIO_AACObjectHE;
+ else if (sbr_ps_enabled == 2 )
+ aacparam.eAACProfile = OMX_AUDIO_AACObjectHE_PS;
+ aacparam.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP2ADTS;
+ OMX_SetParameter(aac_dec_handle,OMX_IndexParamAudioAac,&aacparam);
+
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n");
+ OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+
+ input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(aac_dec_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+
+ output_buf_cnt = outputportFmt.nBufferCountActual; // outputportFmt.nBufferCountMin ;
+
+ /* Allocate buffer on decoder's O/Pp port */
+ error = Allocate_Buffer(aac_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n");
+ OMX_SendCommand(aac_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags = 0;
+ ret = OMX_FillThisBuffer(aac_dec_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++) {
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ //bInputEosReached = true;
+ bEosOnInputBuf = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ ret = OMX_EmptyThisBuffer(aac_dec_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock);
+ if(etb_done)
+ {
+ DEBUG_PRINT("Component is waiting for EBD to be released.\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock);
+ while(1)
+ {
+ wait_for_event();
+ if(bOutputEosReached)
+ {
+ bReconfigureOutputPort = 0;
+ printf("bOutputEosReached breaking\n");
+ break;
+ }
+ else
+ {
+ if(bReconfigureOutputPort)
+ process_portreconfig();
+ }
+ }
+ return 0;
+}
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_dec_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_dec_handle;
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(aac_dec_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+ int bytes_read=0;
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT("\n Length : %lu, buffer address : %p\n", pBufHdr->nAllocLen, pBufHdr->pBuffer);
+ if(bsac && configbufsize)
+ {
+ bytes_read = fread(pBufHdr->pBuffer, 1, configbufsize, inputBufferFile);
+ configbufsize = 0;
+ bsac = 0;
+ }
+ else
+ {
+ bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile);
+ }
+ pBufHdr->nFilledLen = bytes_read;
+ if(bytes_read == 0)
+ {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read is Non zero=%d\n",bytes_read);
+ }
+ return bytes_read;;
+}
+
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+ struct wav_header hdr;
+ int header_len = 0;
+ memset(&hdr,0,sizeof(hdr));
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channels;//2;
+ hdr.sample_rate = samplerate; //SAMPLE_RATE; //44100;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("Inside %s filename=%s -->%s\n", __FUNCTION__, in_filename,out_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ DEBUG_PRINT("\n FILE DESCRIPTOR : %p\n", inputBufferFile );
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ }
+
+ if(filewrite == 1)
+ {
+ DEBUG_PRINT("output file is opened\n");
+ outputBufferFile = fopen(out_filename,"wb");
+ if (outputBufferFile == NULL) {
+ DEBUG_PRINT("\no/p file %s could NOT be opened\n",
+ out_filename);
+ error_code = -1;
+ return error_code;
+ }
+ header_len = fwrite(&hdr,1,sizeof(hdr),outputBufferFile);
+ if (header_len <= 0) {
+ DEBUG_PRINT("Invalid Wav header \n");
+ }
+ DEBUG_PRINT(" Length og wav header is %d \n",header_len );
+ }
+ return error_code;
+}
+
+void process_portreconfig ( )
+{
+ int bufCnt,i=0;
+ OMX_ERRORTYPE ret;
+ struct msm_audio_config drv_pcm_config;
+ //wait_for_event();
+ DEBUG_PRINT("************************************");
+ DEBUG_PRINT("RECIEVED EVENT PORT SETTINGS CHANGED EVENT\n");
+ DEBUG_PRINT("******************************************\n");
+
+ // wait for port settings changed event
+ DEBUG_PRINT("************************************");
+ DEBUG_PRINT("NOW SENDING FLUSH CMD\n");
+ DEBUG_PRINT("******************************************\n");
+ flushinprogress = 1;
+ OMX_SendCommand(aac_dec_handle, OMX_CommandFlush, 1, 0);
+
+ wait_for_event();
+ DEBUG_PRINT("************************************");
+ DEBUG_PRINT("RECIEVED FLUSH EVENT CMPL\n");
+ DEBUG_PRINT("******************************************\n");
+
+ // Send DISABLE command
+ OMX_SendCommand(aac_dec_handle, OMX_CommandPortDisable, 1, 0);
+
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("FREEING BUFFERS output_buf_cnt=%d\n",output_buf_cnt);
+ DEBUG_PRINT("******************************************\n");
+ // Free output Buffer
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(aac_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+
+ // wait for Disable event to come back
+ wait_for_event();
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("DISABLE EVENT RECD\n");
+ DEBUG_PRINT("******************************************\n");
+
+ // Send Enable command
+ OMX_SendCommand(aac_dec_handle, OMX_CommandPortEnable, 1, 0);
+ flushinprogress = 0;
+ // AllocateBuffers
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("ALLOC BUFFER AFTER PORT REENABLE");
+ DEBUG_PRINT("******************************************\n");
+ /* Allocate buffer on decoder's o/p port */
+ error = Allocate_Buffer(aac_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error output_buf_cnt=%d\n",output_buf_cnt);
+ //return -1;
+ }
+ else
+ {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success output_buf_cnt=%d\n",output_buf_cnt);
+ }
+
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("ENABLE EVENTiHANDLER RECD\n");
+ DEBUG_PRINT("******************************************\n");
+ // wait for enable event to come back
+ wait_for_event();
+ DEBUG_PRINT(" Calling stop on pcm driver...\n");
+ if(pcmplayback && start_done)
+ {
+ while (fsync(m_pcmdrv_fd) < 0) {
+ printf(" fsync failed\n");
+ sleep(1);
+ }
+ ioctl(m_pcmdrv_fd, AUDIO_STOP, 0);
+ ioctl(m_pcmdrv_fd, AUDIO_FLUSH, 0);
+ sleep(3);
+ DEBUG_PRINT("AUDIO_STOP\n");
+ OMX_GetParameter(aac_dec_handle,OMX_IndexParamAudioAac,&aacparam);
+ drv_pcm_config.sample_rate = aacparam.nSampleRate;
+ drv_pcm_config.channel_count = aacparam.nChannels;
+ printf("sample =%lu channel = %lu\n",aacparam.nSampleRate,aacparam.nChannels);
+ ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ start_done = 0;
+ bReconfigureOutputPort = 0;
+ }
+
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("FTB after PORT RENABLE\n");
+ DEBUG_PRINT("******************************************\n");
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ //pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(aac_dec_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+}
+
+static void write_devctlcmd(int fd, const void *buf, int param){
+ int nbytes, nbytesWritten;
+ char cmdstr[128];
+ snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param);
+ nbytes = strlen(cmdstr);
+ nbytesWritten = write(fd, cmdstr, nbytes);
+
+ if(nbytes != nbytesWritten)
+ printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr);
+}
+
diff --git a/mm-audio/adec-amr/Android.mk b/mm-audio/adec-amr/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/mm-audio/adec-amr/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mm-audio/adec-amr/sw/Android.mk b/mm-audio/adec-amr/sw/Android.mk
new file mode 100644
index 0000000..ffa9789
--- /dev/null
+++ b/mm-audio/adec-amr/sw/Android.mk
@@ -0,0 +1,59 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+ifneq ($(BUILD_WITHOUT_PV),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxAmrDec-def := -g -O3
+libOmxAmrDec-def += -DQC_MODIFIED
+libOmxAmrDec-def += -D_ANDROID_
+libOmxAmrDec-def += -D_ENABLE_QC_MSG_LOG_
+libOmxAmrDec-def += -DVERBOSE
+libOmxAmrDec-def += -D_DEBUG
+libOmxAmrDec-def += -DAUDIOV2
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+libOmxAmrDec-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-adec-omxamr-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+mm-amr-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \
+ $(PV_TOP)/codecs_v2/omx/omx_common/include \
+ $(PV_TOP)/extern_libs_v2/khronos/openmax/include \
+ $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \
+ $(PV_TOP)/codecs_v2/omx/omx_amr/include \
+ $(PV_TOP)/codecs_v2/audio/amr/dec/include \
+
+LOCAL_MODULE := sw-adec-omxamr-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAmrDec-def)
+LOCAL_C_INCLUDES := $(mm-amr-dec-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libopencore_common
+LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libomx_amrdec_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+
+LOCAL_SRC_FILES := test/omx_amr_dec_test.c
+
+include $(BUILD_EXECUTABLE)
+endif
+
+endif #BUILD_WITHOUT_PV
+endif #BUILD_TINY_ANDROID
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c b/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c
new file mode 100644
index 0000000..2ce7896
--- /dev/null
+++ b/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c
@@ -0,0 +1,1297 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include<unistd.h>
+#include<string.h>
+#include <pthread.h>
+
+#include <linux/ioctl.h>
+#include <linux/msm_audio.h>
+
+#define SAMPLE_RATE 8000
+#define STEREO 2
+uint32_t samplerate = 8000;
+uint32_t channels = 1;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t filewrite = 0;
+#ifdef _DEBUG
+
+#define DEBUG_PRINT(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \
+ printf(args)
+
+#define DEBUG_PRINT_ERROR(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \
+ printf(args)
+
+#else
+
+#define DEBUG_PRINT
+#define DEBUG_PRINT_ERROR
+
+#endif
+
+#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/
+int m_pcmdrv_fd;
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+/* From WmfDecBytesPerFrame in dec_input_format_tab.cpp */
+const int sizes[] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0 };
+
+pthread_mutex_t lock;
+pthread_mutex_t lock1;
+pthread_mutexattr_t lock1_attr;
+pthread_mutex_t etb_lock1;
+pthread_mutex_t etb_lock;
+pthread_cond_t etb_cond;
+
+pthread_cond_t cond;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+OMX_AUDIO_PARAM_AMRTYPE amrparam;
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+OMX_PORT_PARAM_TYPE portParam;
+OMX_ERRORTYPE error;
+OMX_U8* pBuffer_tmp = NULL;
+
+
+/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+static int bFileclose = 0;
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+static unsigned totaldatalen = 0;
+
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+int ebd_cnt;
+int bOutputEosReached = 0;
+int bInputEosReached = 0;
+int bEosOnInputBuf = 0;
+int bEosOnOutputBuf = 0;
+#ifdef AUDIOV2
+unsigned short session_id;
+unsigned short session_id_hpcm;
+int device_id;
+int control = 0;
+//const char *device="handset_rx";
+const char *device="speaker_stereo_rx";
+int devmgr_fd;
+#endif
+static int etb_done = 0;
+static int etb_event_is_done = 0;
+
+OMX_AUDIO_AMRFRAMEFORMATTYPE frameFormat = 0;
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+const char out_filename[512];
+int chunksize =0;
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* amr_dec_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Decoder(OMX_STRING audio_component);
+int Play_Decoder();
+
+OMX_STRING aud_comp;
+
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *amr_dec_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static void write_devctlcmd(int fd, const void *buf, int param);
+
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock);
+}
+
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+ int bufCnt=0;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+
+ switch(eEvent)
+ {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventCmdComplete \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("Recieved DISABLE Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("******************************************\n");
+ }
+ else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved ENABLE Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved FLUSH Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventError \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("\n OMX_ErrorInvalidState \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(amr_dec_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(amr_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Deinitialized \n");
+ DEBUG_PRINT("*********************************************\n");
+ exit(0);
+ }
+ else if(OMX_ErrorComponentSuspended == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Received Suspend Event \n");
+ DEBUG_PRINT("*********************************************\n");
+ }
+ break;
+
+ case OMX_EventPortSettingsChanged:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ DEBUG_PRINT("*********************************************\n");
+ event_complete();
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_Bufferflag \n");
+ DEBUG_PRINT("*********************************************\n");
+ bOutputEosReached = true;
+ event_complete();
+ break;
+ case OMX_EventComponentResumed:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Received Suspend Event \n");
+ DEBUG_PRINT("*********************************************\n");
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ unsigned int i=0;
+ int bytes_writen = 0;
+ static int count = 0;
+ static int copy_done = 0;
+ static int start_done = 0;
+ static int length_filled = 0;
+ static int spill_length = 0;
+ static int pcm_buf_size = 4800;
+ static unsigned int pcm_buf_count = 2;
+ struct msm_audio_config drv_pcm_config;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(count == 0 && pcmplayback)
+ {
+ DEBUG_PRINT(" open pcm device \n");
+ m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR);
+ if (m_pcmdrv_fd < 0)
+ {
+ DEBUG_PRINT("Cannot open audio device\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("Open pcm device successfull\n");
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ drv_pcm_config.sample_rate = samplerate; //SAMPLE_RATE; //m_adec_param.nSampleRate;
+ drv_pcm_config.channel_count = channels; /* 1-> mono 2-> stereo*/
+ ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ pcm_buf_size = drv_pcm_config.buffer_size;
+ pcm_buf_count = drv_pcm_config.buffer_count;
+#ifdef AUDIOV2
+ ioctl(m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &session_id_hpcm);
+ DEBUG_PRINT("session id 0x%4x \n", session_id_hpcm);
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id_hpcm);
+ }
+ else
+ {
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+
+ if (msm_route_stream(1, session_id_hpcm,device_id, 1))
+ {
+ DEBUG_PRINT("could not set stream routing\n");
+ return -1;
+ }
+ }
+#endif
+ }
+ pBuffer_tmp= (OMX_U8*)malloc(pcm_buf_count*sizeof(OMX_U8)*pcm_buf_size);
+ if (pBuffer_tmp == NULL)
+ {
+ return -1;
+ }
+ else
+ {
+ memset(pBuffer_tmp, 0, pcm_buf_count*pcm_buf_size);
+ }
+ }
+ DEBUG_PRINT(" FillBufferDone #%d size %lu\n", count++,pBuffer->nFilledLen);
+
+ if(bEosOnOutputBuf)
+ {
+ return OMX_ErrorNone;
+ }
+
+ if(filewrite == 1)
+ {
+ bytes_writen =
+ fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,outputBufferFile);
+ DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen);
+ totaldatalen += bytes_writen ;
+ }
+
+#ifdef PCM_PLAYBACK
+ if(pcmplayback && pBuffer->nFilledLen)
+ {
+ if(start_done == 0)
+ {
+ if((length_filled+pBuffer->nFilledLen)>=(pcm_buf_count*pcm_buf_size))
+ {
+ spill_length = (pBuffer->nFilledLen-(pcm_buf_count*pcm_buf_size)+length_filled);
+ memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, ((pcm_buf_count*pcm_buf_size)-length_filled));
+ length_filled = (pcm_buf_count*pcm_buf_size);
+ copy_done = 1;
+ }
+ else
+ {
+ memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, pBuffer->nFilledLen);
+ length_filled +=pBuffer->nFilledLen;
+ }
+ if (copy_done == 1)
+ {
+ for (i=0; i<pcm_buf_count; i++)
+ {
+ if (write(m_pcmdrv_fd, pBuffer_tmp+i*pcm_buf_size, pcm_buf_size ) != pcm_buf_size)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+
+ }
+ DEBUG_PRINT("AUDIO_START called for PCM \n");
+ ioctl(m_pcmdrv_fd, AUDIO_START, 0);
+ if (spill_length != 0)
+ {
+ if (write(m_pcmdrv_fd, pBuffer->pBuffer+((pBuffer->nFilledLen)-spill_length), spill_length) != spill_length)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+ }
+ if (pBuffer_tmp)
+ {
+ free(pBuffer_tmp);
+ pBuffer_tmp =NULL;
+ }
+ copy_done = 0;
+ start_done = 1;
+ }
+ }
+ else
+ {
+ if (write(m_pcmdrv_fd, pBuffer->pBuffer, pBuffer->nFilledLen ) !=
+ (ssize_t)pBuffer->nFilledLen)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return OMX_ErrorNone;
+ }
+ }
+
+ DEBUG_PRINT(" FillBufferDone: writing data to pcm device for play succesfull \n");
+ }
+#endif // PCM_PLAYBACK
+
+
+ if(pBuffer->nFlags != OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT(" FBD calling FTB");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+ }
+ else
+ {
+ DEBUG_PRINT(" FBD EOS REACHED...........\n");
+ bEosOnOutputBuf = true;
+ return OMX_ErrorNone;
+ }
+ return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+ DEBUG_PRINT("\nFunction %s cnt[%d]\n", __FUNCTION__, ebd_cnt);
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock1);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock1);
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock1);
+ }
+ if(bEosOnInputBuf)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }
+ else if (true == bFlushing)
+ {
+ DEBUG_PRINT("omx_amr_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (0 == used_ip_buf_cnt)
+ {
+ //fseek(inputBufferFile, 0, 0);
+ bFlushing = false;
+ }
+ else
+ {
+ DEBUG_PRINT("omx_amr_adec_test: more buffer to come back\n");
+ return OMX_ErrorNone;
+ }
+ }
+ if((readBytes = Read_Buffer(pBuffer)) > 0)
+ {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ DEBUG_PRINT("pBuffer->nFilledLen = %d,used_ip_buf_cnt:%d\n", readBytes,used_ip_buf_cnt);
+ timeStampLfile += timestampInterval;
+ pBuffer->nTimeStamp = timeStampLfile;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else
+ {
+ DEBUG_PRINT("OMX_BUFFERFLAG_EOS\n");
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ bEosOnInputBuf = true;
+ pBuffer->nFilledLen = 0;
+ timeStampLfile += timestampInterval;
+ pBuffer->nTimeStamp = timeStampLfile;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id) {
+
+ /* Flush */
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(amr_dec_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ } else if (sig_id == SIGUSR2) {
+ if (bPause == true) {
+ DEBUG_PRINT("%s resume playback\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ } else {
+ DEBUG_PRINT("%s pause playback\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+ struct sigaction sa;
+
+
+ struct wav_header hdr;
+ int bytes_writen = 0;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+
+ pthread_mutexattr_init(&lock1_attr);
+ pthread_mutex_init(&lock1, &lock1_attr);
+
+ if (argc >= 7)
+ {
+ in_filename = argv[1];
+ DEBUG_PRINT("argv[1]- file name = %s\n", argv[1]);
+ samplerate = atoi(argv[2]);
+ DEBUG_PRINT("argv[2]- sample rate = %d\n", samplerate);
+ channels = atoi(argv[3]);
+ DEBUG_PRINT("argv[3]- channels = %d\n", channels);
+ pcmplayback = atoi(argv[4]);
+ DEBUG_PRINT("argv[4]- PCM play y/n = %d\n", pcmplayback);
+ filewrite = atoi(argv[5]);
+ frameFormat = atoi(argv[6]);
+ DEBUG_PRINT("argv[7]- frameFormat = %d\n", frameFormat);
+ strlcpy((char *)out_filename,argv[1],sizeof((char *)out_filename));
+ strlcat((char *)out_filename,".wav",sizeof((char *)out_filename));
+
+ }
+ else
+ {
+ DEBUG_PRINT("invalid format: ex: ");
+ DEBUG_PRINT("ex: ./sw-adec-omxamr-test AMRINPUTFILE SAMPFREQ CHANNEL\n");
+ DEBUG_PRINT("PCMPLAYBACK FILEWRITE FRAMEFORMAT\n");
+ DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT("FRAMEFORMAT = 1 (IF1 format) \n");
+ DEBUG_PRINT("FRAMEFORMAT = 2 (IF2 format) \n");
+ DEBUG_PRINT("FRAMEFORMAT = 3 (FSF format) \n");
+ DEBUG_PRINT("FRAMEFORMAT = 4 (RTP format) \n");
+
+ return 0;
+ }
+ aud_comp = "OMX.PV.amrdec";
+
+ DEBUG_PRINT(" OMX test app : aud_comp = %s\n",aud_comp);
+
+ if(Init_Decoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ if(Play_Decoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+ wait_for_event();
+
+ DEBUG_PRINT("\nAfter wait event .....\n");
+ if(bOutputEosReached)
+ {
+#ifdef PCM_PLAYBACK
+ if(1 == pcmplayback)
+ {
+ sleep(1);
+ ioctl(m_pcmdrv_fd, AUDIO_STOP, 0);
+#ifdef AUDIOV2
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id_hpcm);
+ }
+ else
+ {
+ if (msm_route_stream(1, session_id_hpcm, device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ }
+ }
+#endif
+ if(m_pcmdrv_fd >= 0)
+ {
+ close(m_pcmdrv_fd);
+ m_pcmdrv_fd = -1;
+ DEBUG_PRINT(" PCM device closed succesfully \n");
+ }
+ else
+ {
+ DEBUG_PRINT(" PCM device close failure \n");
+ }
+ }
+#endif // PCM_PLAYBACK
+
+ if(1 == filewrite)
+ {
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channels;//2;
+ hdr.sample_rate = samplerate; //SAMPLE_RATE; //44100;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",totaldatalen);
+ hdr.data_sz = totaldatalen;
+ hdr.riff_sz = totaldatalen + 8 + 16 + 8;
+ fseek(outputBufferFile, 0L , SEEK_SET);
+ bytes_writen = fwrite(&hdr,1,sizeof(hdr),outputBufferFile);
+ if (bytes_writen <= 0)
+ {
+ DEBUG_PRINT("Invalid Wav header write failed\n");
+ }
+ bFileclose = 1;
+ fclose(outputBufferFile);
+ }
+ /************************************************************************************/
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+
+ DEBUG_PRINT("\nMoving the decoder to loaded state \n");
+ OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(amr_dec_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(amr_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+
+ ebd_cnt=0;
+ wait_for_event();
+ ebd_cnt=0;
+ result = OMX_FreeHandle(amr_dec_handle);
+ if (result != OMX_ErrorNone)
+ {
+ DEBUG_PRINT("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+#ifdef AUDIOV2
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id);
+ close(devmgr_fd);
+ }
+ else
+ {
+ if (msm_route_stream(1,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ }
+#endif
+
+ /* Deinit OpenMAX */
+ OMX_Deinit();
+ fclose(inputBufferFile);
+ timeStampLfile = 0;
+ amr_dec_handle = NULL;
+ bInputEosReached = false;
+ bOutputEosReached = false;
+ bEosOnInputBuf = 0;
+ bEosOnOutputBuf = 0;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ pthread_mutexattr_destroy(&lock1_attr);
+ pthread_mutex_destroy(&lock1);
+ pthread_mutex_destroy(&etb_lock1);
+ pthread_cond_destroy(&etb_cond);
+ pthread_mutex_destroy(&etb_lock);
+ etb_done = 0;
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+
+ DEBUG_PRINT("\nClosing Session\n");
+ return 0;
+}
+
+int Init_Decoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0,total1 = 0;
+ unsigned int i = 0;
+ OMX_U8** audCompNames;
+ typedef OMX_U8* OMX_U8_PTR;
+ OMX_STRING role ="audio_decoder.amrnb";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ DEBUG_PRINT("Inside Play_Decoder - samplerate = %d\n", samplerate);
+ DEBUG_PRINT("Inside Play_Decoder - channels = %d\n", channels);
+ DEBUG_PRINT("Inside Play_Decoder - pcmplayback = %d\n", pcmplayback);
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ char* audiocomponent ="OMX.PV.amrdec";
+ int componentfound = false;
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Amr_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT("\nTotal components of role=%s :%lu", role, total);
+
+ if(total)
+ {
+ DEBUG_PRINT("Total number of components = %lu\n", total);
+ /* Allocate memory for pointers to component name */
+ audCompNames = (OMX_U8**)malloc((sizeof(OMX_U8))*total);
+
+ if(NULL == audCompNames)
+ {
+ return -1;
+ }
+
+ for (i = 0; i < total; ++i)
+ {
+ audCompNames[i] =
+ (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_MAX_STRINGNAME_SIZE);
+ if(NULL == audCompNames[i] )
+ {
+ while (i > 0)
+ {
+ free(audCompNames[--i]);
+ }
+ free(audCompNames);
+ return -1;
+ }
+ memset(&audCompNames[i],0,sizeof(audCompNames[i]));
+ }
+ total1 = total;
+ DEBUG_PRINT("Before calling OMX_GetComponentsOfRole()\n");
+ OMX_GetComponentsOfRole(role, &total, audCompNames);
+ DEBUG_PRINT("\nComponents of Role:%s\n", role);
+ for (i = 0; i < total; ++i)
+ {
+ if(i<total1)
+ DEBUG_PRINT("\n Found Component[%s]\n",audCompNames[i]);
+ {
+ componentfound = true;
+ audio_component = audiocomponent;
+ DEBUG_PRINT("\n audiocomponent = %p\n",audiocomponent);
+ }
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("No components found with Role:%s", role);
+ }
+ if(componentfound == false)
+ {
+ DEBUG_PRINT("\n Not found audiocomponent = %p\n",audiocomponent);
+ for (i = 0; i < total1; ++i)
+ free(audCompNames[i]);
+ free(audCompNames);
+ return -1;
+ }
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&amr_dec_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ for (i = 0; i < total1; ++i)
+ free(audCompNames[i]);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent is in LOADED state\n");
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(amr_dec_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ for (i = 0; i < total1; ++i)
+ free(audCompNames[i]);
+ free(audCompNames);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+ for (i = 0; i < total1; ++i)
+ free(audCompNames[i]);
+ free(audCompNames);
+ return 0;
+}
+
+int Play_Decoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file()) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+ /* Query the decoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(amr_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nDec: Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nDec: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir) {
+ DEBUG_PRINT ("\nDec: Expect Input Port\n");
+ return -1;
+ }
+ // Modified to Set the Actual Buffer Count for input port
+ inputportFmt.nBufferCountActual = inputportFmt.nBufferCountMin + 3;
+ OMX_SetParameter(amr_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ OMX_GetExtensionIndex(amr_dec_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(amr_dec_handle,index,&streaminfoparam);
+#ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ devmgr_fd = open("/data/omx_devmgr", O_WRONLY);
+ if(devmgr_fd >= 0)
+ {
+ control = 0;
+ write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id);
+ }
+#endif
+ /* Query the decoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(amr_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nDec: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nDec: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir) {
+ DEBUG_PRINT ("\nDec: Expect Output Port\n");
+ return -1;
+ }
+ // Modified to Set the Actual Buffer Count for output port
+ outputportFmt.nBufferCountActual = outputportFmt.nBufferCountMin + 1;
+ OMX_SetParameter(amr_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+
+ CONFIG_VERSION_SIZE(amrparam);
+
+ OMX_GetParameter(amr_dec_handle,OMX_IndexParamAudioAmr,&amrparam);
+ amrparam.nPortIndex = 0;
+ amrparam.nChannels = 1; //2 ; /* 1-> mono 2-> stereo*/
+ amrparam.nBitRate = 8000; //SAMPLE_RATE;
+ amrparam.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; //default mode
+ if (frameFormat == 1)
+ {
+ amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatIF1;
+ }
+ else if (frameFormat == 2)
+ {
+ amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatIF2;
+ }
+ else if (frameFormat == 3)
+ {
+ amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+ }
+ else if (frameFormat == 4)
+ {
+ amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatRTPPayload;
+ }
+ OMX_SetParameter(amr_dec_handle,OMX_IndexParamAudioAmr,&amrparam);
+
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n");
+ OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+
+ input_buf_cnt = inputportFmt.nBufferCountMin + 3;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(amr_dec_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+
+ output_buf_cnt = outputportFmt.nBufferCountMin + 1 ;
+
+ /* Allocate buffer on decoder's O/Pp port */
+ error = Allocate_Buffer(amr_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n");
+ OMX_SendCommand(amr_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(amr_dec_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++) {
+
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ bInputEosReached = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ timeStampLfile += timestampInterval;
+ pInputBufHdrs[i]->nTimeStamp = timeStampLfile;
+ ret = OMX_EmptyThisBuffer(amr_dec_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock1);
+ if(etb_done)
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("Component is waiting for EBD to be releases, BC signal\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock1);
+
+ return 0;
+}
+
+
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_dec_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_dec_handle;
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(amr_dec_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+
+
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+
+ int bytes_read=0;
+ static int totalbytes_read =0;
+
+ DEBUG_PRINT ("\nInside Read_Buffer\n");
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ DEBUG_PRINT("AllocLen:%lu\n", pBufHdr->nAllocLen);
+
+ bytes_read = fread(pBufHdr->pBuffer,1,pBufHdr->nAllocLen ,inputBufferFile);
+
+ totalbytes_read += bytes_read;
+ DEBUG_PRINT ("bytes_read = %d\n",bytes_read);
+ DEBUG_PRINT ("totalbytes_read = %d\n",totalbytes_read);
+ pBufHdr->nFilledLen = bytes_read;
+ if( bytes_read <= 0)
+ {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read is Non zero\n");
+ }
+ return bytes_read;
+}
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+ struct wav_header hdr;
+ int header_len = 0;
+ memset(&hdr,0,sizeof(hdr));
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channels;
+ hdr.sample_rate = samplerate;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ return error_code;
+ }
+ DEBUG_PRINT("Setting the file pointer to the beginging of the byte");
+ fseek(inputBufferFile, 0, SEEK_SET);
+
+ if(filewrite == 1)
+ {
+ DEBUG_PRINT("output file is opened\n");
+
+ outputBufferFile = fopen(out_filename,"wb");
+ if (outputBufferFile == NULL)
+ {
+ DEBUG_PRINT("\no/p file %s could NOT be opened\n",
+ out_filename);
+ error_code = -1;
+ return error_code;
+ }
+
+ header_len = fwrite(&hdr,1,sizeof(hdr),outputBufferFile);
+ if (header_len <= 0)
+ {
+ DEBUG_PRINT("Invalid Wav header \n");
+ }
+ DEBUG_PRINT(" Length og wav header is %d \n",header_len );
+ }
+ return error_code;
+}
+
+static void write_devctlcmd(int fd, const void *buf, int param){
+ int nbytes, nbytesWritten;
+ char cmdstr[128];
+ snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param);
+ nbytes = strlen(cmdstr);
+ nbytesWritten = write(fd, cmdstr, nbytes);
+
+ if(nbytes != nbytesWritten)
+ printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr);
+}
+
+
+
diff --git a/mm-audio/adec-amrwb/Android.mk b/mm-audio/adec-amrwb/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/mm-audio/adec-amrwb/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mm-audio/adec-amrwb/sw/Android.mk b/mm-audio/adec-amrwb/sw/Android.mk
new file mode 100644
index 0000000..5de1d9d
--- /dev/null
+++ b/mm-audio/adec-amrwb/sw/Android.mk
@@ -0,0 +1,58 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+ifneq ($(BUILD_WITHOUT_PV),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxAmrDec-def := -g -O3
+libOmxAmrDec-def += -DQC_MODIFIED
+libOmxAmrDec-def += -D_ANDROID_
+libOmxAmrDec-def += -D_ENABLE_QC_MSG_LOG_
+libOmxAmrDec-def += -DVERBOSE
+libOmxAmrDec-def += -D_DEBUG
+libOmxAmrDec-def += -DAUDIOV2
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+libOmxAmrDec-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (sw-adec-omxamr-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+mm-amr-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+mm-amr-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \
+ $(PV_TOP)/codecs_v2/omx/omx_common/include \
+ $(PV_TOP)/extern_libs_v2/khronos/openmax/include \
+ $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \
+ $(PV_TOP)/codecs_v2/omx/omx_amr/include \
+ $(PV_TOP)/codecs_v2/audio/amr/dec/include \
+
+LOCAL_MODULE := sw-adec-omxamrwb-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAmrDec-def)
+LOCAL_C_INCLUDES := $(mm-amr-dec-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libopencore_common
+LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libomx_amrdec_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+LOCAL_SRC_FILES := test/omx_amrwb_dec_test.c
+
+include $(BUILD_EXECUTABLE)
+endif
+
+endif #BUILD_WITHOUT_PV
+endif #BUILD_TINY_ANDROID
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c b/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c
new file mode 100644
index 0000000..5e9d748
--- /dev/null
+++ b/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c
@@ -0,0 +1,1283 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#include "OMX_Component.h"
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/msm_audio.h>
+#include<unistd.h>
+#include<string.h>
+#include <pthread.h>
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+
+#ifdef AUDIOV2
+unsigned short session_id;
+unsigned short session_id_hpcm;
+int device_id;
+int control = 0;
+const char *device="handset_rx";
+int devmgr_fd;
+#endif
+
+#include <linux/ioctl.h>
+
+#define SAMPLE_RATE 8000
+#define STEREO 2
+uint32_t samplerate = 8000;
+uint32_t channels = 1;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t filewrite = 0;
+
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+
+int sf = 0;
+int ch = 0;
+int format = 0;
+
+#ifdef _DEBUG
+
+#define DEBUG_PRINT(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \
+ printf(args)
+
+#define DEBUG_PRINT_ERROR(args...) printf("%s:%d ", __FUNCTION__, __LINE__); \
+ printf(args)
+
+#else
+
+#define DEBUG_PRINT
+#define DEBUG_PRINT_ERROR
+
+#endif
+
+
+#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/
+
+int m_pcmdrv_fd;
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+pthread_mutex_t lock;
+pthread_mutex_t lock1;
+pthread_mutexattr_t lock1_attr;
+pthread_mutex_t etb_lock1;
+pthread_mutex_t etb_lock;
+pthread_cond_t etb_cond;
+
+pthread_cond_t cond;
+pthread_mutex_t elock;
+pthread_cond_t econd;
+pthread_cond_t fcond;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+
+OMX_AUDIO_PARAM_AMRTYPE amrparam;
+QOMX_AUDIO_PARAM_AMRWBPLUSTYPE amrwbPlusparam;
+
+OMX_PORT_PARAM_TYPE portParam;
+OMX_ERRORTYPE error;
+OMX_U8* pBuffer_tmp = NULL;
+
+/* AMRWB specific macros */
+
+//AMR-WB Number of channels
+#define AMRWB_CHANNELS 1
+
+//AMR-WB Sampling rate
+#define AMRWB_SAMPLE_RATE 16000
+
+//AMR-WB File Header size
+#define AMRWB_FILE_HEADER_SIZE 9
+
+/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+static int bFileclose = 0;
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+static unsigned totaldatalen = 0;
+
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+int ebd_cnt;
+int bOutputEosReached = 0;
+int bInputEosReached = 0;
+int bEosOnInputBuf = 0;
+int bEosOnOutputBuf = 0;
+static int etb_done = 0;
+static int etb_event_is_done = 0;
+
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* amrwb_dec_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Decoder(OMX_STRING audio_component);
+int Play_Decoder();
+
+OMX_STRING aud_comp;
+
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *amrwb_dec_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static void write_devctlcmd(int fd, const void *buf, int param);
+
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock);
+}
+
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+ int bufCnt = 0;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+
+ switch(eEvent)
+ {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventCmdComplete \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("Recieved DISABLE Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("******************************************\n");
+ }
+ else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved ENABLE Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved FLUSH Event Command Complete[%lu]\n",nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventError \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("\n OMX_ErrorInvalidState \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(amrwb_dec_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(amrwb_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Deinitialized \n");
+ DEBUG_PRINT("*********************************************\n");
+ exit(0);
+ }
+ break;
+
+ case OMX_EventPortSettingsChanged:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ DEBUG_PRINT("*********************************************\n");
+ event_complete();
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_Bufferflag \n");
+ DEBUG_PRINT("*********************************************\n");
+ bOutputEosReached = true;
+ event_complete();
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ unsigned int i=0;
+ int bytes_writen = 0;
+ static int count = 0;
+ static int copy_done = 0;
+ static int start_done = 0;
+ static int length_filled = 0;
+ static int spill_length = 0;
+ static int pcm_buf_size = 4800;
+ static unsigned int pcm_buf_count = 2;
+ struct msm_audio_config drv_pcm_config;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(count == 0 && pcmplayback)
+ {
+ DEBUG_PRINT(" open pcm device \n");
+ m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR);
+ if (m_pcmdrv_fd < 0)
+ {
+ DEBUG_PRINT("Cannot open audio device\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("Open pcm device successfull\n");
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ drv_pcm_config.sample_rate = sf;//SAMPLE_RATE; //m_adec_param.nSampleRate;
+ drv_pcm_config.channel_count = ch;//channels; /* 1-> mono 2-> stereo*/
+ ioctl(m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ pcm_buf_size = drv_pcm_config.buffer_size;
+ pcm_buf_count = drv_pcm_config.buffer_count;
+#ifdef AUDIOV2
+ ioctl(m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &session_id_hpcm);
+ DEBUG_PRINT("session id 0x%4x \n", session_id_hpcm);
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id_hpcm);
+ }
+ else
+ {
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+ if (msm_route_stream(1, session_id_hpcm,device_id, 1))
+ {
+ DEBUG_PRINT("could not set stream routing\n");
+ return -1;
+ }
+ }
+#endif
+ }
+ pBuffer_tmp= (OMX_U8*)malloc(pcm_buf_count*sizeof(OMX_U8)*pcm_buf_size);
+ if (pBuffer_tmp == NULL)
+ {
+ return -1;
+ }
+ else
+ {
+ memset(pBuffer_tmp, 0, pcm_buf_count*pcm_buf_size);
+ }
+ }
+ DEBUG_PRINT(" FillBufferDone #%d size %lu\n", count++,pBuffer->nFilledLen);
+
+ if(bEosOnOutputBuf)
+ return OMX_ErrorNone;
+
+ if(filewrite == 1)
+ {
+ bytes_writen =
+ fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,outputBufferFile);
+ DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen);
+ totaldatalen += bytes_writen ;
+ }
+
+#ifdef PCM_PLAYBACK
+ if(pcmplayback && pBuffer->nFilledLen)
+ {
+ if(start_done == 0)
+ {
+ if((length_filled+pBuffer->nFilledLen)>=(pcm_buf_count*pcm_buf_size))
+ {
+ spill_length = (pBuffer->nFilledLen-(pcm_buf_count*pcm_buf_size)+length_filled);
+ memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, ((pcm_buf_count*pcm_buf_size)-length_filled));
+ length_filled = (pcm_buf_count*pcm_buf_size);
+ copy_done = 1;
+ }
+ else
+ {
+ memcpy (pBuffer_tmp+length_filled, pBuffer->pBuffer, pBuffer->nFilledLen);
+ length_filled +=pBuffer->nFilledLen;
+ }
+ if (copy_done == 1)
+ {
+ for (i=0; i<pcm_buf_count; i++)
+ {
+ if (write(m_pcmdrv_fd, pBuffer_tmp+i*pcm_buf_size, pcm_buf_size ) != pcm_buf_size)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+
+ }
+ DEBUG_PRINT("AUDIO_START called for PCM \n");
+ ioctl(m_pcmdrv_fd, AUDIO_START, 0);
+ if (spill_length != 0)
+ {
+ if (write(m_pcmdrv_fd, pBuffer->pBuffer+((pBuffer->nFilledLen)-spill_length), spill_length) != spill_length)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+ }
+ if (pBuffer_tmp)
+ {
+ free(pBuffer_tmp);
+ pBuffer_tmp =NULL;
+ }
+ copy_done = 0;
+ start_done = 1;
+ }
+ }
+ else
+ {
+ if (write(m_pcmdrv_fd, pBuffer->pBuffer, pBuffer->nFilledLen ) !=
+ (ssize_t)pBuffer->nFilledLen)
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return OMX_ErrorNone;
+ }
+ }
+
+ DEBUG_PRINT(" FillBufferDone: writing data to pcm device for play succesfull \n");
+ }
+#endif // PCM_PLAYBACK
+
+
+ if(pBuffer->nFlags != OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT(" FBD calling FTB");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+ }
+ else
+ {
+ DEBUG_PRINT(" FBD EOS REACHED...........\n");
+ bEosOnOutputBuf = true;
+ return OMX_ErrorNone;
+ }
+ return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ DEBUG_PRINT("\nFunction %s cnt[%d]\n", __FUNCTION__, ebd_cnt);
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock1);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock1);
+ DEBUG_PRINT("EBD: Before etb_wait_for_event.....\n");
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock1);
+ }
+ if(bEosOnInputBuf)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }
+ else if (true == bFlushing)
+ {
+ DEBUG_PRINT("omx_amrwb_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (0 == used_ip_buf_cnt)
+ {
+ bFlushing = false;
+ }
+ else
+ {
+ DEBUG_PRINT("omx_amr_adec_test: more buffer to come back\n");
+ return OMX_ErrorNone;
+ }
+ }
+ if((readBytes = Read_Buffer(pBuffer)) > 0)
+ {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ timeStampLfile += timestampInterval;
+ pBuffer->nTimeStamp = timeStampLfile;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else
+ {
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ bEosOnInputBuf = true;
+ pBuffer->nFilledLen = 0;
+ timeStampLfile += timestampInterval;
+ pBuffer->nTimeStamp = timeStampLfile;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id)
+{
+ if (sig_id == SIGUSR1)
+ {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ }
+ else if (sig_id == SIGUSR2)
+ {
+ if (bPause == true)
+ {
+ DEBUG_PRINT("%s resume playback\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ }
+ else
+ {
+ DEBUG_PRINT("%s pause playback\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+ struct sigaction sa;
+ struct wav_header hdr;
+ int bytes_writen = 0;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+
+ pthread_mutexattr_init(&lock1_attr);
+ pthread_mutex_init(&lock1, &lock1_attr);
+
+ if (argc == 6)
+ {
+ in_filename = argv[1];
+ DEBUG_PRINT("argv[1]- file name = %s\n", argv[1]);
+ pcmplayback = atoi(argv[2]);
+ DEBUG_PRINT("argv[2]- PCM play y/n = %d\n", pcmplayback);
+ filewrite = atoi(argv[3]);
+ sf = atoi(argv[4]);
+ ch = atoi(argv[5]);
+ }
+ else
+ {
+ DEBUG_PRINT("\ninvalid format\n");
+ DEBUG_PRINT("ex: ./sw-adec-omxamrwb-test AMRINPUTFILE PCMPLAYBACK");
+ DEBUG_PRINT("FILEWRITE SAMP-FREQ CHANNELS\n");
+ DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "SAMPLING FREQUENCY:\n");
+ DEBUG_PRINT( "CHANNELS = 1 (MONO)\n");
+ DEBUG_PRINT( "CHANNELS = 2 (STEREO)\n");
+ return 0;
+ }
+
+ aud_comp = "OMX.PV.amrdec";
+
+ DEBUG_PRINT(" OMX test app : aud_comp = %s\n",aud_comp);
+
+ if(Init_Decoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ if(Play_Decoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+ wait_for_event();
+
+ if(bOutputEosReached)
+ {
+#ifdef PCM_PLAYBACK
+ if(1 == pcmplayback)
+ {
+ sleep(1);
+ ioctl(m_pcmdrv_fd, AUDIO_STOP, 0);
+
+#ifdef AUDIOV2
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id_hpcm);
+ }
+ else
+ {
+ if (msm_route_stream(1, session_id_hpcm, device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ }
+ }
+#endif
+ if(m_pcmdrv_fd >= 0)
+ {
+ close(m_pcmdrv_fd);
+ m_pcmdrv_fd = -1;
+ DEBUG_PRINT(" PCM device closed succesfully \n");
+ }
+ else
+ {
+ DEBUG_PRINT(" PCM device close failure \n");
+ }
+ }
+#endif // PCM_PLAYBACK
+
+ if(1 == filewrite)
+ {
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = AMRWB_CHANNELS;
+ hdr.sample_rate = AMRWB_SAMPLE_RATE;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",totaldatalen);
+ hdr.data_sz = totaldatalen;
+ hdr.riff_sz = totaldatalen + 8 + 16 + 8;
+ fseek(outputBufferFile, 0L , SEEK_SET);
+ bytes_writen = fwrite(&hdr,1,sizeof(hdr),outputBufferFile);
+ if (bytes_writen <= 0)
+ {
+ DEBUG_PRINT("Invalid Wav header write failed\n");
+ }
+ bFileclose = 1;
+ fclose(outputBufferFile);
+ }
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+
+ DEBUG_PRINT("\nMoving the decoder to loaded state \n");
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(amrwb_dec_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(amrwb_dec_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+
+ ebd_cnt=0;
+ wait_for_event();
+ ebd_cnt=0;
+
+ result = OMX_FreeHandle(amrwb_dec_handle);
+ if (result != OMX_ErrorNone)
+ {
+ DEBUG_PRINT("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+#ifdef AUDIOV2
+ if(devmgr_fd >= 0)
+ {
+ write_devctlcmd(devmgr_fd, "-cmd=unregister_session_rx -sid=", session_id);
+ close(devmgr_fd);
+ }
+ else
+ {
+ if (msm_route_stream(1,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ }
+#endif
+ /* Deinit OpenMAX */
+ OMX_Deinit();
+ fclose(inputBufferFile);
+ timeStampLfile = 0;
+ amrwb_dec_handle = NULL;
+ bInputEosReached = false;
+ bOutputEosReached = false;
+ bEosOnInputBuf = 0;
+ bEosOnOutputBuf = 0;
+ pthread_cond_destroy(&cond);
+ pthread_cond_destroy(&etb_cond);
+ pthread_mutex_destroy(&lock);
+ pthread_mutexattr_destroy(&lock1_attr);
+ pthread_mutex_destroy(&lock1);
+ pthread_mutex_destroy(&etb_lock);
+ pthread_mutex_destroy(&etb_lock1);
+ etb_done = 0;
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+ return 0;
+}
+
+//int Init_Decoder()
+int Init_Decoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ OMX_U8** audCompNames;
+ typedef OMX_U8* OMX_U8_PTR;
+ unsigned int i = 0;
+ OMX_STRING role ="audio_decoder.amrwb";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ DEBUG_PRINT(" Play_Decoder - pcmplayback = %d\n", pcmplayback);
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult)
+ {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Amrwb_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT("\nTotal components of role=%s :%lu\n", role, total);
+
+ if(total)
+ {
+ DEBUG_PRINT("Total number of components = %lu\n", total);
+ /* Allocate memory for pointers to component name */
+ audCompNames = (OMX_U8**)malloc((sizeof(OMX_U8))*total);
+
+ if(NULL == audCompNames)
+ {
+ return -1;
+ }
+
+ for (i = 0; i < total; ++i)
+ {
+ audCompNames[i] =
+ (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_MAX_STRINGNAME_SIZE);
+ if(NULL == audCompNames[i] )
+ {
+ while (i > 0)
+ {
+ free(audCompNames[--i]);
+ }
+ free(audCompNames);
+ return -1;
+ }
+ }
+ DEBUG_PRINT("Before calling OMX_GetComponentsOfRole()\n");
+ OMX_GetComponentsOfRole(role, &total, audCompNames);
+ DEBUG_PRINT("\nComponents of Role:%s\n", role);
+ }
+ else
+ {
+ DEBUG_PRINT("No components found with Role:%s", role);
+ }
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&amrwb_dec_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult))
+ {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ for (i = 0; i < total; ++i)
+ free(audCompNames[i]);
+ free(audCompNames);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent is in LOADED state\n");
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(amrwb_dec_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult))
+ {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ for (i = 0; i < total; ++i)
+ free(audCompNames[i]);
+ free(audCompNames);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+ for (i = 0; i < total; ++i)
+ free(audCompNames[i]);
+ free(audCompNames);
+ return 0;
+}
+
+int Play_Decoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file())
+ {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+ /* Query the decoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nDec: Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nDec: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir)
+ {
+ DEBUG_PRINT ("\nDec: Expect Input Port\n");
+ return -1;
+ }
+// Modified to Set the Actual Buffer Count for input port
+ inputportFmt.nBufferCountActual = inputportFmt.nBufferCountMin + 3;
+ OMX_SetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+
+ /* Query the decoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nDec: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nDec: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir)
+ {
+ DEBUG_PRINT ("\nDec: Expect Output Port\n");
+ return -1;
+ }
+ // Modified to Set the Actual Buffer Count for output port
+ outputportFmt.nBufferCountActual = outputportFmt.nBufferCountMin + 1;
+ OMX_SetParameter(amrwb_dec_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+
+ CONFIG_VERSION_SIZE(amrparam);
+ OMX_GetExtensionIndex(amrwb_dec_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(amrwb_dec_handle,index,&streaminfoparam);
+#ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ devmgr_fd = open("/data/omx_devmgr", O_WRONLY);
+ if(devmgr_fd >= 0)
+ {
+ control = 0;
+ write_devctlcmd(devmgr_fd, "-cmd=register_session_rx -sid=", session_id);
+ }
+ else
+ {
+ /*
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+
+ if (msm_route_stream(1,session_id,device_id, 1))
+ {
+ perror("could not set stream routing\n");
+ return -1;
+ }
+ */
+ }
+#endif
+
+ OMX_GetParameter(amrwb_dec_handle,OMX_IndexParamAudioAmr,&amrparam);
+ amrparam.nPortIndex = 0;
+ amrparam.nChannels = ch;
+ amrparam.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0; //default
+ amrparam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+ OMX_SetParameter(amrwb_dec_handle,OMX_IndexParamAudioAmr,&amrparam);
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n");
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+
+ input_buf_cnt = inputportFmt.nBufferCountMin + 3;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(amrwb_dec_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+
+
+ output_buf_cnt = outputportFmt.nBufferCountMin + 1;
+
+ /* Allocate buffer on decoder's O/Pp port */
+ error = Allocate_Buffer(amrwb_dec_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n");
+ OMX_SendCommand(amrwb_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+ for(i=0; i < output_buf_cnt; i++)
+ {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(amrwb_dec_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret)
+ {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else
+ {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++)
+ {
+
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ bInputEosReached = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ timeStampLfile += timestampInterval;
+ pInputBufHdrs[i]->nTimeStamp = timeStampLfile;
+ ret = OMX_EmptyThisBuffer(amrwb_dec_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock1);
+ if(etb_done)
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("Component is waiting for EBD to be releases, BC signal\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock1);
+
+ return 0;
+}
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_dec_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_dec_handle;
+
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt)
+ {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(amrwb_dec_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+
+ int bytes_read=0;
+ static int totalbytes_read =0;
+
+ DEBUG_PRINT ("\nInside Read_Buffer nAllocLen:%lu\n", pBufHdr->nAllocLen);
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ bytes_read = fread(pBufHdr->pBuffer,
+ 1, pBufHdr->nAllocLen, inputBufferFile);
+ pBufHdr->nFilledLen = bytes_read;
+ totalbytes_read += bytes_read;
+
+ DEBUG_PRINT ("\bytes_read = %d\n",bytes_read);
+ DEBUG_PRINT ("\totalbytes_read = %d\n",totalbytes_read);
+ if( bytes_read <= 0)
+ {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read is Non zero\n");
+ }
+ return bytes_read;
+}
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+ const char *outfilename = "Audio_amrwb.wav";
+ struct wav_header hdr;
+ int header_len = 0;
+
+ memset(&hdr,0,sizeof(hdr));
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = AMRWB_CHANNELS;
+ hdr.sample_rate = AMRWB_SAMPLE_RATE;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ }
+
+ if(filewrite == 1)
+ {
+ DEBUG_PRINT("output file is opened\n");
+ outputBufferFile = fopen(outfilename,"wb");
+ if (outputBufferFile == NULL)
+ {
+ DEBUG_PRINT("\no/p file %s could NOT be opened\n",
+ outfilename);
+ error_code = -1;
+ return error_code;
+ }
+
+ header_len = fwrite(&hdr,1,sizeof(hdr),outputBufferFile);
+
+ if (header_len <= 0)
+ {
+ DEBUG_PRINT("Invalid Wav header \n");
+ }
+ DEBUG_PRINT(" Length og wav header is %d \n",header_len );
+ }
+ return error_code;
+}
+
+static void write_devctlcmd(int fd, const void *buf, int param){
+ int nbytes, nbytesWritten;
+ char cmdstr[128];
+ snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param);
+ nbytes = strlen(cmdstr);
+ nbytesWritten = write(fd, cmdstr, nbytes);
+
+ if(nbytes != nbytesWritten)
+ printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr);
+}
+
diff --git a/mm-audio/adec-mp3/Android.mk b/mm-audio/adec-mp3/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/mm-audio/adec-mp3/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mm-audio/adec-mp3/Makefile b/mm-audio/adec-mp3/Makefile
new file mode 100644
index 0000000..83d822b
--- /dev/null
+++ b/mm-audio/adec-mp3/Makefile
@@ -0,0 +1,6 @@
+all:
+ @echo "invoking omxaudio make"
+ $(MAKE) -C qdsp6
+
+install:
+ $(MAKE) -C qdsp6 install
diff --git a/mm-audio/adec-mp3/Makefile.am b/mm-audio/adec-mp3/Makefile.am
new file mode 100644
index 0000000..24c1af2
--- /dev/null
+++ b/mm-audio/adec-mp3/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = qdsp6
diff --git a/mm-audio/adec-mp3/sw/Android.mk b/mm-audio/adec-mp3/sw/Android.mk
new file mode 100644
index 0000000..3773a88
--- /dev/null
+++ b/mm-audio/adec-mp3/sw/Android.mk
@@ -0,0 +1,59 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+ifneq ($(BUILD_WITHOUT_PV),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxMp3Dec-def := -g -O3
+libOmxMp3Dec-def += -DQC_MODIFIED
+libOmxMp3Dec-def += -D_ANDROID_
+libOmxMp3Dec-def += -D_ENABLE_QC_MSG_LOG_
+libOmxMp3Dec-def += -DVERBOSE
+libOmxMp3Dec-def += -D_DEBUG
+libOmxMp3Dec-def += -DAUDIOV2
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+libOmxMp3Dec-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-adec-omxmp3-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+ifeq ($(BOARD_USES_QCOM_AUDIO_V2), true)
+mm-mp3-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+mm-mp3-dec-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+mm-mp3-dec-test-inc += $(PV_TOP)/codecs_v2/omx/omx_mastercore/include \
+ $(PV_TOP)/codecs_v2/omx/omx_common/include \
+ $(PV_TOP)/extern_libs_v2/khronos/openmax/include \
+ $(PV_TOP)/codecs_v2/omx/omx_baseclass/include \
+ $(PV_TOP)/codecs_v2/omx/omx_mp3/include \
+ $(PV_TOP)/codecs_v2/audio/mp3/dec/include \
+
+LOCAL_MODULE := sw-adec-omxmp3-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxMp3Dec-def)
+LOCAL_C_INCLUDES := $(mm-mp3-dec-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libopencore_common
+LOCAL_SHARED_LIBRARIES += libomx_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libomx_mp3dec_sharedlibrary
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+
+LOCAL_SRC_FILES := test/omx_mp3_dec_test.c
+
+include $(BUILD_EXECUTABLE)
+endif
+
+endif #BUILD_WITHOUT_PV
+endif #BUILD_TINY_ANDROID
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c b/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c
new file mode 100644
index 0000000..31931d7
--- /dev/null
+++ b/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c
@@ -0,0 +1,2159 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+#include "pthread.h"
+#include <signal.h>
+#include <stdint.h>
+#include<string.h>
+#include <pthread.h>
+#include <linux/ioctl.h>
+#include <linux/msm_audio.h>
+#include <errno.h>
+
+#define USE_BUFFER_CASE 1
+#define HOST_PCM_DEVICE 0
+#define PCM_DEC_DEVICE 1
+
+OMX_U32 mp3_frequency_index[3][4] = {
+ {11025,0,22050,44100},
+ {12000,0,24000,48000},
+ {8000,0,16000,32000}
+};
+
+int is_multi_inst = 0;
+
+#define DEBUG_PRINT printf
+#define DEBUG_PRINT_ERROR printf
+#define PCM_PLAYBACK /* To write the pcm decoded data to the msm_pcm device for playback*/
+
+#ifdef PCM_PLAYBACK
+
+struct mp3_header
+{
+ OMX_U8 sync;
+ OMX_U8 version;
+ uint8_t Layer;
+ OMX_U8 protection;
+ OMX_U32 bitrate;
+ OMX_U32 sampling_rate;
+ OMX_U8 padding;
+ OMX_U8 private_bit;
+ OMX_U8 channel_mode;
+};
+
+
+#define DEFAULT_SAMPLING_RATE 44100
+#define DEFAULT_CHANNEL_MODE 2
+
+#endif // PCM_PLAYBACK
+
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+OMX_ERRORTYPE parse_mp3_frameheader(OMX_BUFFERHEADERTYPE* buffer,
+ struct mp3_header *header);
+
+unsigned int extract_id3_header_size(OMX_U8* buffer);
+
+/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+typedef struct hpcm
+{
+ int pipe_in;
+ int pipe_out;
+}hpcm;
+
+typedef enum msg
+{
+ CTRL = 0,
+ DATA = 1
+}MSG;
+
+typedef struct hpcm_info
+{
+ MSG msg_type;
+ int fd;
+ OMX_COMPONENTTYPE *hComponent;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+}hpcm_info;
+
+struct adec_appdata
+{
+ uint32_t pcmplayback;
+ uint32_t tunnel;
+ uint32_t filewrite;
+ uint32_t flushinprogress;
+ uint32_t buffer_option;
+ uint32_t pcm_device_type;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ pthread_mutex_t elock;
+ pthread_cond_t econd;
+ pthread_cond_t fcond;
+ FILE * inputBufferFile;
+ FILE * outputBufferFile;
+ OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+ OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+ OMX_AUDIO_PARAM_MP3TYPE mp3param;
+ QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+ OMX_PORT_PARAM_TYPE portParam;
+ OMX_ERRORTYPE error;
+ int input_buf_cnt;
+ int output_buf_cnt;
+ int used_ip_buf_cnt;
+ int event_is_done;
+ int ebd_event_is_done;
+ int fbd_event_is_done;
+ int ebd_cnt;
+ int bOutputEosReached ;
+ int bInputEosReached ;
+ int bFlushing;
+ int bPause;
+ #ifdef AUDIOV2
+ unsigned short session_id;
+ unsigned short session_id_hpcm;
+ int device_id ;
+ int control ;
+ char device[44];
+ int devmgr_fd;
+ #endif
+ const char *in_filename;
+ unsigned totaldatalen;
+ OMX_STRING aud_comp;
+ OMX_COMPONENTTYPE* mp3_dec_handle;
+ OMX_BUFFERHEADERTYPE **pInputBufHdrs ;
+ OMX_BUFFERHEADERTYPE **pOutputBufHdrs;
+ int m_pcmdrv_fd;
+ int num_pcm_buffers;
+ pthread_mutex_t pcm_buf_lock;
+ pthread_t m_pcmdrv_evt_thread_id;
+ const char *out_filename;
+ int bReconfigureOutputPort;
+ int bEosOnInputBuf;
+ int bEosOnOutputBuf;
+ int bParseHeader;
+ struct mp3_header mp3Header;
+ OMX_U8* pBuffer_tmp;
+ int count;
+ int copy_done;
+ int start_done;
+ unsigned int length_filled;
+ int spill_length;
+ unsigned int pcm_buf_size;
+ unsigned int pcm_buf_count;
+ int first_buffer;
+ hpcm mp3_hpcm;
+};
+
+struct adec_appdata adec_mp3_inst1;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Decoder(struct adec_appdata* adec_appdata);
+int Play_Decoder(struct adec_appdata* adec_appdata);
+void process_portreconfig(struct adec_appdata* adec_appdata);
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file (struct adec_appdata* adec_appdata);
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr,FILE * inputBufferFile);
+static OMX_ERRORTYPE Use_Buffer ( struct adec_appdata* adec_appdata,
+ OMX_U32 nPortIndex );
+
+static OMX_ERRORTYPE Free_Buffer ( struct adec_appdata* adec_appdata,
+ OMX_U32 nPortIndex,
+ OMX_BUFFERHEADERTYPE *bufHdr
+ );
+
+static OMX_ERRORTYPE Allocate_Buffer ( struct adec_appdata* adec_appdata,
+ OMX_U32 nPortIndex );
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+void write_devctlcmd(int fd, const void *buf, int param);
+
+void adec_appdata_init(struct adec_appdata* adec_appdata)
+{
+ adec_appdata->totaldatalen = 0;
+ adec_appdata->input_buf_cnt = 0;
+ adec_appdata->output_buf_cnt = 0;
+ adec_appdata->used_ip_buf_cnt = 0;
+ adec_appdata->event_is_done = 0;
+ adec_appdata->ebd_event_is_done = 0;
+ adec_appdata->fbd_event_is_done = 0;
+ adec_appdata->ebd_cnt = 0;
+ adec_appdata->bOutputEosReached = 0;
+ adec_appdata->bInputEosReached = 0;
+ adec_appdata->bFlushing = false;
+ adec_appdata->bPause= false;
+ adec_appdata->pcmplayback = 0;
+ adec_appdata->tunnel = 0;
+ adec_appdata->filewrite = 0;
+ adec_appdata->flushinprogress = 0;
+ adec_appdata->buffer_option = 0;
+ adec_appdata->pcm_device_type = HOST_PCM_DEVICE;
+ adec_appdata->bReconfigureOutputPort = 0;
+ adec_appdata->bEosOnInputBuf = 0;
+ adec_appdata->bEosOnOutputBuf = 0;
+ adec_appdata->bParseHeader = 0;
+ adec_appdata->mp3_dec_handle = NULL;
+ adec_appdata->pInputBufHdrs = NULL;
+ adec_appdata->pOutputBufHdrs = NULL;
+ adec_appdata->pBuffer_tmp = NULL;
+ adec_appdata->count = 0;
+ adec_appdata->copy_done = 0;
+ adec_appdata->start_done = 0;
+ adec_appdata->length_filled = 0;
+ adec_appdata->spill_length = 0;
+ adec_appdata->pcm_buf_size = 4800;
+ adec_appdata->pcm_buf_count = 2;
+ adec_appdata->first_buffer = 1;
+ adec_appdata->mp3Header.sync = 0;
+ adec_appdata->mp3Header.version = 0;
+ adec_appdata->mp3Header.Layer = 0;
+ adec_appdata->mp3Header.protection = 0;
+ adec_appdata->mp3Header.bitrate = 0;
+ adec_appdata->mp3Header.sampling_rate = 0;
+ adec_appdata->mp3Header.padding = 0;
+ adec_appdata->mp3Header.private_bit = 0;
+ adec_appdata->mp3Header.channel_mode = 0;
+ adec_appdata->m_pcmdrv_fd = -1;
+ adec_appdata->num_pcm_buffers = 0;
+ adec_appdata->inputBufferFile = NULL;
+ adec_appdata->outputBufferFile = NULL;
+ adec_appdata->error = 0;
+}
+
+void wait_for_event(struct adec_appdata * adec_appdata)
+{
+ pthread_mutex_lock(&adec_appdata->lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, adec_appdata->event_is_done);
+ while (adec_appdata->event_is_done == 0) {
+ pthread_cond_wait(&adec_appdata->cond, &adec_appdata->lock);
+ }
+ adec_appdata->event_is_done = 0;
+ pthread_mutex_unlock(&adec_appdata->lock);
+}
+
+void event_complete(struct adec_appdata * adec_appdata)
+{
+ pthread_mutex_lock(&adec_appdata->lock);
+ if (adec_appdata->event_is_done == 0) {
+ adec_appdata->event_is_done = 1;
+ pthread_cond_broadcast(&adec_appdata->cond);
+ }
+ pthread_mutex_unlock(&adec_appdata->lock);
+}
+
+void *process_hpcm_drv_events( void* data)
+{
+ struct adec_appdata *adec_data = (struct adec_appdata *)data;
+ hpcm_info ftb;
+
+ int n=0;
+ hpcm_info p;
+ DEBUG_PRINT("%s adec_data=%p pipe_in=%d pipe_out=%d\n",__FUNCTION__,
+ adec_data,
+ adec_data->mp3_hpcm.pipe_in,
+ adec_data->mp3_hpcm.pipe_out);
+ while(1)
+ {
+ DEBUG_PRINT("\n Waiting for next FBD from OMX.....\n");
+ n = read(adec_data->mp3_hpcm.pipe_in,&p,sizeof(struct hpcm_info));
+ if(n <= 0){
+ DEBUG_PRINT("*********************\n");
+ DEBUG_PRINT("KILLING HPCM THREAD...\n");
+ DEBUG_PRINT("***********************\n");
+ return (void*) -1;
+ }
+ if(p.msg_type == CTRL)
+ {
+ event_complete(adec_data);
+ DEBUG_PRINT("DATA EMPTY\n");
+ }
+ else
+ {
+ DEBUG_PRINT("***********************\n");
+ DEBUG_PRINT("\n%s-->pipe_in=%d pipe_out=%d n=%d\n",__FUNCTION__,
+ adec_data->mp3_hpcm.pipe_in,
+ adec_data->mp3_hpcm.pipe_out,n);
+ DEBUG_PRINT("***********************\n");
+ ftb.hComponent = p.hComponent;
+ ftb.bufHdr = p.bufHdr;
+
+ if ( write(adec_data->m_pcmdrv_fd, ftb.bufHdr->pBuffer, ftb.bufHdr->nFilledLen ) !=
+ (ssize_t)(ftb.bufHdr->nFilledLen) )
+ {
+ DEBUG_PRINT_ERROR("%s: Write data to PCM failed\n",__FUNCTION__);
+ }
+ DEBUG_PRINT("drvfd=%d bufHdr[%p] buffer[%p] len[%lu] hComponent[%p] bOutputEos=%d\n",
+ adec_data->m_pcmdrv_fd,
+ ftb.bufHdr,ftb.bufHdr->pBuffer,
+ ftb.bufHdr->nFilledLen,
+ ftb.hComponent,adec_data->bOutputEosReached);
+ if(!(adec_data->bOutputEosReached))
+ OMX_FillThisBuffer(ftb.hComponent,ftb.bufHdr);
+ }
+ }
+ return 0;
+}
+
+/* Thread for handling the events from PCM_DEC driver */
+void* process_pcm_drv_events( void* data)
+{
+ struct adec_appdata *adec_data = (struct adec_appdata *)data;
+ OMX_BUFFERHEADERTYPE *bufHdr = NULL;
+ struct msm_audio_event tcxo_event;
+ int rc = 0, buf_count = 0;
+
+ if(data == NULL)
+ {
+ DEBUG_PRINT("\n PPDE: data is NULL\n");
+ return (void*)(-1);
+ }
+
+ while(1)
+ {
+ DEBUG_PRINT("\nPPDE:Calling ioctl AUDIO_GET_EVENT ...\n");
+ rc = ioctl(adec_data->m_pcmdrv_fd, AUDIO_GET_EVENT, &tcxo_event);
+ if((rc == -1) && (errno == ENODEV ))
+ {
+ DEBUG_PRINT("\nPPDE:Exiting with rc %d and error %d", rc, errno);
+ return (void*)(-1);
+ }
+ DEBUG_PRINT("\nPPDE:Event Type[%d]", tcxo_event.event_type);
+
+ switch(tcxo_event.event_type)
+ {
+ case AUDIO_EVENT_WRITE_DONE:
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE*)tcxo_event.event_payload.
+ aio_buf.private_data;
+
+ if(bufHdr)
+ {
+ buf_count++;
+ DEBUG_PRINT("\nPPDE:PCMDEC-ASYNC_WRITE DONE for bufHdr[%p], \
+ buf_count = %d\n", bufHdr, buf_count);
+
+ pthread_mutex_lock(&adec_data->pcm_buf_lock);
+ adec_data->num_pcm_buffers--;
+ pthread_mutex_unlock(&adec_data->pcm_buf_lock);
+
+ if(adec_data->bOutputEosReached == true)
+ {
+ if(adec_data->num_pcm_buffers == 0)
+ {
+ DEBUG_PRINT("\nPPDE: Output EOS reached in PCMDEC\n");
+ DEBUG_PRINT("\nPPDE::: OUTPUT EOS REACHED....\n");
+ event_complete(adec_data);
+ return 0;
+ }
+ else
+ {
+ DEBUG_PRINT("\nWaiting for PCM to play remaining \
+ %d buffers ...\n", adec_data->num_pcm_buffers);
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("\nPPDE calling FTB");
+ OMX_FillThisBuffer(adec_data->mp3_dec_handle, bufHdr);
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("\nPPDE: Invalid bufHdr[%p] in WRITE_DONE\n",
+ bufHdr);
+ }
+ }
+ break;
+
+ default:
+ DEBUG_PRINT("PPDE: Received Invalid Event");
+ break;
+ }
+ }
+ return 0;
+}
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ //DEBUG_PRINT("Function %s \n command %d Event complete %d", __FUNCTION__,(OMX_COMMANDTYPE)nData1,nData2);
+ int bufCnt=0;
+ struct adec_appdata* adec_appdata;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pEventData;
+
+ if(NULL != pAppData)
+ adec_appdata = (struct adec_appdata*) pAppData;
+ else
+ return OMX_ErrorBadParameter;
+ switch(eEvent) {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventCmdComplete \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1) {
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("Recieved DISABLE Event Command Complete[%d]\n",(signed)nData2);
+ DEBUG_PRINT("******************************************\n");
+ }
+ else if(OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1) {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved ENABLE Event Command Complete[%d]\n",(signed)nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ else if(OMX_CommandFlush== (OMX_COMMANDTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("Recieved FLUSH Event Command Complete[%d]\n",(signed)nData2);
+ DEBUG_PRINT("*********************************************\n");
+ }
+ event_complete(adec_appdata);
+ break;
+
+ case OMX_EventError:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventError \n");
+ DEBUG_PRINT("*********************************************\n");
+ if(OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("\n OMX_ErrorInvalidState \n");
+ for(bufCnt=0; bufCnt < adec_appdata->input_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(adec_appdata->mp3_dec_handle, 0, adec_appdata->pInputBufHdrs[bufCnt]);
+ }
+ if(adec_appdata->tunnel == 0)
+ {
+ for(bufCnt=0; bufCnt < adec_appdata->output_buf_cnt; ++bufCnt)
+ {
+ OMX_FreeBuffer(adec_appdata->mp3_dec_handle, 1, adec_appdata->pOutputBufHdrs[bufCnt]);
+ }
+ }
+
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Deinitialized \n");
+ DEBUG_PRINT("*********************************************\n");
+ exit(0);
+ }
+ else if(OMX_ErrorComponentSuspended == (OMX_ERRORTYPE)nData1)
+ {
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Received Suspend Event \n");
+ DEBUG_PRINT("*********************************************\n");
+ }
+ break;
+
+ case OMX_EventPortSettingsChanged:
+ if(adec_appdata->tunnel == 0)
+ {
+ adec_appdata->bReconfigureOutputPort = 1;
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ DEBUG_PRINT("*********************************************\n");
+ event_complete(adec_appdata);
+ }
+ break;
+
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("\n *********************************************\n");
+ DEBUG_PRINT("\n OMX_EventBufferFlag \n");
+ DEBUG_PRINT("\n *********************************************\n");
+ adec_appdata->bOutputEosReached = true;
+ if((!adec_appdata->pcmplayback && adec_appdata->filewrite)
+ || (adec_appdata->pcmplayback &&
+ (adec_appdata->pcm_device_type == HOST_PCM_DEVICE ||
+ (adec_appdata->pcm_device_type == PCM_DEC_DEVICE
+ && !adec_appdata->num_pcm_buffers))))
+ {
+ event_complete(adec_appdata);
+ }
+ break;
+ case OMX_EventComponentResumed:
+ DEBUG_PRINT("*********************************************\n");
+ DEBUG_PRINT("\n Component Received Resume Event \n");
+ DEBUG_PRINT("*********************************************\n");
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ struct msm_audio_aio_buf audio_aio_buf;
+ unsigned int i=0;
+ int bytes_writen = 0;
+ struct msm_audio_config drv_pcm_config;
+ struct adec_appdata* adec_appdata;
+
+ if(NULL != pAppData)
+ adec_appdata = (struct adec_appdata*) pAppData;
+ else
+ return OMX_ErrorBadParameter;
+
+ if (adec_appdata->flushinprogress == 1 )
+ {
+ DEBUG_PRINT(" FillBufferDone: flush is in progress so hold the buffers\n");
+ return OMX_ErrorNone;
+ }
+ if ( (adec_appdata->count == 0) &&
+ (adec_appdata->pcm_device_type == HOST_PCM_DEVICE) &&
+ (adec_appdata->pcmplayback))
+ {
+ DEBUG_PRINT(" open pcm device \n");
+ adec_appdata->m_pcmdrv_fd = open("/dev/msm_pcm_out", O_RDWR);
+ if ( adec_appdata->m_pcmdrv_fd < 0 )
+ {
+ DEBUG_PRINT("Cannot open audio device\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("Open pcm device successfull\n");
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ drv_pcm_config.sample_rate = adec_appdata->mp3Header.sampling_rate;
+ drv_pcm_config.channel_count = adec_appdata->mp3Header.channel_mode;
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ DEBUG_PRINT("drv_pcm_config.buffer_count %d \n", drv_pcm_config.buffer_count);
+ DEBUG_PRINT("drv_pcm_config.buffer_size %d \n", drv_pcm_config.buffer_size);
+ adec_appdata->pcm_buf_size = drv_pcm_config.buffer_size;
+ adec_appdata->pcm_buf_count = drv_pcm_config.buffer_count;
+#ifdef AUDIOV2
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_SESSION_ID, &adec_appdata->session_id_hpcm);
+ DEBUG_PRINT("session id 0x%4x \n", adec_appdata->session_id_hpcm);
+ if(adec_appdata->devmgr_fd >= 0)
+ {
+ write_devctlcmd(adec_appdata->devmgr_fd, "-cmd=register_session_rx -sid=", adec_appdata->session_id_hpcm);
+ }
+ else
+ {
+ adec_appdata->control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if (adec_appdata->control < 0)
+ printf("ERROR opening the device\n");
+ adec_appdata->device_id = msm_get_device(adec_appdata->device);
+ DEBUG_PRINT ("\ndevice_id = %d\n", adec_appdata->device_id);
+ DEBUG_PRINT("\nsessionid = %d\n", adec_appdata->session_id);
+ if (msm_en_device(adec_appdata->device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+ if (msm_route_stream(1, adec_appdata->session_id_hpcm, adec_appdata->device_id, 1))
+ {
+ DEBUG_PRINT("could not set stream routing\n");
+ return -1;
+ }
+ }
+#endif
+ }
+ adec_appdata->pBuffer_tmp= (OMX_U8*)malloc(adec_appdata->pcm_buf_count*sizeof(OMX_U8)*adec_appdata->pcm_buf_size);
+ if ( adec_appdata->pBuffer_tmp == NULL )
+ {
+ return -1;
+ }
+ else
+ {
+ memset(adec_appdata->pBuffer_tmp, 0, adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size);
+ }
+ }
+ DEBUG_PRINT(" FillBufferDone #%d size %u\n", adec_appdata->count++,(unsigned)(pBuffer->nFilledLen));
+
+ if ( adec_appdata->bEosOnOutputBuf )
+ {
+ return OMX_ErrorNone;
+ }
+
+ if ( (adec_appdata->tunnel == 0) && (adec_appdata->filewrite == 1) )
+ {
+ bytes_writen =
+ fwrite(pBuffer->pBuffer,1,pBuffer->nFilledLen,adec_appdata->outputBufferFile);
+ DEBUG_PRINT(" FillBufferDone size writen to file %d\n",bytes_writen);
+ adec_appdata->totaldatalen += bytes_writen ;
+ }
+
+#ifdef PCM_PLAYBACK
+ if ( adec_appdata->pcmplayback && pBuffer->nFilledLen )
+ {
+ if(adec_appdata->pcm_device_type == HOST_PCM_DEVICE)
+ {
+ if ( adec_appdata->start_done == 0 )
+ {
+ if ( (adec_appdata->length_filled+ pBuffer->nFilledLen)>=(adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size) )
+ {
+ adec_appdata->spill_length = (pBuffer->nFilledLen-(adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size)+adec_appdata->length_filled);
+ memcpy (adec_appdata->pBuffer_tmp+adec_appdata->length_filled, pBuffer->pBuffer,
+ ((adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size)-adec_appdata->length_filled));
+ adec_appdata->length_filled = (adec_appdata->pcm_buf_count*adec_appdata->pcm_buf_size);
+ adec_appdata->copy_done = 1;
+ }
+ else
+ {
+ memcpy (adec_appdata->pBuffer_tmp+adec_appdata->length_filled, pBuffer->pBuffer, pBuffer->nFilledLen);
+ adec_appdata->length_filled +=pBuffer->nFilledLen;
+ }
+ if (adec_appdata->copy_done == 1 )
+ {
+ for ( i=0; i<adec_appdata->pcm_buf_count; i++ )
+ {
+ if ( write(adec_appdata->m_pcmdrv_fd,adec_appdata->pBuffer_tmp+i*adec_appdata->pcm_buf_size, adec_appdata->pcm_buf_size )
+ != (ssize_t)(adec_appdata->pcm_buf_size) )
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+
+ }
+ DEBUG_PRINT("AUDIO_START called for PCM \n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_START, 0);
+ if (adec_appdata->spill_length != 0 )
+ {
+ if ( write(adec_appdata->m_pcmdrv_fd, pBuffer->pBuffer+((pBuffer->nFilledLen)-adec_appdata->spill_length),adec_appdata->spill_length)
+ != adec_appdata->spill_length )
+ {
+ DEBUG_PRINT("FillBufferDone: Write data to PCM failed\n");
+ return -1;
+ }
+ }
+
+
+
+
+ adec_appdata->copy_done = 0;
+ adec_appdata->start_done = 1;
+ }
+ if((adec_appdata->pcmplayback && (adec_appdata->pcm_device_type == HOST_PCM_DEVICE)) ||
+ (!adec_appdata->pcmplayback && adec_appdata->filewrite))
+ {
+ DEBUG_PRINT(" FBD calling FTB");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+ }
+ }
+ else
+ {
+ unsigned int len=0;
+ hpcm_info ftb;
+ ftb.msg_type = DATA;
+ ftb.hComponent = hComponent;
+ ftb.bufHdr = pBuffer;
+ len= write(adec_appdata->mp3_hpcm.pipe_out,&ftb,sizeof(hpcm_info));
+ DEBUG_PRINT(" FillBufferDone: writing data to hpcm thread len=%d\n",len);
+
+ }
+
+ }
+
+ /* Write o/p data in Async manner to PCM Dec Driver */
+ if(adec_appdata->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ if(adec_appdata->count == 1)
+ {
+ DEBUG_PRINT("FillBufferDone: PCM AUDIO_START\n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_START, 0);
+ }
+
+ audio_aio_buf.buf_len = pBuffer->nAllocLen;
+ audio_aio_buf.data_len = pBuffer->nFilledLen;
+ audio_aio_buf.buf_addr = pBuffer->pBuffer;
+ audio_aio_buf.private_data = pBuffer;
+
+ DEBUG_PRINT("FBD:Calling PCMDEC ASYNC_WRITE for bufhdr[%p]\n", pBuffer);
+
+ if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_ASYNC_WRITE, &audio_aio_buf))
+ {
+ DEBUG_PRINT("\nERROR in PCMDEC ASYNC WRITE call\n");
+ return OMX_ErrorHardware;
+ }
+
+ pthread_mutex_lock(&adec_appdata->pcm_buf_lock);
+ adec_appdata->num_pcm_buffers++;
+ DEBUG_PRINT("FBD: Bufcnt with PCMDEC = %d\n", adec_appdata->num_pcm_buffers);
+ pthread_mutex_unlock(&adec_appdata->pcm_buf_lock);
+
+ DEBUG_PRINT("FBD: PCMDEC ASYNC_WRITE call is succesfull\n");
+ }
+ }
+ else if(adec_appdata->pcmplayback && !pBuffer->nFilledLen)
+ {
+ DEBUG_PRINT(" FBD calling FTB...special case");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+
+ }
+ else if(!(adec_appdata->pcmplayback) && (adec_appdata->filewrite))
+ {
+ DEBUG_PRINT(" FBD calling FTB");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+
+ }
+#endif // PCM_PLAYBACK
+
+ if(pBuffer->nFlags & OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT("FBD EOS REACHED...........\n");
+ adec_appdata->bEosOnOutputBuf = true;
+ }
+
+ return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+ struct adec_appdata* adec_appdata;
+
+ if(NULL != pAppData)
+ adec_appdata = (struct adec_appdata*) pAppData;
+ else
+ return OMX_ErrorBadParameter;
+ DEBUG_PRINT("\nFunction %s cnt[%d]\n", __FUNCTION__,adec_appdata->ebd_cnt);
+ adec_appdata->ebd_cnt++;
+ adec_appdata->used_ip_buf_cnt--;
+ if(adec_appdata->bEosOnInputBuf) {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT(" TBD:::De Init the open max here....!!!\n");
+ DEBUG_PRINT("*********************************************\n");
+
+ return OMX_ErrorNone;
+ }
+ else if (adec_appdata->bFlushing == true) {
+ if (adec_appdata->used_ip_buf_cnt == 0) {
+ fseek(adec_appdata->inputBufferFile, 0, 0);
+ adec_appdata->bFlushing = false;
+ }
+ else {
+ DEBUG_PRINT("omx_mp3_adec_test: more buffer to come back\n");
+ return OMX_ErrorNone;
+ }
+ }
+ if((readBytes = Read_Buffer(pBuffer,adec_appdata->inputBufferFile)) > 0) {
+ pBuffer->nFilledLen = readBytes;
+ adec_appdata->used_ip_buf_cnt++;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else {
+ DEBUG_PRINT("\n readBytes = %d\n", readBytes);
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ adec_appdata->bEosOnInputBuf = true;
+ adec_appdata->used_ip_buf_cnt++;
+ pBuffer->nFilledLen = 0;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+
+void signal_handler(int sig_id)
+{
+ /* Flush */
+
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("SIGUSR1 Invoked\n");
+ if(!is_multi_inst)
+ {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ adec_mp3_inst1.bFlushing = true;
+ OMX_SendCommand(adec_mp3_inst1.mp3_dec_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ }
+ }
+ else if (sig_id == SIGUSR2) {
+ DEBUG_PRINT("SIGUSR2 Invoked\n");
+ if(!is_multi_inst)
+ {
+ if (adec_mp3_inst1.bPause == true) {
+ DEBUG_PRINT("%s resume playback\n", __FUNCTION__);
+ adec_mp3_inst1.bPause = false;
+ OMX_SendCommand(adec_mp3_inst1.mp3_dec_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ }
+ else {
+ DEBUG_PRINT("%s pause playback\n", __FUNCTION__);
+ adec_mp3_inst1.bPause = true;
+ OMX_SendCommand(adec_mp3_inst1.mp3_dec_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+ }
+}
+
+
+void* thread_function(void* data)
+{
+ struct adec_appdata *adec_mp3_inst = (struct adec_appdata *)data;
+ struct wav_header hdr;
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+ int bytes_writen = 0;
+
+#ifdef AUDIOV2
+strlcpy(adec_mp3_inst1.device,"speaker_stereo_rx",
+ sizeof(adec_mp3_inst1.device));
+adec_mp3_inst1.control=0;
+#endif
+
+ if(Init_Decoder(adec_mp3_inst)!= 0x00) {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return (void*)(-1);
+ }
+
+ if(Play_Decoder(adec_mp3_inst) != 0x00) {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return (void*) (-1);
+ }
+
+ // Wait till EOS is reached...
+ if(adec_mp3_inst->bReconfigureOutputPort)
+ {
+ wait_for_event(adec_mp3_inst);
+ }
+
+ DEBUG_PRINT(" bOutputEosReached = %d bInputEosReached = %d \n",
+ adec_mp3_inst->bOutputEosReached, adec_mp3_inst->bInputEosReached);
+ if(adec_mp3_inst->bOutputEosReached) {
+
+ #ifdef PCM_PLAYBACK
+ if(adec_mp3_inst->pcmplayback == 1) {
+ sleep(1);
+ if(adec_mp3_inst->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ fsync(adec_mp3_inst->m_pcmdrv_fd);
+ }
+
+
+ if(adec_mp3_inst->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ DEBUG_PRINT("\n Calling ABORT_GET_EVENT for PCMDEC driver\n");
+ if(0 > ioctl(adec_mp3_inst->m_pcmdrv_fd, AUDIO_ABORT_GET_EVENT, NULL))
+ {
+ DEBUG_PRINT("\n Error in ioctl AUDIO_ABORT_GET_EVENT\n");
+ }
+
+ DEBUG_PRINT("\n Waiting for PCMDrv Event Thread complete\n");
+ pthread_join(adec_mp3_inst->m_pcmdrv_evt_thread_id, NULL);
+ }
+ else
+ {
+ DEBUG_PRINT("*******************************\n");
+ DEBUG_PRINT("\n HPCMDrv Event Thread complete %d %d\n",
+ adec_mp3_inst->mp3_hpcm.pipe_in,
+ adec_mp3_inst->mp3_hpcm.pipe_out);
+ close(adec_mp3_inst->mp3_hpcm.pipe_in);
+ close(adec_mp3_inst->mp3_hpcm.pipe_out);
+ adec_mp3_inst->mp3_hpcm.pipe_in=-1;
+ adec_mp3_inst->mp3_hpcm.pipe_out=-1;
+ pthread_join(adec_mp3_inst->m_pcmdrv_evt_thread_id, NULL);
+ DEBUG_PRINT("*******************************\n");
+ }
+ ioctl(adec_mp3_inst->m_pcmdrv_fd, AUDIO_STOP, 0);
+#ifdef AUDIOV2
+ if(adec_mp3_inst->devmgr_fd >= 0)
+ {
+ write_devctlcmd(adec_mp3_inst->devmgr_fd, "-cmd=unregister_session_rx -sid=", adec_mp3_inst->session_id_hpcm);
+ }
+ else
+ {
+ if (msm_route_stream(1, adec_mp3_inst->session_id_hpcm, adec_mp3_inst->device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ }
+ }
+#endif
+ if(adec_mp3_inst->m_pcmdrv_fd >= 0) {
+ close(adec_mp3_inst->m_pcmdrv_fd);
+ adec_mp3_inst->m_pcmdrv_fd = -1;
+ DEBUG_PRINT(" PCM device closed succesfully \n");
+ }
+ else {
+ DEBUG_PRINT(" PCM device close failure \n");
+ }
+ }
+ #endif // PCM_PLAYBACK
+
+ if((adec_mp3_inst->tunnel == 0) && (adec_mp3_inst->filewrite == 1)) {
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = adec_mp3_inst->mp3Header.channel_mode;
+ hdr.sample_rate = adec_mp3_inst->mp3Header.sampling_rate;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("output file closed and EOS reached total decoded data length %d\n",adec_mp3_inst->totaldatalen);
+ hdr.data_sz = adec_mp3_inst->totaldatalen;
+ hdr.riff_sz = adec_mp3_inst->totaldatalen + 8 + 16 + 8;
+ fseek(adec_mp3_inst->outputBufferFile, 0L , SEEK_SET);
+ bytes_writen = fwrite(&hdr,1,sizeof(hdr),adec_mp3_inst->outputBufferFile);
+ if (bytes_writen <= 0) {
+ DEBUG_PRINT("Invalid Wav header write failed\n");
+ }
+ fclose(adec_mp3_inst->outputBufferFile);
+ }
+ /************************************************************************************/
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(adec_mp3_inst->mp3_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event(adec_mp3_inst);
+
+ DEBUG_PRINT("\nMoving the decoder to loaded state \n");
+ OMX_SendCommand(adec_mp3_inst->mp3_dec_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < adec_mp3_inst->input_buf_cnt; ++bufCnt) {
+ Free_Buffer(adec_mp3_inst, 0, adec_mp3_inst->pInputBufHdrs[bufCnt]);
+ }
+
+ free(adec_mp3_inst->pInputBufHdrs);
+ adec_mp3_inst->pInputBufHdrs = NULL;
+
+ if(adec_mp3_inst->tunnel == 0) {
+ DEBUG_PRINT("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < adec_mp3_inst->output_buf_cnt; ++bufCnt) {
+ Free_Buffer(adec_mp3_inst, 1, adec_mp3_inst->pOutputBufHdrs[bufCnt]);
+ }
+ free(adec_mp3_inst->pOutputBufHdrs);
+ adec_mp3_inst->pOutputBufHdrs = NULL;
+ }
+
+ DEBUG_PRINT("*******************************************\n");
+ wait_for_event(adec_mp3_inst);
+ adec_mp3_inst->ebd_cnt=0;
+ adec_mp3_inst->bOutputEosReached = false;
+ adec_mp3_inst->bInputEosReached = false;
+ adec_mp3_inst->bEosOnInputBuf = 0;
+ adec_mp3_inst->bEosOnOutputBuf = 0;
+ adec_mp3_inst->bReconfigureOutputPort = 0;
+ if (adec_mp3_inst->pBuffer_tmp )
+ {
+ free(adec_mp3_inst->pBuffer_tmp);
+ adec_mp3_inst->pBuffer_tmp =NULL;
+ }
+ result = OMX_FreeHandle(adec_mp3_inst->mp3_dec_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT_ERROR("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+ else DEBUG_PRINT("OMX_FreeHandle success...\n");
+
+ adec_mp3_inst->mp3_dec_handle = NULL;
+#ifdef AUDIOV2
+ if(adec_mp3_inst->devmgr_fd >= 0)
+ {
+ write_devctlcmd(adec_mp3_inst->devmgr_fd, "-cmd=unregister_session_rx -sid=", adec_mp3_inst->session_id);
+ close(adec_mp3_inst->devmgr_fd);
+ }
+ else
+ {
+ if (msm_route_stream(1, adec_mp3_inst->session_id, adec_mp3_inst->device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return (void *)-1;
+ }
+ if (msm_en_device(adec_mp3_inst->device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return (void *)-1;
+ }
+ msm_mixer_close();
+ }
+#endif
+ pthread_cond_destroy(&adec_mp3_inst->cond);
+ pthread_mutex_destroy(&adec_mp3_inst->lock);
+
+ if(adec_mp3_inst->pcmplayback &&
+ adec_mp3_inst->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ pthread_mutex_destroy(&adec_mp3_inst->pcm_buf_lock);
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct sigaction sa;
+ pthread_t thread1_id;
+ int thread1_ret=0;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+ if(argc == 7)
+ {
+ adec_appdata_init(&adec_mp3_inst1);
+ pthread_cond_init(&adec_mp3_inst1.cond, 0);
+ pthread_mutex_init(&adec_mp3_inst1.lock, 0);
+ adec_mp3_inst1.in_filename = argv[1];
+ adec_mp3_inst1.bParseHeader = atoi(argv[2]);
+ adec_mp3_inst1.pcmplayback = atoi(argv[3]);
+ adec_mp3_inst1.filewrite = atoi(argv[4]);
+ adec_mp3_inst1.out_filename = argv[5];
+ adec_mp3_inst1.buffer_option = atoi(argv[6]);
+
+ //adec_mp3_inst1.out_filename = (char*)malloc(sizeof("audio.wav"));
+ //strncpy(adec_mp3_inst1.out_filename,"audio.wav",strlen("audio.wav"));
+ if(adec_mp3_inst1.tunnel == 0)
+ adec_mp3_inst1.aud_comp = "OMX.PV.mp3dec";
+
+ if(adec_mp3_inst1.pcmplayback &&
+ adec_mp3_inst1.pcm_device_type == PCM_DEC_DEVICE)
+ {
+ pthread_mutex_init(&adec_mp3_inst1.pcm_buf_lock, 0);
+ }
+ DEBUG_PRINT(" OMX test app : aud_comp instance = %s\n",adec_mp3_inst1.aud_comp);
+
+ }
+ else
+ {
+ DEBUG_PRINT( "invalid format: \n");
+ DEBUG_PRINT( "ex: ./sw-adec-omxmp3-test MP3INPUTFILE ParseHeader PCMPLAYBACK \n");
+ DEBUG_PRINT( "FILEWRITE OUTFILENAME BUFFEROPTION PCMDEVICETYPE\n");
+ DEBUG_PRINT( "ParseHeader= 1 (Parses MP3 Header) \n");
+ DEBUG_PRINT( "ParseHeader= 0 (Uses Default Sampling rate and channel) \n");
+ DEBUG_PRINT( "PCMPLAYBACK = 1 (ENABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "PCMPLAYBACK = 0 (DISABLES PCM PLAYBACK IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 1 (ENABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "FILEWRITE = 0 (DISABLES PCM FILEWRITE IN NON TUNNEL MODE) \n");
+ DEBUG_PRINT( "BUFFER OPTION = 0 (AllocateBuffer case)\n");
+ DEBUG_PRINT( "BUFFER OPTION = 1 (UseBuffer case)\n");
+ return 0;
+ }
+
+ if(adec_mp3_inst1.tunnel == 0)
+ adec_mp3_inst1.aud_comp = "OMX.PV.mp3dec";
+
+ DEBUG_PRINT(" OMX test app : aud_comp instance 1= %s\n",adec_mp3_inst1.aud_comp);
+ pthread_create (&thread1_id, NULL, &thread_function, &adec_mp3_inst1);
+ pthread_join(thread1_id,(void**) &thread1_ret);
+ if(0 == thread1_ret)
+ DEBUG_PRINT(" Thread 1 ended successfully\n");
+
+ /* Deinit OpenMAX */
+ OMX_Deinit();
+
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ return 0;
+}
+
+
+int Init_Decoder(struct adec_appdata* adec_appdata)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ typedef OMX_U8* OMX_U8_PTR;
+ char *role ="audio_decoder.mp3";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Mp3_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT("\nTotal components of role = %s :%u \n", role ,(unsigned)total);
+
+ DEBUG_PRINT("\nComponent before GEThandle %s \n", adec_appdata->aud_comp);
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&adec_appdata->mp3_dec_handle),
+ (OMX_STRING)adec_appdata->aud_comp, adec_appdata, &call_back);
+
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", adec_appdata->aud_comp);
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nComponent %s is in LOADED state with handle: %p\n", adec_appdata->aud_comp,adec_appdata->mp3_dec_handle);
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(adec_appdata->portParam);
+ omxresult = OMX_GetParameter(adec_appdata->mp3_dec_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&(adec_appdata->portParam));
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nportParam.nPorts:%u\n", (unsigned)(adec_appdata->portParam.nPorts));
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%u\n",
+ (unsigned)(adec_appdata->portParam.nStartPortNumber));
+ }
+ return 0;
+}
+
+int Play_Decoder(struct adec_appdata* adec_appdata)
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+ #ifdef PCM_PLAYBACK
+ struct msm_audio_config drv_pcm_config;
+ #endif // PCM_PLAYBACK
+
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file(adec_appdata)) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+ /* Query the decoder input min buf requirements */
+ CONFIG_VERSION_SIZE(adec_appdata->inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ adec_appdata->inputportFmt.nPortIndex = adec_appdata->portParam.nStartPortNumber;
+
+ OMX_GetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->inputportFmt);
+ DEBUG_PRINT ("\nDec: Input Buffer Count %u\n",(unsigned) (adec_appdata->inputportFmt.nBufferCountMin));
+ DEBUG_PRINT ("\nDec: Input Buffer Size %u\n", (unsigned) (adec_appdata->inputportFmt.nBufferSize));
+
+ if(OMX_DirInput != adec_appdata->inputportFmt.eDir) {
+ DEBUG_PRINT ("\nDec: Expect Input Port\n");
+ return -1;
+ }
+
+ adec_appdata->inputportFmt.nBufferCountActual = adec_appdata->inputportFmt.nBufferCountMin + 5;
+ OMX_SetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->inputportFmt);
+ OMX_GetExtensionIndex(adec_appdata->mp3_dec_handle,"OMX.Qualcomm.index.audio.sessionid",&index);
+ OMX_GetParameter(adec_appdata->mp3_dec_handle,index,&adec_appdata->streaminfoparam);
+#ifdef AUDIOV2
+ adec_appdata->session_id = adec_appdata->streaminfoparam.sessionId;
+ adec_appdata->devmgr_fd = open("/data/omx_devmgr", O_WRONLY);
+ if(adec_appdata->devmgr_fd >= 0)
+ {
+ adec_appdata->control = 0;
+ write_devctlcmd(adec_appdata->devmgr_fd, "-cmd=register_session_rx -sid=", adec_appdata->session_id);
+ }
+#endif
+ if(adec_appdata->tunnel == 0) {
+ /* Query the decoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(adec_appdata->outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ adec_appdata->outputportFmt.nPortIndex = adec_appdata->portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->outputportFmt);
+ DEBUG_PRINT ("\nDec: Output Buffer Count %u\n",(unsigned)( adec_appdata->outputportFmt.nBufferCountMin));
+ DEBUG_PRINT ("\nDec: Output Buffer Size %u\n",(unsigned)( adec_appdata->outputportFmt.nBufferSize));
+
+ if(OMX_DirOutput != adec_appdata->outputportFmt.eDir) {
+ DEBUG_PRINT ("\nDec: Expect Output Port\n");
+ return -1;
+ }
+ adec_appdata->outputportFmt.nBufferCountActual = adec_appdata->outputportFmt.nBufferCountMin + 3;
+ OMX_SetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamPortDefinition,&adec_appdata->outputportFmt);
+ }
+
+ CONFIG_VERSION_SIZE(adec_appdata->mp3param);
+
+ DEBUG_PRINT(" adec_appdata->pcm_device_type = %d\n", adec_appdata->pcm_device_type);
+ #ifdef PCM_PLAYBACK
+ if(adec_appdata->pcmplayback && adec_appdata->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ DEBUG_PRINT(" open pcm dec device \n");
+ adec_appdata->m_pcmdrv_fd = open("/dev/msm_pcm_dec", O_WRONLY | O_NONBLOCK);
+ if (adec_appdata->m_pcmdrv_fd < 0)
+ {
+ DEBUG_PRINT("Play_Decoder: cannot open pcm_dec device");
+ return -1;
+ }
+ DEBUG_PRINT(" Play_Decoder: open pcm device successfull\n");
+
+ /* Create the Event Thread for PCM Dec driver */
+ if (pthread_create(&adec_appdata->m_pcmdrv_evt_thread_id, 0, process_pcm_drv_events,
+ adec_appdata) < 0)
+ {
+ DEBUG_PRINT("\n Event Thread creation for PCM Dec driver FAILED\n");
+ return -1;
+ }
+ }
+ else
+ {
+ int fds[2];
+ if (pipe(fds)) {
+ DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__);
+ }
+ adec_appdata->mp3_hpcm.pipe_in=fds[0];
+ adec_appdata->mp3_hpcm.pipe_out=fds[1];
+ DEBUG_PRINT("********************************\n");
+ DEBUG_PRINT("HPCM PIPES %d %d\n",fds[0],fds[1]);
+ DEBUG_PRINT("********************************\n");
+
+ if (pthread_create(&adec_appdata->m_pcmdrv_evt_thread_id, 0, process_hpcm_drv_events,
+ adec_appdata) < 0)
+ {
+ DEBUG_PRINT_ERROR("\n Event Thread creation for PCM Dec driver FAILED\n");
+ return -1;
+ }
+ }
+ #endif // PCM_PLAYBACK
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> IDLE\n");
+ OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+
+ adec_appdata->input_buf_cnt = adec_appdata->inputportFmt.nBufferCountActual; //inputportFmt.nBufferCountMin + 5;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+
+ if(adec_appdata->buffer_option == USE_BUFFER_CASE)
+ {
+ /* Use buffer on decoder's I/P port */
+ adec_appdata->error = Use_Buffer(adec_appdata,
+ adec_appdata->inputportFmt.nPortIndex);
+ if (adec_appdata->error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT ("\nOMX_UseBuffer Input buffer error\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT ("\nOMX_UseBuffer Input buffer success\n");
+ }
+ }
+ else
+ {
+ /* Allocate buffer on decoder's i/p port */
+ adec_appdata->error = Allocate_Buffer(adec_appdata,
+ adec_appdata->inputportFmt.nPortIndex);
+ if (adec_appdata->error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+ }
+
+ if(adec_appdata->tunnel == 0) {
+ adec_appdata->output_buf_cnt = adec_appdata->outputportFmt.nBufferCountActual ;
+
+ if(adec_appdata->buffer_option == USE_BUFFER_CASE)
+ {
+ /* Use buffer on decoder's O/P port */
+ adec_appdata->error = Use_Buffer(adec_appdata,
+ adec_appdata->outputportFmt.nPortIndex);
+ if (adec_appdata->error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT ("\nOMX_UseBuffer Output buffer error\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT ("\nOMX_UseBuffer Output buffer success\n");
+ }
+ }
+ else
+ {
+ /* Allocate buffer on decoder's O/Pp port */
+ adec_appdata->error = Allocate_Buffer(adec_appdata,
+ adec_appdata->outputportFmt.nPortIndex);
+ if (adec_appdata->error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+ }
+ }
+
+ wait_for_event(adec_appdata);
+
+ DEBUG_PRINT ("\nOMX_SendCommand Decoder -> Executing\n");
+ OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event(adec_appdata);
+
+ if((adec_appdata->tunnel == 0))
+ {
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+
+ for(i=0; i < adec_appdata->output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ adec_appdata->pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ adec_appdata->pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(adec_appdata->mp3_dec_handle, adec_appdata->pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+ }
+
+
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < adec_appdata->input_buf_cnt;i++) {
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ adec_appdata->pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(adec_appdata->pInputBufHdrs[i],adec_appdata->inputBufferFile);
+ if(Size <=0 ) {
+ DEBUG_PRINT("\n readBytes = %d\n", Size);
+ DEBUG_PRINT("NO DATA READ\n");
+ adec_appdata->bEosOnInputBuf = true;
+ Size = 0;
+ adec_appdata->pInputBufHdrs[i]->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT("Play_decoder::EOS or Error while reading file\n");
+ }
+ adec_appdata->pInputBufHdrs[i]->nFilledLen = Size;
+ adec_appdata->pInputBufHdrs[i]->nInputPortIndex = 0;
+ adec_appdata->used_ip_buf_cnt++;
+
+ if(adec_appdata->first_buffer)
+ {
+ adec_appdata->first_buffer = 0;
+ ret = parse_mp3_frameheader(adec_appdata->pInputBufHdrs[i],&adec_appdata->mp3Header);
+ if(ret != OMX_ErrorNone)
+ {
+ DEBUG_PRINT("parse_mp3_frameheader return failure\n");
+ adec_appdata->mp3Header.sampling_rate = DEFAULT_SAMPLING_RATE;
+ adec_appdata->mp3Header.channel_mode = DEFAULT_CHANNEL_MODE;
+ }
+
+ /* Get the Output port PCM configuration details */
+ adec_appdata->mp3param.nPortIndex = 0;
+ adec_appdata->mp3param.nSampleRate = adec_appdata->mp3Header.sampling_rate;
+ adec_appdata->mp3param.nChannels = adec_appdata->mp3Header.channel_mode;
+ adec_appdata->mp3param.nBitRate = 0;
+ adec_appdata->mp3param.eChannelMode = OMX_AUDIO_ChannelModeStereo;
+ adec_appdata->mp3param.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
+
+ if(!adec_appdata->bParseHeader)
+ {
+ adec_appdata->mp3param.nSampleRate = DEFAULT_SAMPLING_RATE;
+ adec_appdata->mp3param.nChannels = DEFAULT_CHANNEL_MODE;
+ }
+
+ OMX_SetParameter(adec_appdata->mp3_dec_handle, OMX_IndexParamAudioMp3,
+ (OMX_PTR)&adec_appdata->mp3param);
+
+ if(adec_appdata->pcmplayback &&
+ adec_appdata->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ DEBUG_PRINT("configure Driver for PCM playback \n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_GET_CONFIG, &drv_pcm_config);
+ drv_pcm_config.sample_rate = adec_appdata->mp3Header.sampling_rate;
+ drv_pcm_config.channel_count = adec_appdata->mp3Header.channel_mode;
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+ }
+ }
+
+ ret = OMX_EmptyThisBuffer(adec_appdata->mp3_dec_handle, adec_appdata->pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ }
+
+ /* Waiting for EOS or PortSettingsChange*/
+ while(1)
+ {
+ wait_for_event(adec_appdata);
+ if(adec_appdata->bOutputEosReached)
+ {
+ adec_appdata->bReconfigureOutputPort = 0;
+ printf("bOutputEosReached breaking\n");
+ break;
+ }
+ else
+ {
+ if(adec_appdata->tunnel == 0 && adec_appdata->bReconfigureOutputPort)
+ process_portreconfig(adec_appdata);
+ }
+ }
+
+ return 0;
+}
+
+unsigned int extract_id3_header_size(OMX_U8* buffer)
+{
+ unsigned int size = 0;
+ OMX_U8* pTemp = NULL;
+
+ if(!buffer)
+ {
+ return 0;
+ }
+
+ pTemp = buffer+6;
+ size = ((pTemp[0]&0x7F) << 21);
+ size |= ((pTemp[1]&0x7F) << 14);
+ size |= ((pTemp[2]&0x7F) << 7);
+ size |= ((pTemp[3]&0x7F));
+
+ return (size+10);
+}
+
+OMX_ERRORTYPE parse_mp3_frameheader(OMX_BUFFERHEADERTYPE* buffer,
+ struct mp3_header *header)
+{
+ OMX_U8* temp_pBuf1 = NULL;
+ unsigned int i = 0;
+ unsigned int id3_size = 0;
+ OMX_U8 temp;
+
+
+ for(i=0;i<10;i++)
+ DEBUG_PRINT ("\n buffer[%d] = 0x%x",i,buffer->pBuffer[i]);
+ if ( buffer->nFilledLen == 0 )
+ {
+ DEBUG_PRINT ("\n Length is zero hence no point in processing \n");
+ return OMX_ErrorNone;
+ }
+
+ temp_pBuf1 = buffer->pBuffer;
+
+ i = 0;
+ while (i<buffer->nFilledLen)
+ {
+ if((i < buffer->nFilledLen-2) && (temp_pBuf1[0] == 0x49) &&
+ (temp_pBuf1[1] == 0x44) && (temp_pBuf1[2] == 0x33))
+ {
+ if(i < buffer->nFilledLen-10)
+ {
+ id3_size = extract_id3_header_size(temp_pBuf1);
+ DEBUG_PRINT("\n ID3 tag size = %u\n", id3_size);
+ }
+ else
+ {
+ DEBUG_PRINT("\nFull ID3 tag header not available\n");
+ return OMX_ErrorMax;
+ }
+
+ if(id3_size && i < buffer->nFilledLen-id3_size)
+ {
+ i += id3_size;
+ temp_pBuf1 += id3_size;
+
+ DEBUG_PRINT("\n Skipping valid ID3 tag\n");
+ break;
+ }
+ else
+ {
+ DEBUG_PRINT("\n ID3 Tag size 0 or exceeds 1st buffer\n");
+ return OMX_ErrorMax;
+ }
+ }
+ else if(*temp_pBuf1 == 0xFF )
+ {
+ break;
+ }
+
+ i++;
+ temp_pBuf1++;
+ }
+
+ if ( i==buffer->nFilledLen )
+ return OMX_ErrorMax;
+
+ temp = temp_pBuf1[0];
+ header->sync = temp & 0xFF;
+ if ( header->sync == 0xFF )
+ {
+ temp = temp_pBuf1[1];
+ header->sync = temp & 0xC0;
+ if ( header->sync != 0xC0 )
+ {
+ DEBUG_PRINT("parse_mp3_frameheader failure");
+ return OMX_ErrorMax;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("parse_mp3_frameheader failure");
+ return OMX_ErrorMax;
+ }
+ temp = temp_pBuf1[1];
+ header->version = (temp & 0x18)>>3;
+ header->Layer = (temp & 0x06)>>1;
+ temp = temp_pBuf1[2];
+ header->sampling_rate = (temp & 0x0C)>>2;
+ temp = temp_pBuf1[3];
+ header->channel_mode = (temp & 0xC0)>>6;
+
+ DEBUG_PRINT("Channel Mode: %u, Sampling rate: %u and header version: %u from the header\n",
+ (unsigned)(header->channel_mode),(unsigned) (header->sampling_rate),(unsigned)( header->version));
+ // Stereo, Joint Stereo,Dual Mono)
+ if ( (header->channel_mode == 0)||(header->channel_mode == 1)||(header->channel_mode == 2) )
+ {
+ header->channel_mode = 2; // stereo
+ }
+ else if ( header->channel_mode == 3 )
+ {
+ header->channel_mode = 1; // for all other cases configuring as mono TBD
+ }
+ else
+ {
+ header->channel_mode = 2; // if the channel is not recog. making the channel by default to Stereo.
+ DEBUG_PRINT("Defauting the channel mode to Stereo");
+ }
+ header->sampling_rate = mp3_frequency_index[header->sampling_rate][header->version];
+ DEBUG_PRINT(" frequency = %u, channels = %u\n",(unsigned)(header->sampling_rate),(unsigned)(header->channel_mode));
+ return OMX_ErrorNone;
+}
+
+
+static OMX_ERRORTYPE Allocate_Buffer ( struct adec_appdata* adec_appdata,
+ OMX_U32 nPortIndex )
+{
+ OMX_BUFFERHEADERTYPE ***pBufHdrs = NULL;
+ OMX_BUFFERHEADERTYPE *bufHdr = NULL;
+ struct msm_audio_pmem_info pmem_info;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+ long bufCntMin = 0;
+ long bufSize = 0;
+
+ if(!adec_appdata || !adec_appdata->mp3_dec_handle)
+ {
+ DEBUG_PRINT("\nAllocate_Buffer:Invalid i/p parameter\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ if(nPortIndex == 0)
+ {
+ pBufHdrs = &adec_appdata->pInputBufHdrs;
+ bufCntMin = adec_appdata->input_buf_cnt;
+ bufSize = adec_appdata->inputportFmt.nBufferSize;
+ }
+ else if(nPortIndex == 1)
+ {
+ pBufHdrs = &adec_appdata->pOutputBufHdrs;
+ bufCntMin = adec_appdata->output_buf_cnt;
+ bufSize = adec_appdata->outputportFmt.nBufferSize;
+ }
+ else
+ {
+ DEBUG_PRINT("\nAllocate_Buffer:Invalid PortIndex\n");
+ return OMX_ErrorBadPortIndex;
+ }
+
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ if(*pBufHdrs == NULL)
+ {
+ DEBUG_PRINT ("\nAllocate_Buffer: *pBufHdrs allocation failed!\n");
+ return OMX_ErrorInsufficientResources;
+ }
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(adec_appdata->mp3_dec_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+
+ if(error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT("\nOMX_AllocateBuffer ERROR\n");
+ break;
+ }
+
+#ifdef PCM_PLAYBACK
+ if(adec_appdata->pcmplayback == 1 && adec_appdata->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ if(nPortIndex == 1)
+ {
+ bufHdr = (*pBufHdrs)[bufCnt];
+
+ if(bufHdr)
+ {
+ pmem_info.fd = (int)bufHdr->pOutputPortPrivate;
+ pmem_info.vaddr = bufHdr->pBuffer;
+
+ DEBUG_PRINT ("\n PCMDEC REGISTER_PMEM fd = %d, vaddr = %x",
+ pmem_info.fd,(unsigned) (pmem_info.vaddr));
+ if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_REGISTER_PMEM, &pmem_info))
+ {
+ DEBUG_PRINT("\n Error in ioctl AUDIO_REGISTER_PMEM\n");
+ error = OMX_ErrorHardware;
+ break;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("\nbufHdr is NULL, couldnt REGISTER PMEM\n");
+ error = OMX_ErrorUndefined;
+ break;
+ }
+ }
+ }
+#endif
+
+ }
+
+ if(error != OMX_ErrorNone && bufCnt < bufCntMin)
+ {
+ while(bufCnt)
+ {
+ bufCnt--;
+ bufHdr = (*pBufHdrs)[bufCnt];
+ Free_Buffer(adec_appdata, nPortIndex, bufHdr);
+ }
+ free(*pBufHdrs);
+ *pBufHdrs = NULL;
+ }
+
+ return error;
+}
+
+static OMX_ERRORTYPE Use_Buffer ( struct adec_appdata* adec_appdata,
+ OMX_U32 nPortIndex )
+{
+ OMX_BUFFERHEADERTYPE ***pBufHdrs = NULL;
+ OMX_BUFFERHEADERTYPE *bufHdr = NULL;
+ OMX_U8 *buffer = NULL;
+ struct msm_audio_pmem_info pmem_info;
+ OMX_ERRORTYPE error = OMX_ErrorNone;
+ long bufCnt = 0;
+ long bufCntMin = 0;
+ long bufSize = 0;
+ int pmem_fd = -1;
+
+ if(!adec_appdata || !adec_appdata->mp3_dec_handle)
+ {
+ DEBUG_PRINT("\nUse_Buffer:Invalid i/p parameter\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ if(nPortIndex == 0)
+ {
+ pBufHdrs = &adec_appdata->pInputBufHdrs;
+ bufCntMin = adec_appdata->input_buf_cnt;
+ bufSize = adec_appdata->inputportFmt.nBufferSize;
+ }
+ else if(nPortIndex == 1)
+ {
+ pBufHdrs = &adec_appdata->pOutputBufHdrs;
+ bufCntMin = adec_appdata->output_buf_cnt;
+ bufSize = adec_appdata->outputportFmt.nBufferSize;
+ }
+ else
+ {
+ DEBUG_PRINT("\nUse_Buffer:Invalid PortIndex\n");
+ return OMX_ErrorBadPortIndex;
+ }
+
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ *pBufHdrs = (OMX_BUFFERHEADERTYPE **)calloc
+ (sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin, 1);
+
+ if(*pBufHdrs == NULL)
+ {
+ DEBUG_PRINT ("\nUse_Buffer: *pBufHdrs allocation failed!\n");
+ return OMX_ErrorInsufficientResources;
+ }
+
+ DEBUG_PRINT("\nUse_Buffer::*pBufHdrs = %p", *pBufHdrs);
+ for(bufCnt = 0; bufCnt < bufCntMin; ++bufCnt)
+ {
+ pmem_fd = open("/dev/pmem_adsp", O_RDWR);
+
+ if (pmem_fd < 0)
+ {
+ DEBUG_PRINT ("\n pmem_adsp open failed");
+ error = OMX_ErrorInsufficientResources;
+ break;
+ }
+
+ DEBUG_PRINT("\nUse_Buffer:: For Buffer %ld, pmem_fd = %d \n", bufCnt,
+ pmem_fd);
+
+ /* Map the PMEM file descriptor into current process address space */
+ buffer = (OMX_U8*) mmap( NULL,
+ bufSize,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ pmem_fd,
+ 0
+ );
+
+ if(MAP_FAILED == buffer)
+ {
+ DEBUG_PRINT ("\n mmap() failed");
+ buffer = NULL;
+ close(pmem_fd);
+ error = OMX_ErrorInsufficientResources;
+ break;
+ }
+
+ DEBUG_PRINT("\n Use_Buffer::Client Buf = %p", buffer);
+ DEBUG_PRINT("\n OMX_UseBuffer No %ld \n", bufCnt);
+ error = OMX_UseBuffer( adec_appdata->mp3_dec_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, (void*)pmem_fd, bufSize, buffer
+ );
+ DEBUG_PRINT("\nUse_Buffer::Buf ret = %p", (*pBufHdrs)[bufCnt]);
+
+ if(error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT("\nOMX_AllocateBuffer ERROR\n");
+ munmap(buffer, bufSize);
+ buffer = NULL;
+ close(pmem_fd);
+ break;
+ }
+
+#ifdef PCM_PLAYBACK
+ if(adec_appdata->pcmplayback == 1 && adec_appdata->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ if(nPortIndex == 1)
+ {
+ bufHdr = (*pBufHdrs)[bufCnt];
+ if(bufHdr)
+ {
+ pmem_info.fd = pmem_fd;
+ pmem_info.vaddr = buffer;
+ DEBUG_PRINT ("\n PCMDEC REGISTER_PMEM fd = %d, vaddr = %x",
+ pmem_info.fd, (unsigned)(pmem_info.vaddr));
+ if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_REGISTER_PMEM, &pmem_info))
+ {
+ DEBUG_PRINT("\n Error in ioctl AUDIO_REGISTER_PMEM\n");
+ error = OMX_ErrorHardware;
+ break;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("\nbufHdr is NULL, couldnt REGISTER PMEM\n");
+ error = OMX_ErrorUndefined;
+ break;
+ }
+ }
+ }
+#endif
+
+ }
+
+ if(error != OMX_ErrorNone && bufCnt != bufCntMin)
+ {
+ while(bufCnt)
+ {
+ bufCnt--;
+ bufHdr = (*pBufHdrs)[bufCnt];
+ Free_Buffer(adec_appdata, nPortIndex, bufHdr);
+ }
+ free(*pBufHdrs);
+ *pBufHdrs = NULL;
+ }
+
+ return error;
+}
+
+static OMX_ERRORTYPE Free_Buffer ( struct adec_appdata* adec_appdata,
+ OMX_U32 nPortIndex,
+ OMX_BUFFERHEADERTYPE *bufHdr
+ )
+{
+ struct msm_audio_pmem_info audio_pmem_buf;
+ OMX_ERRORTYPE error = OMX_ErrorNone;
+ int pmem_fd = -1;
+
+ if(!adec_appdata || !adec_appdata->mp3_dec_handle || !bufHdr
+ || (nPortIndex > 1))
+ {
+ DEBUG_PRINT("\nFree_Buffer:Invalid i/p parameters\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ DEBUG_PRINT("\nFree_Buffer::bufHdr = %p", bufHdr);
+ if(adec_appdata->buffer_option == USE_BUFFER_CASE)
+ {
+ pmem_fd = (int)bufHdr->pAppPrivate;
+ }
+ else
+ {
+ if(nPortIndex == 1)
+ {
+ pmem_fd = (int)bufHdr->pOutputPortPrivate;
+ }
+ }
+
+#ifdef PCM_PLAYBACK
+ if(adec_appdata->pcmplayback && adec_appdata->pcm_device_type == PCM_DEC_DEVICE)
+ {
+ if(nPortIndex == 1 && pmem_fd > 0)
+ {
+ audio_pmem_buf.fd = pmem_fd;
+ audio_pmem_buf.vaddr = bufHdr->pBuffer;
+ DEBUG_PRINT ("\n PCMDEC DEREGISTER_PMEM fd = %d, vaddr = %x",
+ audio_pmem_buf.fd,(unsigned)( audio_pmem_buf.vaddr));
+ if(0 > ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_DEREGISTER_PMEM, &audio_pmem_buf))
+ {
+ DEBUG_PRINT("\n Error in ioctl AUDIO_DEREGISTER_PMEM\n");
+ error = OMX_ErrorHardware;
+ }
+ }
+ }
+#endif
+
+ if(adec_appdata->buffer_option == USE_BUFFER_CASE)
+ {
+ if (bufHdr->pBuffer &&
+ (EINVAL == munmap (bufHdr->pBuffer, bufHdr->nAllocLen)))
+ {
+ DEBUG_PRINT ("\n Error in Unmapping the buffer %p",
+ bufHdr);
+ }
+ bufHdr->pBuffer = NULL;
+ close(pmem_fd);
+ DEBUG_PRINT("FREED CLIENT BUFHDR[%p], pmem_fd[%d]", bufHdr, pmem_fd);
+ }
+ return(OMX_FreeBuffer(adec_appdata->mp3_dec_handle, nPortIndex, bufHdr));
+}
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr,FILE* inputBufferFile)
+{
+ int bytes_read=0;
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile);
+ DEBUG_PRINT ("\nBytes read :%d\n",bytes_read);
+ pBufHdr->nFilledLen = bytes_read;
+ if(bytes_read == 0) {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read is Non zero\n");
+ }
+
+ return bytes_read;;
+}
+
+static int open_audio_file (struct adec_appdata* adec_appdata)
+{
+ int error_code = 0;
+ struct wav_header hdr;
+ int header_len = 0;
+ memset(&hdr,0,sizeof(hdr));
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = 2; // Will be updated in the end
+ hdr.sample_rate = 44100; // Will be updated in the end
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, adec_appdata->in_filename);
+ adec_appdata->inputBufferFile = fopen (adec_appdata->in_filename, "rb");
+ if (adec_appdata->inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ adec_appdata->in_filename);
+ error_code = -1;
+ }
+
+ if((adec_appdata->tunnel == 0) && (adec_appdata->filewrite == 1)) {
+ DEBUG_PRINT("output file is opened\n");
+ adec_appdata->outputBufferFile = fopen(adec_appdata->out_filename,"wb");
+ if (adec_appdata->outputBufferFile == NULL) {
+ DEBUG_PRINT("\no/p file %s could NOT be opened\n",
+ adec_appdata->out_filename);
+ error_code = -1;
+ return error_code;
+ }
+
+ header_len = fwrite(&hdr,1,sizeof(hdr),adec_appdata->outputBufferFile);
+
+ if (header_len <= 0) {
+ DEBUG_PRINT("Invalid Wav header \n");
+ }
+ DEBUG_PRINT(" Length og wav header is %d \n",header_len );
+ }
+ return error_code;
+}
+
+void process_portreconfig(struct adec_appdata* adec_appdata)
+{
+ int bufCnt,i=0;
+ OMX_ERRORTYPE ret;
+ struct msm_audio_config drv_pcm_config;
+
+ unsigned int len=0;
+ hpcm_info ftb;
+ ftb.msg_type = CTRL;
+ ftb.hComponent = NULL;
+ ftb.bufHdr = NULL;
+
+ DEBUG_PRINT("************************************");
+ DEBUG_PRINT("RECIEVED EVENT PORT SETTINGS CHANGED EVENT\n");
+ DEBUG_PRINT("******************************************\n");
+ if(adec_appdata->start_done)
+ sleep(1);
+ len= write(adec_appdata->mp3_hpcm.pipe_out,&ftb,sizeof(hpcm_info));
+ wait_for_event(adec_appdata);
+ DEBUG_PRINT("*PORT SETTINGS CHANGED: FLUSHCOMMAND TO COMPONENT*******\n");
+ adec_appdata->flushinprogress = 1;
+ OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandFlush, 1, NULL);
+ wait_for_event(adec_appdata); // output port
+
+ // Send DISABLE command
+ OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandPortDisable, 1, 0);
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("FREEING BUFFERS output_buf_cnt=%d\n",adec_appdata->output_buf_cnt);
+ DEBUG_PRINT("******************************************\n");
+
+ // Free output Buffer
+ for(bufCnt=0; bufCnt < adec_appdata->output_buf_cnt; ++bufCnt) {
+ Free_Buffer(adec_appdata, 1, adec_appdata->pOutputBufHdrs[bufCnt]);
+ }
+
+ free(adec_appdata->pOutputBufHdrs);
+ adec_appdata->pOutputBufHdrs = NULL;
+ // wait for Disable event to come back
+ wait_for_event(adec_appdata);
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("DISABLE EVENT RECD\n");
+ DEBUG_PRINT("******************************************\n");
+
+ // Send Enable command
+ OMX_SendCommand(adec_appdata->mp3_dec_handle, OMX_CommandPortEnable, 1, 0);
+
+ adec_appdata->flushinprogress = 0;
+
+ // AllocateBuffers
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("ALLOC BUFFER AFTER PORT REENABLE");
+ DEBUG_PRINT("******************************************\n");
+
+ if(adec_appdata->buffer_option == USE_BUFFER_CASE)
+ {
+
+ /* Use buffer on decoder's o/p port */
+ adec_appdata->error = Use_Buffer(adec_appdata,
+ adec_appdata->outputportFmt.nPortIndex);
+ if (adec_appdata->error != OMX_ErrorNone)
+ {
+ DEBUG_PRINT ("\nOMX_UseBuffer Output buffer error\n");
+ return;
+ }
+ else
+ {
+ DEBUG_PRINT ("\nOMX_UseBuffer Output buffer success\n");
+ }
+ }
+ else
+ {
+ /* Allocate buffer on decoder's o/p port */
+ adec_appdata->error = Allocate_Buffer(adec_appdata,
+ adec_appdata->outputportFmt.nPortIndex);
+ if (adec_appdata->error != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error output_buf_cnt=%d\n",adec_appdata->output_buf_cnt);
+ return;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success output_buf_cnt=%d\n",adec_appdata->output_buf_cnt);
+ }
+ }
+
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("ENABLE EVENTiHANDLER RECD\n");
+ DEBUG_PRINT("******************************************\n");
+ // wait for enable event to come back
+ wait_for_event(adec_appdata);
+ if(adec_appdata->pcmplayback && adec_appdata->pcm_device_type == HOST_PCM_DEVICE
+ && adec_appdata->start_done)
+
+ {
+ DEBUG_PRINT(" Calling fsync on pcm driver...\n");
+ while (fsync(adec_appdata->m_pcmdrv_fd) < 0) {
+ printf(" fsync failed\n");
+ sleep(1);
+ }
+ DEBUG_PRINT(" Calling stop on pcm driver...\n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_STOP, 0);
+ DEBUG_PRINT(" Calling flush on pcm driver...\n");
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_FLUSH, 0);
+ sleep(3);
+ OMX_GetParameter(adec_appdata->mp3_dec_handle,OMX_IndexParamAudioMp3,&adec_appdata->mp3param);
+ drv_pcm_config.sample_rate = adec_appdata->mp3param.nSampleRate;
+ drv_pcm_config.channel_count =adec_appdata-> mp3param.nChannels;
+ printf("sample =%lu channel = %lu\n",adec_appdata->mp3param.nSampleRate,adec_appdata->mp3param.nChannels);
+ ioctl(adec_appdata->m_pcmdrv_fd, AUDIO_SET_CONFIG, &drv_pcm_config);
+
+
+ DEBUG_PRINT("Configure Driver for PCM playback \n");
+ adec_appdata->start_done = 0;
+ adec_appdata->bReconfigureOutputPort = 0;
+ }
+ DEBUG_PRINT("******************************************\n");
+ DEBUG_PRINT("FTB after PORT RENABLE\n");
+ DEBUG_PRINT("******************************************\n");
+ for(i=0; i < adec_appdata->output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ adec_appdata->pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ adec_appdata->pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(adec_appdata->mp3_dec_handle, adec_appdata->pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+}
+
+void write_devctlcmd(int fd, const void *buf, int param){
+ int nbytes, nbytesWritten;
+ char cmdstr[128];
+ snprintf(cmdstr, 128, "%s%d\n", (char *)buf, param);
+ nbytes = strlen(cmdstr);
+ nbytesWritten = write(fd, cmdstr, nbytes);
+
+ if(nbytes != nbytesWritten)
+ printf("Failed to write string \"%s\" to omx_devmgr\n", cmdstr);
+}
+
+
diff --git a/mm-audio/aenc-aac/Android.mk b/mm-audio/aenc-aac/Android.mk
new file mode 100644
index 0000000..8698436
--- /dev/null
+++ b/mm-audio/aenc-aac/Android.mk
@@ -0,0 +1,26 @@
+ifeq ($(TARGET_ARCH),arm)
+
+
+AENC_AAC_PATH:= $(call my-dir)
+
+ifeq ($(call is-board-platform,msm8660),true)
+include $(AENC_AAC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8960),true)
+include $(AENC_AAC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8974),true)
+include $(AENC_AAC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8226),true)
+include $(AENC_AAC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8610),true)
+include $(AENC_AAC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,apq8084),true)
+include $(AENC_AAC_PATH)/qdsp6/Android.mk
+endif
+
+
+endif
diff --git a/mm-audio/aenc-aac/Makefile b/mm-audio/aenc-aac/Makefile
new file mode 100644
index 0000000..83d822b
--- /dev/null
+++ b/mm-audio/aenc-aac/Makefile
@@ -0,0 +1,6 @@
+all:
+ @echo "invoking omxaudio make"
+ $(MAKE) -C qdsp6
+
+install:
+ $(MAKE) -C qdsp6 install
diff --git a/mm-audio/aenc-aac/Makefile.am b/mm-audio/aenc-aac/Makefile.am
new file mode 100644
index 0000000..24c1af2
--- /dev/null
+++ b/mm-audio/aenc-aac/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = qdsp6
diff --git a/mm-audio/aenc-aac/qdsp6/Android.mk b/mm-audio/aenc-aac/qdsp6/Android.mk
new file mode 100644
index 0000000..e339f5d
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/Android.mk
@@ -0,0 +1,76 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxAacEnc-def := -g -O3
+libOmxAacEnc-def += -DQC_MODIFIED
+libOmxAacEnc-def += -D_ANDROID_
+libOmxAacEnc-def += -D_ENABLE_QC_MSG_LOG_
+libOmxAacEnc-def += -DVERBOSE
+libOmxAacEnc-def += -D_DEBUG
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+libOmxAacEnc-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the Shared library (libOmxAacEnc)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+libOmxAacEnc-inc := $(LOCAL_PATH)/inc
+libOmxAacEnc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+
+LOCAL_MODULE := libOmxAacEnc
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAacEnc-def)
+LOCAL_C_INCLUDES := $(libOmxAacEnc-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libutils liblog
+
+LOCAL_SRC_FILES := src/aenc_svr.c
+LOCAL_SRC_FILES += src/omx_aac_aenc.cpp
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+include $(BUILD_SHARED_LIBRARY)
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-aenc-omxaac-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+mm-aac-enc-test-inc := $(LOCAL_PATH)/inc
+mm-aac-enc-test-inc += $(LOCAL_PATH)/test
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+mm-aac-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+endif
+mm-aac-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+
+LOCAL_MODULE := mm-aenc-omxaac-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAacEnc-def)
+LOCAL_C_INCLUDES := $(mm-aac-enc-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libmm-omxcore
+LOCAL_SHARED_LIBRARIES += libOmxAacEnc
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+endif
+LOCAL_SRC_FILES := test/omx_aac_enc_test.c
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
+
diff --git a/mm-audio/aenc-aac/qdsp6/Makefile b/mm-audio/aenc-aac/qdsp6/Makefile
new file mode 100644
index 0000000..5421d45
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/Makefile
@@ -0,0 +1,81 @@
+# ---------------------------------------------------------------------------------
+# MM-AUDIO-OSS-8K-AENC-AAC
+# ---------------------------------------------------------------------------------
+
+# cross-compiler flags
+CFLAGS += -Wall
+CFLAGS += -Wundef
+CFLAGS += -Wstrict-prototypes
+CFLAGS += -Wno-trigraphs
+
+# cross-compile flags specific to shared objects
+CFLAGS_SO += -fpic
+
+# required pre-processor flags
+CPPFLAGS := -D__packed__=
+CPPFLAGS += -DIMAGE_APPS_PROC
+CPPFLAGS += -DFEATURE_Q_SINGLE_LINK
+CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR
+CPPFLAGS += -DFEATURE_LINUX
+CPPFLAGS += -DFEATURE_NATIVELINUX
+CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS
+
+CPPFLAGS += -g
+CPPFALGS += -D_DEBUG
+CPPFLAGS += -Iinc
+
+# linker flags
+LDFLAGS += -L$(SYSROOT)/usr/lib
+
+# linker flags for shared objects
+LDFLAGS_SO := -shared
+
+# defintions
+LIBMAJOR := $(basename $(basename $(LIBVER)))
+LIBINSTALLDIR := $(DESTDIR)usr/lib
+INCINSTALLDIR := $(DESTDIR)usr/include
+BININSTALLDIR := $(DESTDIR)usr/bin
+
+# ---------------------------------------------------------------------------------
+# BUILD
+# ---------------------------------------------------------------------------------
+all: libOmxAacEnc.so.$(LIBVER) mm-aenc-omxaac-test
+
+install:
+ echo "intalling aenc-aac in $(DESTDIR)"
+ if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi
+ if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi
+ if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi
+ install -m 555 libOmxAacEnc.so.$(LIBVER) $(LIBINSTALLDIR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxAacEnc.so.$(LIBVER) libOmxAacEnc.so.$(LIBMAJOR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxAacEnc.so.$(LIBMAJOR) libOmxAacEnc.so
+ install -m 555 mm-aenc-omxaac-test $(BININSTALLDIR)
+
+# ---------------------------------------------------------------------------------
+# COMPILE LIBRARY
+# ---------------------------------------------------------------------------------
+LDLIBS := -lpthread
+LDLIBS += -lstdc++
+LDLIBS += -lOmxCore
+
+SRCS := src/omx_aac_aenc.cpp
+SRCS += src/aenc_svr.c
+
+libOmxAacEnc.so.$(LIBVER): $(SRCS)
+ $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxAacEnc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# COMPILE TEST APP
+# ---------------------------------------------------------------------------------
+TEST_LDLIBS := -lpthread
+TEST_LDLIBS += -ldl
+TEST_LDLIBS += -lOmxCore
+
+TEST_SRCS := test/omx_aac_enc_test.c
+
+mm-aenc-omxaac-test: libOmxAacEnc.so.$(LIBVER) $(TEST_SRCS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/aenc-aac/qdsp6/Makefile.am b/mm-audio/aenc-aac/qdsp6/Makefile.am
new file mode 100644
index 0000000..5af028a
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/Makefile.am
@@ -0,0 +1,30 @@
+# sources and intermediate files are separated
+
+AM_CFLAGS = -Wall
+AM_CFLAGS += -Wundef
+AM_CFLAGS += -Wstrict-prototypes
+AM_CFLAGS += -Wno-trigraphs
+AM_CFLAGS += -g -O3
+
+AM_CPPFLAGS = -D__packed__=
+AM_CPPFLAGS += -DIMAGE_APPS_PROC
+AM_CPPFLAGS += -DFEATURE_Q_SINGLE_LINK
+AM_CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR
+AM_CPPFLAGS += -DFEATURE_LINUX
+AM_CPPFLAGS += -DFEATURE_NATIVELINUX
+AM_CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS
+AM_CPPFLAGS += -D_DEBUG
+AM_CPPFLAGS += -Iinc
+
+c_sources =src/omx_aac_aenc.cpp
+c_sources +=src/aenc_svr.c
+
+lib_LTLIBRARIES = libOmxAacEnc.la
+libOmxAacEnc_la_SOURCES = $(c_sources)
+libOmxAacEnc_la_CFLAGS = $(AM_CFLAGS) -fPIC
+libOmxAacEnc_la_LDLIBS = -lOmxCore -lstdc++ -lpthread
+libOmxAacEnc_la_LDFLAGS = -shared -version-info $(OMXAUDIO_LIBRARY_VERSION)
+
+bin_PROGRAMS = mm-aenc-omxaac-test
+mm_aenc_omxaac_test_SOURCES = test/omx_aac_enc_test.c
+mm_aenc_omxaac_test_LDADD = -lOmxCore -ldl -lpthread libOmxAacEnc.la
diff --git a/mm-audio/aenc-aac/qdsp6/inc/Map.h b/mm-audio/aenc-aac/qdsp6/inc/Map.h
new file mode 100644
index 0000000..aac96fd
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/inc/Map.h
@@ -0,0 +1,244 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdio.h>
+using namespace std;
+
+template <typename T,typename T2>
+class Map
+{
+ struct node
+ {
+ T data;
+ T2 data2;
+ node* prev;
+ node* next;
+ node(T t, T2 t2,node* p, node* n) :
+ data(t), data2(t2), prev(p), next(n) {}
+ };
+ node* head;
+ node* tail;
+ node* tmp;
+ unsigned size_of_list;
+ static Map<T,T2> *m_self;
+public:
+ Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {}
+ bool empty() const { return ( !head || !tail ); }
+ operator bool() const { return !empty(); }
+ void insert(T,T2);
+ void show();
+ int size();
+ T2 find(T); // Return VALUE
+ T find_ele(T);// Check if the KEY is present or not
+ T2 begin(); //give the first ele
+ bool erase(T);
+ bool eraseall();
+ bool isempty();
+ ~Map()
+ {
+ while(head)
+ {
+ node* temp(head);
+ head=head->next;
+ size_of_list--;
+ delete temp;
+ }
+ }
+};
+
+template <typename T,typename T2>
+T2 Map<T,T2>::find(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data2;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T Map<T,T2>::find_ele(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T2 Map<T,T2>::begin()
+{
+ tmp = head;
+ if(tmp)
+ {
+ return (tmp->data2);
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::show()
+{
+ tmp = head;
+ while(tmp)
+ {
+ printf("%d-->%d\n",tmp->data,tmp->data2);
+ tmp = tmp->next;
+ }
+}
+
+template <typename T,typename T2>
+int Map<T,T2>::size()
+{
+ int count =0;
+ tmp = head;
+ while(tmp)
+ {
+ tmp = tmp->next;
+ count++;
+ }
+ return count;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::insert(T data, T2 data2)
+{
+ tail = new node(data, data2,tail, NULL);
+ if( tail->prev )
+ tail->prev->next = tail;
+
+ if( empty() )
+ {
+ head = tail;
+ tmp=head;
+ }
+ tmp = head;
+ size_of_list++;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::erase(T d)
+{
+ bool found = false;
+ tmp = head;
+ node* prevnode = tmp;
+ node *tempnode;
+
+ while(tmp)
+ {
+ if((head == tail) && (head->data == d))
+ {
+ found = true;
+ tempnode = head;
+ head = tail = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp ==head) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ tmp = tmp->next;
+ tmp->prev = NULL;
+ head = tmp;
+ tempnode->next = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp == tail) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ prevnode->next = NULL;
+ tmp->prev = NULL;
+ tail = prevnode;
+ delete tempnode;
+ break;
+ }
+ if(tmp->data == d)
+ {
+ found = true;
+ prevnode->next = tmp->next;
+ tmp->next->prev = prevnode->next;
+ tempnode = tmp;
+ //tmp = tmp->next;
+ delete tempnode;
+ break;
+ }
+ prevnode = tmp;
+ tmp = tmp->next;
+ }
+ if(found)size_of_list--;
+ return found;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::eraseall()
+{
+ // Be careful while using this method
+ // it not only removes the node but FREES(not delete) the allocated
+ // memory.
+ node *tempnode;
+ tmp = head;
+ while(head)
+ {
+ tempnode = head;
+ head = head->next;
+ tempnode->next = NULL;
+ if(tempnode->data)
+ free(tempnode->data);
+ if(tempnode->data2)
+ free(tempnode->data2);
+ delete tempnode;
+ }
+ tail = head = NULL;
+ return true;
+}
+
+
+template <typename T,typename T2>
+bool Map<T,T2>::isempty()
+{
+ if(!size_of_list) return true;
+ else return false;
+}
+
+#endif // _MAP_H_
diff --git a/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h
new file mode 100644
index 0000000..72bfebe
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h
@@ -0,0 +1,120 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef AENC_SVR_H
+#define AENC_SVR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <pthread.h>
+#include <sched.h>
+#include <utils/Log.h>
+
+#ifdef _ANDROID_
+#define LOG_TAG "QC_AACENC"
+#endif
+
+#ifndef LOGE
+#define LOGE ALOGE
+#endif
+
+#ifndef LOGW
+#define LOGW ALOGW
+#endif
+
+#ifndef LOGD
+#define LOGD ALOGD
+#endif
+
+#ifndef LOGV
+#define LOGV ALOGV
+#endif
+
+#ifndef LOGI
+#define LOGI ALOGI
+#endif
+
+#define DEBUG_PRINT_ERROR LOGE
+#define DEBUG_PRINT LOGI
+#define DEBUG_DETAIL LOGV
+
+typedef void (*message_func)(void* client_data, unsigned char id);
+
+/**
+ @brief audio encoder ipc info structure
+
+ */
+struct aac_ipc_info
+{
+ pthread_t thr;
+ int pipe_in;
+ int pipe_out;
+ int dead;
+ message_func process_msg_cb;
+ void *client_data;
+ char thread_name[128];
+};
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to command server
+ */
+struct aac_ipc_info *omx_aac_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+
+struct aac_ipc_info *omx_aac_event_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+/**
+ @brief This function stop command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_aac_thread_stop(struct aac_ipc_info *aac_ipc);
+
+
+/**
+ @brief This function post message in the command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_aac_post_msg(struct aac_ipc_info *aac_ipc,
+ unsigned char id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AENC_SVR */
diff --git a/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h
new file mode 100644
index 0000000..276eaa3
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h
@@ -0,0 +1,624 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _AAC_ENC_H_
+#define _AAC_ENC_H_
+/*============================================================================
+ Audio Encoder
+
+@file omx_aac_aenc.h
+This module contains the class definition for openMAX encoder component.
+
+
+
+============================================================================*/
+
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see
+ * all DEBUG_PRINT or LOGV messaging */
+#include<stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#include "OMX_Core.h"
+#include "OMX_Audio.h"
+#include "aenc_svr.h"
+#include "qc_omx_component.h"
+#include "Map.h"
+#include <semaphore.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_aac.h>
+extern "C" {
+ void * get_omx_component_factory_fn(void);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Module specific globals
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+#define OMX_SPEC_VERSION 0x00000101
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (x >= y?x:y)
+
+//////////////////////////////////////////////////////////////////////////////
+// Macros
+//////////////////////////////////////////////////////////////////////////////
+//
+
+
+#define PrintFrameHdr(i,bufHdr) \
+ DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\
+ i,\
+ (unsigned) bufHdr, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\
+ ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags)
+
+
+// BitMask Management logic
+#define BITS_PER_BYTE 8
+#define BITMASK_SIZE(mIndex) \
+ (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE)
+#define BITMASK_OFFSET(mIndex)\
+ ((mIndex)/BITS_PER_BYTE)
+#define BITMASK_FLAG(mIndex) \
+ (1 << ((mIndex) % BITS_PER_BYTE))
+#define BITMASK_CLEAR(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex))
+#define BITMASK_SET(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex)
+#define BITMASK_PRESENT(mArray,mIndex)\
+ ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex))
+#define BITMASK_ABSENT(mArray,mIndex)\
+ (((mArray)[BITMASK_OFFSET(mIndex)] & \
+ BITMASK_FLAG(mIndex)) == 0x0)
+
+#define OMX_CORE_NUM_INPUT_BUFFERS 2
+#define OMX_CORE_NUM_OUTPUT_BUFFERS 16
+
+#define OMX_CORE_INPUT_BUFFER_SIZE 8192
+#define OMX_CORE_CONTROL_CMDQ_SIZE 100
+#define OMX_AENC_VOLUME_STEP 0x147
+#define OMX_AENC_MIN 0
+#define OMX_AENC_MAX 100
+#define NON_TUNNEL 1
+#define TUNNEL 0
+#define IP_PORT_BITMASK 0x02
+#define OP_PORT_BITMASK 0x01
+#define IP_OP_PORT_BITMASK 0x03
+
+#define DEFAULT_SF 44100
+#define DEFAULT_CH_CFG 2
+#define DEFAULT_BITRATE 64000
+#define OMX_AAC_DEFAULT_VOL 25
+// 14 bytes for input meta data
+#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14)
+
+#define TRUE 1
+#define FALSE 0
+
+
+#define NUMOFFRAMES 1
+#define MAXFRAMELENGTH 1536
+#define OMX_AAC_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT)+ MAXFRAMELENGTH + 1)\
+ + 1023) & (~1023))
+//Raw Header
+#define AUDAAC_MAX_MP4FF_HEADER_LENGTH 2
+
+#define AUDAAC_MP4FF_OBJ_TYPE 5
+#define AUDAAC_MP4FF_FREQ_IDX 4
+#define AUDAAC_MP4FF_CH_CONFIG 4
+
+//ADIF Header
+#define AUDAAC_MAX_ADIF_HEADER_LENGTH 17
+
+#define AAC_COPYRIGHT_PRESENT_SIZE 1
+#define AAC_ORIGINAL_COPY_SIZE 1
+#define AAC_HOME_SIZE 1
+#define AAC_BITSTREAM_TYPE_SIZE 1
+#define AAC_BITRATE_SIZE 23
+#define AAC_NUM_PFE_SIZE 4
+#define AAC_BUFFER_FULLNESS_SIZE 20
+#define AAC_ELEMENT_INSTANCE_TAG_SIZE 4
+#define AAC_NUM_FRONT_CHANNEL_ELEMENTS_SIZE 4
+#define AAC_NUM_SIDE_CHANNEL_ELEMENTS_SIZE 4
+#define AAC_NUM_BACK_CHANNEL_ELEMENTS_SIZE 4
+#define AAC_NUM_LFE_CHANNEL_ELEMENTS_SIZE 2
+#define AAC_NUM_ASSOC_DATA_ELEMENTS_SIZE 3
+#define AAC_NUM_VALID_CC_ELEMENTS_SIZE 4
+#define AAC_MONO_MIXDOWN_PRESENT_SIZE 1
+#define AAC_MONO_MIXDOWN_ELEMENT_SIZE 4
+#define AAC_STEREO_MIXDOWN_PRESENT_SIZE 1
+#define AAC_STEREO_MIXDOWN_ELEMENT_SIZE 4
+#define AAC_MATRIX_MIXDOWN_PRESENT_SIZE 1
+#define AAC_MATRIX_MIXDOWN_SIZE 3
+#define AAC_FCE_SIZE 5
+#define AAC_SCE_SIZE 5
+#define AAC_BCE_SIZE 5
+#define AAC_LFE_SIZE 4
+#define AAC_ADE_SIZE 4
+#define AAC_VCE_SIZE 5
+#define AAC_COMMENT_FIELD_BYTES_SIZE 8
+#define AAC_COMMENT_FIELD_DATA_SIZE 8
+#define AAC_SAMPLING_FREQ_INDEX_SIZE 4
+#define AAC_PROFILE_SIZE 2
+
+
+
+//Raw Header
+#define AUDAAC_MAX_RAW_HEADER_LENGTH 8
+
+#define AUDAAC_RAW_OBJ_TYPE 8
+#define AUDAAC_RAW_FREQ_IDX 8
+#define AUDAAC_RAW_CH_CONFIG 8
+#define AUDAAC_RAW_SBR_PRESENT 8
+#define AUDAAC_RAW_SBR_PS_PRESENT 8
+#define AUDAAC_RAW_EXT_OBJ_TYPE 8
+#define AUDAAC_RAW_EXT_FREQ_IDX 8
+#define AUDAAC_RAW_EXT_CH_CONFIG 8
+
+struct sample_rate_idx {
+ OMX_U32 sample_rate;
+ OMX_U32 sample_rate_idx;
+};
+static struct sample_rate_idx sample_idx_tbl[10] = {
+ {8000, 0x0b},
+ {11025, 0x0a},
+ {12000, 0x09},
+ {16000, 0x08},
+ {22050, 0x07},
+ {24000, 0x06},
+ {32000, 0x05},
+ {44100, 0x04},
+ {48000, 0x03},
+ {64000, 0x02},
+};
+class omx_aac_aenc;
+
+// OMX AAC audio encoder class
+class omx_aac_aenc: public qc_omx_component
+{
+public:
+ omx_aac_aenc(); // constructor
+ virtual ~omx_aac_aenc(); // destructor
+
+ OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+
+ OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp);
+
+ OMX_ERRORTYPE component_init(OMX_STRING role);
+
+ OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp,
+ OMX_U8 *role,
+ OMX_U32 index);
+
+ OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_HANDLETYPE peerComponent,
+ OMX_U32 peerPort,
+ OMX_TUNNELSETUPTYPE *tunnelSetup);
+
+ OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp,
+ OMX_STRING componentName,
+ OMX_VERSIONTYPE *componentVersion,
+ OMX_VERSIONTYPE * specVersion,
+ OMX_UUIDTYPE *componentUUID);
+
+ OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp,
+ OMX_STRING paramName,
+ OMX_INDEXTYPE *indexType);
+
+ OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp,
+ OMX_STATETYPE *state);
+
+ static void process_in_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_out_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_command_msg(void *client_data,
+ unsigned char id);
+
+ static void process_event_cb(void *client_data,
+ unsigned char id);
+
+
+ OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp,
+ OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData);
+
+ OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes,
+ OMX_U8 *buffer);
+
+ OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ void * eglImage);
+
+ bool post_command(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ // Deferred callback identifiers
+ enum
+ {
+ //Event Callbacks from the component thread context
+ OMX_COMPONENT_GENERATE_EVENT = 0x1,
+ //Buffer Done callbacks from component thread context
+ OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2,
+ OMX_COMPONENT_GENERATE_ETB = 0x3,
+ //Command
+ OMX_COMPONENT_GENERATE_COMMAND = 0x4,
+ OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05,
+ OMX_COMPONENT_GENERATE_FTB = 0x06,
+ OMX_COMPONENT_GENERATE_EOS = 0x07,
+ OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08,
+ OMX_COMPONENT_SUSPEND = 0x09,
+ OMX_COMPONENT_RESUME = 0x0a
+ };
+private:
+
+ ///////////////////////////////////////////////////////////
+ // Type definitions
+ ///////////////////////////////////////////////////////////
+ // Bit Positions
+ enum flags_bit_positions
+ {
+ // Defer transition to IDLE
+ OMX_COMPONENT_IDLE_PENDING =0x1,
+ // Defer transition to LOADING
+ OMX_COMPONENT_LOADING_PENDING =0x2,
+
+ OMX_COMPONENT_MUTED =0x3,
+
+ // Defer transition to Enable
+ OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4,
+ // Defer transition to Enable
+ OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5,
+ // Defer transition to Disable
+ OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6,
+ // Defer transition to Disable
+ OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7
+ };
+
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ input_buffer_map;
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ output_buffer_map;
+
+ enum port_indexes
+ {
+ OMX_CORE_INPUT_PORT_INDEX =0,
+ OMX_CORE_OUTPUT_PORT_INDEX =1
+ };
+
+ struct omx_event
+ {
+ unsigned param1;
+ unsigned param2;
+ unsigned id;
+ };
+
+ struct omx_cmd_queue
+ {
+ omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE];
+ unsigned m_read;
+ unsigned m_write;
+ unsigned m_size;
+
+ omx_cmd_queue();
+ ~omx_cmd_queue();
+ bool insert_entry(unsigned p1, unsigned p2, unsigned id);
+ bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id);
+ bool get_msg_id(unsigned *id);
+ bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id);
+ };
+
+ typedef struct TIMESTAMP
+ {
+ unsigned long LowPart;
+ unsigned long HighPart;
+ }__attribute__((packed)) TIMESTAMP;
+
+ typedef struct metadata_input
+ {
+ unsigned short offsetVal;
+ TIMESTAMP nTimeStamp;
+ unsigned int nFlags;
+ }__attribute__((packed)) META_IN;
+
+ typedef struct enc_meta_out
+ {
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+ } __attribute__ ((packed))ENC_META_OUT;
+
+ typedef struct
+ {
+ OMX_U32 tot_in_buf_len;
+ OMX_U32 tot_out_buf_len;
+ OMX_U32 tot_pb_time;
+ OMX_U32 fbd_cnt;
+ OMX_U32 ftb_cnt;
+ OMX_U32 etb_cnt;
+ OMX_U32 ebd_cnt;
+ }AAC_PB_STATS;
+
+ ///////////////////////////////////////////////////////////
+ // Member variables
+ ///////////////////////////////////////////////////////////
+ OMX_U8 *m_tmp_meta_buf;
+ OMX_U8 *m_tmp_out_meta_buf;
+ OMX_U8 m_flush_cnt ;
+ OMX_U8 m_comp_deinit;
+
+ // the below var doesnt hold good if combo of use and alloc bufs are used
+ OMX_U8 m_eos_bm;
+ OMX_S32 m_volume;//Unit to be determined
+ OMX_U8 audaac_header_adif[AUDAAC_MAX_ADIF_HEADER_LENGTH];
+ OMX_U8 audaac_header_mp4ff[AUDAAC_MAX_MP4FF_HEADER_LENGTH];
+ OMX_U16 audaac_hdr_bit_index;
+ OMX_S32 sample_idx;
+ OMX_S32 adif_flag;
+ OMX_S32 mp4ff_flag;
+ OMX_PTR m_app_data;// Application data
+ int nNumInputBuf;
+ int nNumOutputBuf;
+ int m_drv_fd; // Kernel device node file handle
+ bool bFlushinprogress;
+ bool is_in_th_sleep;
+ bool is_out_th_sleep;
+ unsigned int m_flags; //encapsulate the waiting states.
+ OMX_U64 nTimestamp;
+ OMX_U64 ts;
+ unsigned int frameduration;
+ unsigned int pcm_input; //tunnel or non-tunnel
+ unsigned int m_inp_act_buf_count; // Num of Input Buffers
+ unsigned int m_out_act_buf_count; // Numb of Output Buffers
+ unsigned int m_inp_current_buf_count; // Num of Input Buffers
+ unsigned int m_out_current_buf_count; // Numb of Output Buffers
+ unsigned int output_buffer_size;
+ unsigned int input_buffer_size;
+ unsigned short m_session_id;
+ // store I/P PORT state
+ OMX_BOOL m_inp_bEnabled;
+ // store O/P PORT state
+ OMX_BOOL m_out_bEnabled;
+ //Input port Populated
+ OMX_BOOL m_inp_bPopulated;
+ //Output port Populated
+ OMX_BOOL m_out_bPopulated;
+ sem_t sem_States;
+ sem_t sem_read_msg;
+ sem_t sem_write_msg;
+
+ volatile int m_is_event_done;
+ volatile int m_is_in_th_sleep;
+ volatile int m_is_out_th_sleep;
+ input_buffer_map m_input_buf_hdrs;
+ output_buffer_map m_output_buf_hdrs;
+ omx_cmd_queue m_input_q;
+ omx_cmd_queue m_input_ctrl_cmd_q;
+ omx_cmd_queue m_input_ctrl_ebd_q;
+ omx_cmd_queue m_command_q;
+ omx_cmd_queue m_output_q;
+ omx_cmd_queue m_output_ctrl_cmd_q;
+ omx_cmd_queue m_output_ctrl_fbd_q;
+ pthread_mutexattr_t m_outputlock_attr;
+ pthread_mutexattr_t m_commandlock_attr;
+ pthread_mutexattr_t m_lock_attr;
+ pthread_mutexattr_t m_state_attr;
+ pthread_mutexattr_t m_flush_attr;
+ pthread_mutexattr_t m_in_th_attr_1;
+ pthread_mutexattr_t m_out_th_attr_1;
+ pthread_mutexattr_t m_event_attr;
+ pthread_mutexattr_t m_in_th_attr;
+ pthread_mutexattr_t m_out_th_attr;
+ pthread_mutexattr_t out_buf_count_lock_attr;
+ pthread_mutexattr_t in_buf_count_lock_attr;
+ pthread_cond_t cond;
+ pthread_cond_t in_cond;
+ pthread_cond_t out_cond;
+ pthread_mutex_t m_lock;
+ pthread_mutex_t m_commandlock;
+ pthread_mutex_t m_outputlock;
+ // Mutexes for state change
+ pthread_mutex_t m_state_lock;
+ // Mutexes for flush acks from input and output threads
+ pthread_mutex_t m_flush_lock;
+ pthread_mutex_t m_event_lock;
+ pthread_mutex_t m_in_th_lock;
+ pthread_mutex_t m_out_th_lock;
+ pthread_mutex_t m_in_th_lock_1;
+ pthread_mutex_t m_out_th_lock_1;
+ pthread_mutex_t out_buf_count_lock;
+ pthread_mutex_t in_buf_count_lock;
+
+ OMX_STATETYPE m_state; // OMX State
+ OMX_STATETYPE nState;
+ OMX_CALLBACKTYPE m_cb; // Application callbacks
+ AAC_PB_STATS m_aac_pb_stats;
+ struct aac_ipc_info *m_ipc_to_in_th; // for input thread
+ struct aac_ipc_info *m_ipc_to_out_th; // for output thread
+ struct aac_ipc_info *m_ipc_to_cmd_th; // for command thread
+ OMX_PRIORITYMGMTTYPE m_priority_mgm ;
+ OMX_AUDIO_PARAM_AACPROFILETYPE m_aac_param; // Cache AAC encoder parameter
+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter
+ OMX_PARAM_COMPONENTROLETYPE component_Role;
+ OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier;
+
+ ///////////////////////////////////////////////////////////
+ // Private methods
+ ///////////////////////////////////////////////////////////
+ OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ bool allocate_done(void);
+
+ bool release_done(OMX_U32 param1);
+
+ bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true);
+
+ bool execute_input_omx_flush(void);
+
+ bool execute_output_omx_flush(void);
+
+ bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool post_input(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ bool post_output(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ void process_events(omx_aac_aenc *client_data);
+
+ void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void wait_for_event();
+
+ void event_complete();
+
+ void in_th_goto_sleep();
+
+ void in_th_wakeup();
+
+ void out_th_goto_sleep();
+
+ void out_th_wakeup();
+
+ void flush_ack();
+ void deinit_encoder();
+ void audaac_rec_install_adif_header_variable (OMX_U16 byte_num,
+ OMX_U32 sample_index, OMX_U8 channel_config);
+ void audaac_rec_install_mp4ff_header_variable (OMX_U16 byte_num,
+ OMX_U32 sample_index,OMX_U8 channel_config);
+ void audaac_rec_install_bits(OMX_U8 *input,
+ OMX_U8 num_bits_reqd,
+ OMX_U32 value,
+ OMX_U16 *hdr_bit_index);
+
+};
+#endif
diff --git a/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c b/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c
new file mode 100644
index 0000000..a7c2a42
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c
@@ -0,0 +1,206 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <aenc_svr.h>
+
+/**
+ @brief This function processes posted messages
+
+ Once thread is being spawned, this function is run to
+ start processing commands posted by client
+
+ @param info pointer to context
+
+ */
+void *omx_aac_msg(void *info)
+{
+ struct aac_ipc_info *aac_info = (struct aac_ipc_info*)info;
+ unsigned char id;
+ int n;
+
+ DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__);
+ while (!aac_info->dead)
+ {
+ n = read(aac_info->pipe_in, &id, 1);
+ if (0 == n) break;
+ if (1 == n)
+ {
+ DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n",
+ aac_info->thread_name,
+ aac_info->pipe_in,
+ aac_info->pipe_out);
+
+ aac_info->process_msg_cb(aac_info->client_data, id);
+ }
+ if ((n < 0) && (errno != EINTR)) break;
+ }
+ DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__);
+
+ return 0;
+}
+
+void *omx_aac_events(void *info)
+{
+ struct aac_ipc_info *aac_info = (struct aac_ipc_info*)info;
+ unsigned char id = 0;
+
+ DEBUG_DETAIL("%s: message thread start\n", aac_info->thread_name);
+ aac_info->process_msg_cb(aac_info->client_data, id);
+ DEBUG_DETAIL("%s: message thread stop\n", aac_info->thread_name);
+ return 0;
+}
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to msging thread
+ */
+struct aac_ipc_info *omx_aac_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct aac_ipc_info *aac_info;
+
+ aac_info = calloc(1, sizeof(struct aac_ipc_info));
+ if (!aac_info)
+ {
+ return 0;
+ }
+
+ aac_info->client_data = client_data;
+ aac_info->process_msg_cb = cb;
+ strlcpy(aac_info->thread_name, th_name, sizeof(aac_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ aac_info->pipe_in = fds[0];
+ aac_info->pipe_out = fds[1];
+
+ r = pthread_create(&aac_info->thr, 0, omx_aac_msg, aac_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", aac_info->thread_name);
+ return aac_info;
+
+
+fail_thread:
+ close(aac_info->pipe_in);
+ close(aac_info->pipe_out);
+
+fail_pipe:
+ free(aac_info);
+
+ return 0;
+}
+
+/**
+ * @brief This function starts command server
+ *
+ * @param cb pointer to callback function from the client
+ * @param client_data reference client wants to get back
+ * through callback
+ * @return handle to msging thread
+ * */
+struct aac_ipc_info *omx_aac_event_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct aac_ipc_info *aac_info;
+
+ aac_info = calloc(1, sizeof(struct aac_ipc_info));
+ if (!aac_info)
+ {
+ return 0;
+ }
+
+ aac_info->client_data = client_data;
+ aac_info->process_msg_cb = cb;
+ strlcpy(aac_info->thread_name, th_name, sizeof(aac_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ aac_info->pipe_in = fds[0];
+ aac_info->pipe_out = fds[1];
+
+ r = pthread_create(&aac_info->thr, 0, omx_aac_events, aac_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", aac_info->thread_name);
+ return aac_info;
+
+
+fail_thread:
+ close(aac_info->pipe_in);
+ close(aac_info->pipe_out);
+
+fail_pipe:
+ free(aac_info);
+
+ return 0;
+}
+
+void omx_aac_thread_stop(struct aac_ipc_info *aac_info) {
+ DEBUG_DETAIL("%s stop server\n", __FUNCTION__);
+ close(aac_info->pipe_in);
+ close(aac_info->pipe_out);
+ pthread_join(aac_info->thr,NULL);
+ aac_info->pipe_out = -1;
+ aac_info->pipe_in = -1;
+ DEBUG_DETAIL("%s: message thread close fds%d %d\n", aac_info->thread_name,
+ aac_info->pipe_in,aac_info->pipe_out);
+ free(aac_info);
+}
+
+void omx_aac_post_msg(struct aac_ipc_info *aac_info, unsigned char id) {
+ DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id);
+
+ write(aac_info->pipe_out, &id, 1);
+}
diff --git a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
new file mode 100644
index 0000000..52aa915
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
@@ -0,0 +1,5016 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+/*============================================================================
+@file omx_aenc_aac.c
+ This module contains the implementation of the OpenMAX core & component.
+
+*//*========================================================================*/
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+
+#include<string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "omx_aac_aenc.h"
+#include <errno.h>
+
+using namespace std;
+
+#define SLEEP_MS 100
+
+// omx_cmd_queue destructor
+omx_aac_aenc::omx_cmd_queue::~omx_cmd_queue()
+{
+ // Nothing to do
+}
+
+// omx cmd queue constructor
+omx_aac_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0)
+{
+ memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE);
+}
+
+// omx cmd queue insert
+bool omx_aac_aenc::omx_cmd_queue::insert_entry(unsigned p1,
+ unsigned p2,
+ unsigned id)
+{
+ bool ret = true;
+ if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_q[m_write].id = id;
+ m_q[m_write].param1 = p1;
+ m_q[m_write].param2 = p2;
+ m_write++;
+ m_size ++;
+ if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_write = 0;
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full");
+ }
+ return ret;
+}
+
+bool omx_aac_aenc::omx_cmd_queue::pop_entry(unsigned *p1,
+ unsigned *p2, unsigned *id)
+{
+ bool ret = true;
+ if (m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ *p1 = m_q[m_read].param1;
+ *p2 = m_q[m_read].param2;
+ // Move the read pointer ahead
+ ++m_read;
+ --m_size;
+ if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_read = 0;
+
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty");
+ }
+ return ret;
+}
+
+// factory function executed by the core to create instances
+void *get_omx_component_factory_fn(void)
+{
+ return(new omx_aac_aenc);
+}
+bool omx_aac_aenc::omx_cmd_queue::get_msg_id(unsigned *id)
+{
+ if(m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ DEBUG_PRINT("get_msg_id=%d\n",*id);
+ }
+ else{
+ return false;
+ }
+ return true;
+}
+/*=============================================================================
+FUNCTION:
+ wait_for_event
+
+DESCRIPTION:
+ waits for a particular event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_aac_aenc::wait_for_event()
+{
+ int rc;
+ struct timespec ts;
+ pthread_mutex_lock(&m_event_lock);
+ while (0 == m_is_event_done)
+ {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += (SLEEP_MS/1000);
+ ts.tv_nsec += ((SLEEP_MS%1000) * 1000000);
+ rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts);
+ if (rc == ETIMEDOUT && !m_is_event_done) {
+ DEBUG_PRINT("Timed out waiting for flush");
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ }
+ }
+ m_is_event_done = 0;
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+/*=============================================================================
+FUNCTION:
+ event_complete
+
+DESCRIPTION:
+ informs about the occurance of an event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_aac_aenc::event_complete()
+{
+ pthread_mutex_lock(&m_event_lock);
+ if (0 == m_is_event_done)
+ {
+ m_is_event_done = 1;
+ pthread_cond_signal(&cond);
+ }
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+// All this non-sense because of a single aac object
+void omx_aac_aenc::in_th_goto_sleep()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ while (0 == m_is_in_th_sleep)
+ {
+ pthread_cond_wait(&in_cond, &m_in_th_lock);
+ }
+ m_is_in_th_sleep = 0;
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_aac_aenc::in_th_wakeup()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ if (0 == m_is_in_th_sleep)
+ {
+ m_is_in_th_sleep = 1;
+ pthread_cond_signal(&in_cond);
+ }
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_aac_aenc::out_th_goto_sleep()
+{
+
+ pthread_mutex_lock(&m_out_th_lock);
+ while (0 == m_is_out_th_sleep)
+ {
+ pthread_cond_wait(&out_cond, &m_out_th_lock);
+ }
+ m_is_out_th_sleep = 0;
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+
+void omx_aac_aenc::out_th_wakeup()
+{
+ pthread_mutex_lock(&m_out_th_lock);
+ if (0 == m_is_out_th_sleep)
+ {
+ m_is_out_th_sleep = 1;
+ pthread_cond_signal(&out_cond);
+ }
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::omx_aac_aenc
+
+DESCRIPTION
+ Constructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_aac_aenc::omx_aac_aenc(): m_tmp_meta_buf(NULL),
+ m_tmp_out_meta_buf(NULL),
+ m_flush_cnt(255),
+ m_comp_deinit(0),
+ adif_flag(0),
+ mp4ff_flag(0),
+ m_app_data(NULL),
+ m_drv_fd(-1),
+ bFlushinprogress(0),
+ is_in_th_sleep(false),
+ is_out_th_sleep(false),
+ m_flags(0),
+ nTimestamp(0),
+ ts(0),
+ frameduration(0),
+ m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS),
+ m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS),
+ m_inp_current_buf_count(0),
+ m_out_current_buf_count(0),
+ output_buffer_size(OMX_AAC_OUTPUT_BUFFER_SIZE),
+ input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE),
+ m_inp_bEnabled(OMX_TRUE),
+ m_out_bEnabled(OMX_TRUE),
+ m_inp_bPopulated(OMX_FALSE),
+ m_out_bPopulated(OMX_FALSE),
+ m_is_event_done(0),
+ m_state(OMX_StateInvalid),
+ m_ipc_to_in_th(NULL),
+ m_ipc_to_out_th(NULL),
+ m_ipc_to_cmd_th(NULL),
+ nNumOutputBuf(0),
+ m_session_id(0)
+{
+ int cond_ret = 0;
+ component_Role.nSize = 0;
+ memset(&m_cmp, 0, sizeof(m_cmp));
+ memset(&m_cb, 0, sizeof(m_cb));
+ memset(&m_aac_pb_stats, 0, sizeof(m_aac_pb_stats));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ memset(&m_aac_param, 0, sizeof(m_aac_param));
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+
+ pthread_mutexattr_init(&m_lock_attr);
+ pthread_mutex_init(&m_lock, &m_lock_attr);
+ pthread_mutexattr_init(&m_commandlock_attr);
+ pthread_mutex_init(&m_commandlock, &m_commandlock_attr);
+
+ pthread_mutexattr_init(&m_outputlock_attr);
+ pthread_mutex_init(&m_outputlock, &m_outputlock_attr);
+
+ pthread_mutexattr_init(&m_state_attr);
+ pthread_mutex_init(&m_state_lock, &m_state_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_flush_attr);
+ pthread_mutex_init(&m_flush_lock, &m_flush_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr);
+ pthread_mutex_init(&m_in_th_lock, &m_in_th_attr);
+
+ pthread_mutexattr_init(&m_out_th_attr);
+ pthread_mutex_init(&m_out_th_lock, &m_out_th_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr_1);
+ pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1);
+
+ pthread_mutexattr_init(&m_out_th_attr_1);
+ pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1);
+
+ pthread_mutexattr_init(&out_buf_count_lock_attr);
+ pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr);
+
+ pthread_mutexattr_init(&in_buf_count_lock_attr);
+ pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr);
+ if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to \
+ initialise condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to \
+ initialise condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to \
+ initialise condition variable\n");
+ }
+
+ sem_init(&sem_read_msg,0, 0);
+ sem_init(&sem_write_msg,0, 0);
+ sem_init(&sem_States,0, 0);
+ return;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::~omx_aac_aenc
+
+DESCRIPTION
+ Destructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_aac_aenc::~omx_aac_aenc()
+{
+ DEBUG_PRINT_ERROR("AAC Object getting destroyed comp-deinit=%d\n",
+ m_comp_deinit);
+ if ( !m_comp_deinit )
+ {
+ deinit_encoder();
+ }
+ pthread_mutexattr_destroy(&m_lock_attr);
+ pthread_mutex_destroy(&m_lock);
+
+ pthread_mutexattr_destroy(&m_commandlock_attr);
+ pthread_mutex_destroy(&m_commandlock);
+
+ pthread_mutexattr_destroy(&m_outputlock_attr);
+ pthread_mutex_destroy(&m_outputlock);
+
+ pthread_mutexattr_destroy(&m_state_attr);
+ pthread_mutex_destroy(&m_state_lock);
+
+ pthread_mutexattr_destroy(&m_event_attr);
+ pthread_mutex_destroy(&m_event_lock);
+
+ pthread_mutexattr_destroy(&m_flush_attr);
+ pthread_mutex_destroy(&m_flush_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr);
+ pthread_mutex_destroy(&m_in_th_lock);
+
+ pthread_mutexattr_destroy(&m_out_th_attr);
+ pthread_mutex_destroy(&m_out_th_lock);
+
+ pthread_mutexattr_destroy(&out_buf_count_lock_attr);
+ pthread_mutex_destroy(&out_buf_count_lock);
+
+ pthread_mutexattr_destroy(&in_buf_count_lock_attr);
+ pthread_mutex_destroy(&in_buf_count_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr_1);
+ pthread_mutex_destroy(&m_in_th_lock_1);
+
+ pthread_mutexattr_destroy(&m_out_th_attr_1);
+ pthread_mutex_destroy(&m_out_th_lock_1);
+ pthread_mutex_destroy(&out_buf_count_lock);
+ pthread_mutex_destroy(&in_buf_count_lock);
+ pthread_cond_destroy(&cond);
+ pthread_cond_destroy(&in_cond);
+ pthread_cond_destroy(&out_cond);
+ sem_destroy (&sem_read_msg);
+ sem_destroy (&sem_write_msg);
+ sem_destroy (&sem_States);
+ DEBUG_PRINT_ERROR("OMX AAC component destroyed\n");
+ return;
+}
+
+/**
+ @brief memory function for sending EmptyBufferDone event
+ back to IL client
+
+ @param bufHdr OMX buffer header to be passed back to IL client
+ @return none
+ */
+void omx_aac_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.EmptyBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr);
+ bufHdr->nFilledLen = 0;
+
+ m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr);
+ pthread_mutex_lock(&in_buf_count_lock);
+ m_aac_pb_stats.ebd_cnt++;
+ nNumInputBuf--;
+ DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\
+ m_aac_pb_stats.tot_in_buf_len,
+ nNumInputBuf, m_aac_pb_stats.ebd_cnt);
+ pthread_mutex_unlock(&in_buf_count_lock);
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ flush_ack
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_aac_aenc::flush_ack()
+{
+ // Decrement the FLUSH ACK count and notify the waiting recepients
+ pthread_mutex_lock(&m_flush_lock);
+ --m_flush_cnt;
+ if (0 == m_flush_cnt)
+ {
+ event_complete();
+ }
+ DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt);
+ pthread_mutex_unlock(&m_flush_lock);
+}
+void omx_aac_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.FillBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr);
+ m_aac_pb_stats.fbd_cnt++;
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf--;
+ DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\
+ nNumOutputBuf,
+ m_aac_pb_stats.tot_out_buf_len,
+ m_aac_pb_stats.fbd_cnt);
+ m_aac_pb_stats.tot_out_buf_len += bufHdr->nFilledLen;
+ m_aac_pb_stats.tot_pb_time = bufHdr->nTimeStamp;
+ DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n",
+ m_aac_pb_stats.tot_in_buf_len,
+ m_aac_pb_stats.tot_out_buf_len);
+ pthread_mutex_unlock(&out_buf_count_lock);
+ m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_out_port_msg
+
+DESCRIPTION:
+ Function for handling all commands from IL client
+IL client commands are processed and callbacks are generated through
+this routine Audio Command Server provides the thread context for this routine
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_aac_aenc::process_out_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0; // qsize
+ unsigned tot_qsize = 0;
+ omx_aac_aenc *pThis = (omx_aac_aenc *) client_data;
+ OMX_STATETYPE state;
+
+loopback_out:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n");
+ return;
+ }
+ pthread_mutex_lock(&pThis->m_outputlock);
+
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize);
+ return;
+ }
+ if ( (state != OMX_StateExecuting) && !qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+
+ if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) )
+ {
+ // case where no port reconfig and nothing in the flush q
+ DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\
+ qsize,tot_qsize);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress))
+ {
+ DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+ }
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size,state);
+
+
+ if (qsize)
+ {
+ // process FLUSH message
+ pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // if no FLUSH and FBD's then process FTB's
+ pThis->m_output_q.pop_entry(&p1,&p2,&ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pThis->out_th_goto_sleep();
+ goto loopback_out;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_outputlock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ ident = 0;
+ DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id )
+ {
+ pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_FTB == id )
+ {
+ pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_EOS == id )
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+
+ }
+ else if(id == OMX_COMPONENT_RESUME)
+ {
+ DEBUG_PRINT("RESUMED...\n");
+ }
+ else if(id == OMX_COMPONENT_GENERATE_COMMAND)
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL("Executing FLUSH command on Output port\n");
+ pThis->execute_output_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n");
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_command_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_aac_aenc::process_command_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ omx_aac_aenc *pThis = (omx_aac_aenc*)client_data;
+ pthread_mutex_lock(&pThis->m_commandlock);
+
+ qsize = pThis->m_command_q.m_size;
+ DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size,
+ pThis->m_state);
+
+ if (!qsize)
+ {
+ DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n");
+ pthread_mutex_unlock(&pThis->m_commandlock);
+ return;
+ } else
+ {
+ pThis->m_command_q.pop_entry(&p1,&p2,&ident);
+ }
+ pthread_mutex_unlock(&pThis->m_commandlock);
+
+ id = ident;
+ DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\
+ pThis->m_state,ident, \
+ pThis->m_command_q.m_size);
+
+ if (OMX_COMPONENT_GENERATE_EVENT == id)
+ {
+ if (pThis->m_cb.EventHandler)
+ {
+ if (OMX_CommandStateSet == p1)
+ {
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->m_state = (OMX_STATETYPE) p2;
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_PRINT("CMD:Process->state set to %d \n", \
+ pThis->m_state);
+
+ if (pThis->m_state == OMX_StateExecuting ||
+ pThis->m_state == OMX_StateLoaded)
+ {
+
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ if (pThis->is_in_th_sleep)
+ {
+ pThis->is_in_th_sleep = false;
+ DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n");
+ pThis->in_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ if (pThis->is_out_th_sleep)
+ {
+ DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n");
+ pThis->is_out_th_sleep = false;
+ pThis->out_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ }
+ }
+ if (OMX_StateInvalid == pThis->m_state)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ } else if ((signed)p2 == OMX_ErrorPortUnpopulated)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ p2,
+ NULL,
+ NULL );
+ } else
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventCmdComplete,
+ p1, p2, NULL );
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n");
+ }
+ } else if (OMX_COMPONENT_GENERATE_COMMAND == id)
+ {
+ pThis->send_command_proxy(&pThis->m_cmp,
+ (OMX_COMMANDTYPE)p1,
+ (OMX_U32)p2,(OMX_PTR)NULL);
+ } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id)
+ {
+ DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED");
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventPortSettingsChanged,
+ 1, 1, NULL );
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_in_port_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_aac_aenc::process_in_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ unsigned tot_qsize = 0;
+ omx_aac_aenc *pThis = (omx_aac_aenc *) client_data;
+ OMX_STATETYPE state;
+
+ if (!pThis)
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n");
+ return;
+ }
+loopback_in:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n");
+ return;
+ }
+ // Protect the shared queue data structure
+ pthread_mutex_lock(&pThis->m_lock);
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP");
+ pthread_mutex_unlock(&pThis->m_lock);
+ return;
+ }
+
+ if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_DETAIL("SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ else if ((state == OMX_StatePause))
+ {
+ if(!(pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ DEBUG_DETAIL("IN: SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ }
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size, state);
+
+
+ if ( qsize )
+ {
+ // process FLUSH message
+ pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) &&
+ (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident);
+ } else if ((qsize = pThis->m_input_q.m_size) &&
+ (state == OMX_StateExecuting))
+ {
+ // if no FLUSH and EBD's then process ETB's
+ pThis->m_input_q.pop_entry(&p1, &p2, &ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\
+ state,pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_lock);
+ pThis->in_th_goto_sleep();
+ goto loopback_in;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+ if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id )
+ {
+ pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ }
+ else if(id == OMX_COMPONENT_GENERATE_EOS)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
+ OMX_EventBufferFlag, 0, 1, NULL );
+ } else if ( OMX_COMPONENT_GENERATE_ETB == id )
+ {
+ pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_COMMAND == id )
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL(" Executing FLUSH command on Input port\n");
+ pThis->execute_input_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n");
+ }
+ return;
+}
+
+/**
+ @brief member function for performing component initialization
+
+ @param role C string mandating role of this component
+ @return Error status
+ */
+OMX_ERRORTYPE omx_aac_aenc::component_init(OMX_STRING role)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ m_state = OMX_StateLoaded;
+
+ /* DSP does not give information about the bitstream
+ randomly assign the value right now. Query will result in
+ incorrect param */
+ memset(&m_aac_param, 0, sizeof(m_aac_param));
+ m_aac_param.nSize = sizeof(m_aac_param);
+ m_aac_param.nChannels = DEFAULT_CH_CFG;
+ m_aac_param.nSampleRate = DEFAULT_SF;
+ m_aac_param.nBitRate = DEFAULT_BITRATE;
+ m_volume = OMX_AAC_DEFAULT_VOL; /* Close to unity gain */
+ memset(&m_aac_pb_stats,0,sizeof(AAC_PB_STATS));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ m_pcm_param.nSize = sizeof(m_pcm_param);
+ m_pcm_param.nChannels = DEFAULT_CH_CFG;
+ m_pcm_param.nSamplingRate = DEFAULT_SF;
+
+ nTimestamp = 0;
+ ts = 0;
+ frameduration = 0;
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ m_ipc_to_in_th = NULL; // Command server instance
+ m_ipc_to_out_th = NULL; // Client server instance
+ m_ipc_to_cmd_th = NULL; // command instance
+ m_is_out_th_sleep = 0;
+ m_is_in_th_sleep = 0;
+ is_out_th_sleep= false;
+
+ is_in_th_sleep=false;
+ adif_flag = 0;
+ mp4ff_flag = 0;
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+ m_priority_mgm.nGroupID =0;
+ m_priority_mgm.nGroupPriority=0;
+
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified;
+
+ DEBUG_PRINT_ERROR(" component init: role = %s\n",role);
+
+ DEBUG_PRINT(" component init: role = %s\n",role);
+ component_Role.nVersion.nVersion = OMX_SPEC_VERSION;
+ if (!strcmp(role,"OMX.qcom.audio.encoder.aac"))
+ {
+ pcm_input = 1;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole, (const char*)role,
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.aac"))
+ {
+ pcm_input = 0;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole, (const char*)role,
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else
+ {
+ component_Role.nSize = sizeof("\0");
+ strlcpy((char *)component_Role.cRole, (const char*)"\0",
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT_ERROR("\ncomponent_init: Component %s LOADED is invalid\n",
+ role);
+ return OMX_ErrorInsufficientResources;
+ }
+ if(pcm_input)
+ {
+ m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) *
+ (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN)));
+
+ if (m_tmp_meta_buf == NULL) {
+ DEBUG_PRINT_ERROR("Mem alloc failed for in meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ m_tmp_out_meta_buf =
+ (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_AAC_OUTPUT_BUFFER_SIZE);
+ if ( m_tmp_out_meta_buf == NULL ) {
+ DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+
+ if(0 == pcm_input)
+ {
+ m_drv_fd = open("/dev/msm_aac_in",O_RDONLY);
+ }
+ else
+ {
+ m_drv_fd = open("/dev/msm_aac_in",O_RDWR);
+ }
+ if (m_drv_fd < 0)
+ {
+ DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\
+ m_drv_fd,errno);
+
+ return OMX_ErrorInsufficientResources;
+ }
+ if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1)
+ {
+ DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n");
+ }
+ if(pcm_input)
+ {
+ if (!m_ipc_to_in_th)
+ {
+ m_ipc_to_in_th = omx_aac_thread_create(process_in_port_msg,
+ this, (char *)"INPUT_THREAD");
+ if (!m_ipc_to_in_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start \
+ Input port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ }
+
+ if (!m_ipc_to_cmd_th)
+ {
+ m_ipc_to_cmd_th = omx_aac_thread_create(process_command_msg,
+ this, (char *)"CMD_THREAD");
+ if (!m_ipc_to_cmd_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!!Failed to start "
+ "command message thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+
+ if (!m_ipc_to_out_th)
+ {
+ m_ipc_to_out_th = omx_aac_thread_create(process_out_port_msg,
+ this, (char *)"OUTPUT_THREAD");
+ if (!m_ipc_to_out_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start output "
+ "port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ return eRet;
+}
+
+/**
+
+ @brief member function to retrieve version of component
+
+
+
+ @param hComp handle to this component instance
+ @param componentName name of component
+ @param componentVersion pointer to memory space which stores the
+ version number
+ @param specVersion pointer to memory sapce which stores version of
+ openMax specification
+ @param componentUUID
+ @return Error status
+ */
+OMX_ERRORTYPE omx_aac_aenc::get_component_version
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STRING componentName,
+ OMX_OUT OMX_VERSIONTYPE* componentVersion,
+ OMX_OUT OMX_VERSIONTYPE* specVersion,
+ OMX_OUT OMX_UUIDTYPE* componentUUID)
+{
+ if((hComp == NULL) || (componentName == NULL) ||
+ (specVersion == NULL) || (componentUUID == NULL))
+ {
+ componentVersion = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ componentVersion->nVersion = OMX_SPEC_VERSION;
+ specVersion->nVersion = OMX_SPEC_VERSION;
+ return OMX_ErrorNone;
+}
+/**
+ @brief member function handles command from IL client
+
+ This function simply queue up commands from IL client.
+ Commands will be processed in command server thread context later
+
+ @param hComp handle to component instance
+ @param cmd type of command
+ @param param1 parameters associated with the command type
+ @param cmdData
+ @return Error status
+*/
+OMX_ERRORTYPE omx_aac_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ int portIndex = (int)param1;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateInvalid == m_state)
+ {
+ return OMX_ErrorInvalidState;
+ }
+ if ( (cmd == OMX_CommandFlush) && (portIndex > 1) )
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND);
+ DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n");
+ DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1);
+ sem_wait (&sem_States);
+ DEBUG_PRINT("send_command : recieved state after semwait\n");
+ return OMX_ErrorNone;
+}
+
+/**
+ @brief member function performs actual processing of commands excluding
+ empty buffer call
+
+ @param hComp handle to component
+ @param cmd command type
+ @param param1 parameter associated with the command
+ @param cmdData
+
+ @return error status
+*/
+OMX_ERRORTYPE omx_aac_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ // Handle only IDLE and executing
+ OMX_STATETYPE eState = (OMX_STATETYPE) param1;
+ int bFlag = 1;
+ nState = eState;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_CommandStateSet == cmd)
+ {
+ /***************************/
+ /* Current State is Loaded */
+ /***************************/
+ if (OMX_StateLoaded == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+
+ if (allocate_done() ||
+ (m_inp_bEnabled == OMX_FALSE
+ && m_out_bEnabled == OMX_FALSE))
+ {
+ DEBUG_PRINT("SCP-->Allocate Done Complete\n");
+ }
+ else
+ {
+ DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ bFlag = 0;
+ }
+
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ }
+
+ else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n");
+ eRet = OMX_ErrorNone;
+ }
+
+ else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ m_state = OMX_StateInvalid;
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /***************************/
+ /* Current State is IDLE */
+ /***************************/
+ else if (OMX_StateIdle == m_state)
+ {
+ if (OMX_StateLoaded == eState)
+ {
+ if (release_done(-1))
+ {
+ if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("SCP:Idle->Loaded,ioctl \
+ stop failed %d\n", errno);
+ }
+ nTimestamp=0;
+ ts = 0;
+ frameduration = 0;
+ DEBUG_PRINT("SCP-->Idle to Loaded\n");
+ } else
+ {
+ DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING);
+ // Skip the event notification
+ bFlag = 0;
+ }
+ }
+ else if (OMX_StateExecuting == eState)
+ {
+
+ struct msm_audio_aac_enc_config drv_aac_enc_config;
+ struct msm_audio_aac_config drv_aac_config;
+ struct msm_audio_stream_config drv_stream_config;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+ if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+ if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+
+ if(ioctl(m_drv_fd, AUDIO_GET_AAC_ENC_CONFIG,
+ &drv_aac_enc_config) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_AAC_ENC_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+ drv_aac_enc_config.channels = m_aac_param.nChannels;
+ drv_aac_enc_config.sample_rate = m_aac_param.nSampleRate;
+ drv_aac_enc_config.bit_rate = m_aac_param.nBitRate;
+ DEBUG_PRINT("aac config %lu,%lu,%lu %d\n",
+ m_aac_param.nChannels,m_aac_param.nSampleRate,
+ m_aac_param.nBitRate,m_aac_param.eAACStreamFormat);
+ switch(m_aac_param.eAACStreamFormat)
+ {
+
+ case 0:
+ case 1:
+ {
+ drv_aac_enc_config.stream_format = 65535;
+ DEBUG_PRINT("Setting AUDIO_AAC_FORMAT_ADTS\n");
+ break;
+ }
+ case 4:
+ case 5:
+ case 6:
+ {
+ drv_aac_enc_config.stream_format = AUDIO_AAC_FORMAT_RAW;
+ DEBUG_PRINT("Setting AUDIO_AAC_FORMAT_RAW\n");
+ break;
+ }
+ default:
+ break;
+ }
+ DEBUG_PRINT("Stream format = %d\n",
+ drv_aac_enc_config.stream_format);
+ if(ioctl(m_drv_fd, AUDIO_SET_AAC_ENC_CONFIG,
+ &drv_aac_enc_config) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_AAC_ENC_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+ if (ioctl(m_drv_fd, AUDIO_GET_AAC_CONFIG, &drv_aac_config)
+ == -1) {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_AAC_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+
+ drv_aac_config.sbr_on_flag = 0;
+ drv_aac_config.sbr_ps_on_flag = 0;
+ /* Other members of drv_aac_config are not used,
+ so not setting them */
+ switch(m_aac_param.eAACProfile)
+ {
+ case OMX_AUDIO_AACObjectLC:
+ {
+ DEBUG_PRINT("AAC_Profile: OMX_AUDIO_AACObjectLC\n");
+ drv_aac_config.sbr_on_flag = 0;
+ drv_aac_config.sbr_ps_on_flag = 0;
+ break;
+ }
+ case OMX_AUDIO_AACObjectHE:
+ {
+ DEBUG_PRINT("AAC_Profile: OMX_AUDIO_AACObjectHE\n");
+ drv_aac_config.sbr_on_flag = 1;
+ drv_aac_config.sbr_ps_on_flag = 0;
+ break;
+ }
+ case OMX_AUDIO_AACObjectHE_PS:
+ {
+ DEBUG_PRINT("AAC_Profile: OMX_AUDIO_AACObjectHE_PS\n");
+ drv_aac_config.sbr_on_flag = 1;
+ drv_aac_config.sbr_ps_on_flag = 1;
+ break;
+ }
+ default:
+ {
+ DEBUG_PRINT_ERROR("Unsupported AAC Profile Type = %d\n",
+ m_aac_param.eAACProfile);
+ break;
+ }
+ }
+ DEBUG_PRINT("sbr_flag = %d, sbr_ps_flag = %d\n",
+ drv_aac_config.sbr_on_flag,
+ drv_aac_config.sbr_ps_on_flag);
+
+ if (ioctl(m_drv_fd, AUDIO_SET_AAC_CONFIG, &drv_aac_config)
+ == -1) {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_AAC_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+
+ if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ buf_cfg.meta_info_enable = 1;
+ buf_cfg.frames_per_buf = NUMOFFRAMES;
+ if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ if(pcm_input)
+ {
+ if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ pcm_cfg.channel_count = m_pcm_param.nChannels;
+ pcm_cfg.sample_rate = m_pcm_param.nSamplingRate;
+ pcm_cfg.buffer_size = input_buffer_size;
+ pcm_cfg.buffer_count = m_inp_current_buf_count;
+ DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+
+ if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ }
+ if(ioctl(m_drv_fd, AUDIO_START, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n",
+ errno);
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ }
+ DEBUG_PRINT("SCP-->Idle to Executing\n");
+ nState = eState;
+ frameduration = (1024*1000000)/m_aac_param.nSampleRate;
+ } else if (eState == OMX_StateIdle)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n");
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /******************************/
+ /* Current State is Executing */
+ /******************************/
+ else if (OMX_StateExecuting == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+ DEBUG_PRINT("SCP-->Executing to Idle \n");
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+
+ } else if (OMX_StatePause == eState)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED PAUSE STATE\n");
+ DEBUG_DETAIL("*************************\n");
+ //ioctl(m_drv_fd, AUDIO_PAUSE, 0);
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n",
+ eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /***************************/
+ /* Current State is Pause */
+ /***************************/
+ else if (OMX_StatePause == m_state)
+ {
+ if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) )
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if(is_out_th_sleep)
+ {
+ DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n");
+ is_out_th_sleep = false;
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ }
+ if ( OMX_StateExecuting == eState )
+ {
+ nState = eState;
+ } else if ( OMX_StateIdle == eState )
+ {
+ DEBUG_PRINT("SCP-->Paused to Idle \n");
+ DEBUG_PRINT ("\n Internal flush issued");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+ } else if ( eState == OMX_StateLoaded )
+ {
+ DEBUG_PRINT("\n Pause --> loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n Pause --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("\n Pause --> Pause \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n Pause --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /**************************************/
+ /* Current State is WaitForResources */
+ /**************************************/
+ else if (m_state == OMX_StateWaitForResources)
+ {
+ if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n");
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: \
+ WaitForResources-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n",
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /****************************/
+ /* Current State is Invalid */
+ /****************************/
+ else if (m_state == OMX_StateInvalid)
+ {
+ if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState
+ || OMX_StateIdle == eState || OMX_StateExecuting == eState
+ || OMX_StatePause == eState || OMX_StateInvalid == eState)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing"
+ "/Pause/Invalid/WaitForResources\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else if (OMX_CommandFlush == cmd)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1);
+ DEBUG_DETAIL("*************************\n");
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX ||
+ param1 == OMX_CORE_OUTPUT_PORT_INDEX ||
+ (signed)param1 == -1 )
+ {
+ execute_omx_flush(param1);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError,
+ OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL );
+ }
+ } else if ( cmd == OMX_CommandPortDisable )
+ {
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL )
+ {
+ DEBUG_PRINT("SCP: Disabling Input port Indx\n");
+ m_inp_bEnabled = OMX_FALSE;
+ if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(0) )
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_inp_bEnabled=%d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+
+ else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\
+ " param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+
+ }
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+
+ DEBUG_PRINT("SCP: Disabling Output port Indx\n");
+ m_out_bEnabled = OMX_FALSE;
+ if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(1))
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_out_bEnabled=%d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\
+ "param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID");
+ }
+
+ } else if (cmd == OMX_CommandPortEnable)
+ {
+ bFlag = 0;
+ if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ m_inp_bEnabled = OMX_TRUE;
+ DEBUG_PRINT("SCP: Enabling Input port Indx\n");
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_inp_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+
+ } else
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ }
+
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ DEBUG_PRINT("SCP: Enabling Output port Indx\n");
+ m_out_bEnabled = OMX_TRUE;
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_out_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID");
+ }
+
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd);
+ eRet = OMX_ErrorNotImplemented;
+ }
+ DEBUG_PRINT("posting sem_States\n");
+ sem_post (&sem_States);
+ if (eRet == OMX_ErrorNone && bFlag)
+ {
+ post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT);
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] param1
+ [IN] cmd_cmpl
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_aac_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl)
+{
+ bool bRet = true;
+
+ DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1);
+ struct timespec abs_timeout;
+ abs_timeout.tv_sec = 1;
+ abs_timeout.tv_nsec = 0;
+
+ if ((signed)param1 == -1)
+ {
+ bFlushinprogress = true;
+ DEBUG_PRINT("Execute flush for both I/p O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+
+ // Send Flush commands to input and output threads
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ // Send Flush to the kernel so that the in and out buffers are released
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+
+ DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\
+ param1,cmd_cmpl);
+
+ // If not going to idle state, Send FLUSH complete message
+ // to the Client, now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n");
+ }
+ bFlushinprogress = false;
+ }
+ else if (param1 == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("Execute FLUSH for I/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ //sleep till the FLUSH ACK are done by both the input and output threads
+ DEBUG_DETAIL("Executing FLUSH for I/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+ DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1);
+
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1)
+ {
+ DEBUG_PRINT("Executing FLUSH for O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ DEBUG_DETAIL("Executing FLUSH for O/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1)
+ DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ // sleep till the FLUSH ACK are done by both the input
+ // and output threads
+ wait_for_event();
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ }
+ DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1);
+ } else
+ {
+ DEBUG_PRINT("Invalid Port ID[%lu]",param1);
+ }
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_input_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_aac_aenc::execute_input_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on input port");
+
+ pthread_mutex_lock(&m_lock);
+ do
+ {
+ qsize = m_input_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += m_input_ctrl_ebd_q.m_size;
+
+ DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,qsize);
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_lock);
+ break;
+ }
+ if (qsize)
+ {
+ m_input_q.pop_entry(&p1, &p2, &ident);
+ if ((ident == OMX_COMPONENT_GENERATE_ETB) ||
+ (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf);
+ omx_buf->nFilledLen = 0;
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else if (m_input_ctrl_ebd_q.m_size)
+ {
+ m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident);
+ if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ omx_buf->nFilledLen = 0;
+ DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf);
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else
+ {
+ }
+ }while (tot_qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("IN-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_lock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_output_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_aac_aenc::execute_output_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on output port");
+
+ pthread_mutex_lock(&m_outputlock);
+ do
+ {
+ qsize = m_output_q.m_size;
+ DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,qsize);
+ tot_qsize = qsize;
+ tot_qsize += m_output_ctrl_fbd_q.m_size;
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_outputlock);
+ break;
+ }
+ if (qsize)
+ {
+ m_output_q.pop_entry(&p1,&p2,&ident);
+ if ( (OMX_COMPONENT_GENERATE_FTB == ident) ||
+ (OMX_COMPONENT_GENERATE_FRAME_DONE == ident))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FBD FROM FLUSH");
+ }
+ } else if ((qsize = m_output_ctrl_fbd_q.m_size))
+ {
+ m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident);
+ if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH");
+ }
+ }
+ }while (qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("OUT-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_outputlock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_input
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_aac_aenc::post_input(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+ pthread_mutex_lock(&m_lock);
+
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND))
+ {
+ // insert flush message and ebd
+ m_input_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id))
+ {
+ // insert ebd
+ m_input_ctrl_ebd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ // ETBS in this queue
+ m_input_q.insert_entry(p1,p2,id);
+ }
+
+ if (m_ipc_to_in_th)
+ {
+ bRet = true;
+ omx_aac_post_msg(m_ipc_to_in_th, id);
+ }
+
+ DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\
+ m_state,
+ id,
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,
+ m_input_q.m_size);
+
+ pthread_mutex_unlock(&m_lock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_command
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_aac_aenc::post_command(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_commandlock);
+
+ m_command_q.insert_entry(p1,p2,id);
+
+ if (m_ipc_to_cmd_th)
+ {
+ bRet = true;
+ omx_aac_post_msg(m_ipc_to_cmd_th, id);
+ }
+
+ DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\
+ m_state,
+ id,
+ m_command_q.m_size,
+ m_flags >> 3);
+
+ pthread_mutex_unlock(&m_commandlock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_output
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_aac_aenc::post_output(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_outputlock);
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)
+ || (id == OMX_COMPONENT_RESUME))
+ {
+ // insert flush message and fbd
+ m_output_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) )
+ {
+ // insert flush message and fbd
+ m_output_ctrl_fbd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ m_output_q.insert_entry(p1,p2,id);
+ }
+ if ( m_ipc_to_out_th )
+ {
+ bRet = true;
+ omx_aac_post_msg(m_ipc_to_out_th, id);
+ }
+ DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ m_state,
+ id,
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,
+ m_output_q.m_size);
+
+ pthread_mutex_unlock(&m_outputlock);
+ return bRet;
+}
+/**
+ @brief member function that return parameters to IL client
+
+ @param hComp handle to component instance
+ @param paramIndex Parameter type
+ @param paramData pointer to memory space which would hold the
+ paramter
+ @return error status
+*/
+OMX_ERRORTYPE omx_aac_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_INOUT OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Param in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("get_parameter: paramData is NULL\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ DEBUG_PRINT("OMX_IndexParamPortDefinition " \
+ "portDefn->nPortIndex = %lu\n",
+ portDefn->nPortIndex);
+
+ portDefn->nVersion.nVersion = OMX_SPEC_VERSION;
+ portDefn->nSize = sizeof(portDefn);
+ portDefn->eDomain = OMX_PortDomainAudio;
+
+ if (0 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirInput;
+ portDefn->bEnabled = m_inp_bEnabled;
+ portDefn->bPopulated = m_inp_bPopulated;
+ portDefn->nBufferCountActual = m_inp_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS;
+ portDefn->nBufferSize = input_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+ portDefn->format.audio.pNativeRender = 0;
+ } else if (1 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirOutput;
+ portDefn->bEnabled = m_out_bEnabled;
+ portDefn->bPopulated = m_out_bPopulated;
+ portDefn->nBufferCountActual = m_out_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS;
+ portDefn->nBufferSize = output_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+ portDefn->format.audio.pNativeRender = 0;
+ } else
+ {
+ portDefn->eDir = OMX_DirMax;
+ DEBUG_PRINT_ERROR("Bad Port idx %d\n",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioInit\n");
+
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 2;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n");
+ portFormatType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portFormatType->nSize = sizeof(portFormatType);
+
+ if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex)
+ {
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\
+ "%lu\n", portFormatType->nIndex);
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingAAC;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n",
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioAac:
+ {
+ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParam =
+ (OMX_AUDIO_PARAM_AACPROFILETYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioAac\n");
+ if (OMX_CORE_OUTPUT_PORT_INDEX== aacParam->nPortIndex)
+ {
+ memcpy(aacParam,&m_aac_param,
+ sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE));
+
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioAac "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)aacParam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case QOMX_IndexParamAudioSessionId:
+ {
+ QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam =
+ (QOMX_AUDIO_STREAM_INFO_DATA *) paramData;
+ streaminfoparam->sessionId = m_session_id;
+ break;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(pcmparam,&m_pcm_param,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+
+ DEBUG_PRINT("get_parameter: Sampling rate %lu",\
+ pcmparam->nSamplingRate);
+ DEBUG_PRINT("get_parameter: Number of channels %lu",\
+ pcmparam->nChannels);
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamComponentSuspended:
+ {
+ OMX_PARAM_SUSPENSIONTYPE *suspend =
+ (OMX_PARAM_SUSPENSIONTYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n",
+ suspend);
+ break;
+ }
+ case OMX_IndexParamVideoInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ OMX_PRIORITYMGMTTYPE *priorityMgmtType =
+ (OMX_PRIORITYMGMTTYPE*)paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n");
+ priorityMgmtType->nSize = sizeof(priorityMgmtType);
+ priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION;
+ priorityMgmtType->nGroupID = m_priority_mgm.nGroupID;
+ priorityMgmtType->nGroupPriority =
+ m_priority_mgm.nGroupPriority;
+ break;
+ }
+ case OMX_IndexParamImageInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+
+ bufferSupplierType->nSize = sizeof(bufferSupplierType);
+ bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION;
+ if (OMX_CORE_INPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:"\
+ "OMX_IndexParamCompBufferSupplier eRet"\
+ "%08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ /*Component should support this port definition*/
+ case OMX_IndexParamOtherInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ componentRole->nSize = component_Role.nSize;
+ componentRole->nVersion = component_Role.nVersion;
+ strlcpy((char *)componentRole->cRole,
+ (const char*)component_Role.cRole,
+ sizeof(componentRole->cRole));
+ DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n",
+ component_Role.nSize,
+ component_Role.nVersion,
+ component_Role.cRole);
+ break;
+
+ }
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+
+}
+
+/**
+ @brief member function that set paramter from IL client
+
+ @param hComp handle to component instance
+ @param paramIndex parameter type
+ @param paramData pointer to memory space which holds the paramter
+ @return error status
+ */
+OMX_ERRORTYPE omx_aac_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_IN OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ unsigned int loop=0;
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("set_parameter is not in proper state\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("param data is NULL");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamAudioAac:
+ {
+ DEBUG_PRINT("OMX_IndexParamAudioAac");
+ OMX_AUDIO_PARAM_AACPROFILETYPE *aacparam
+ = (OMX_AUDIO_PARAM_AACPROFILETYPE *) paramData;
+ memcpy(&m_aac_param,aacparam,
+ sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE));
+
+ for (loop=0; loop< sizeof(sample_idx_tbl) / \
+ sizeof(struct sample_rate_idx); \
+ loop++)
+ {
+ if(sample_idx_tbl[loop].sample_rate == m_aac_param.nSampleRate)
+ {
+ sample_idx = sample_idx_tbl[loop].sample_rate_idx;
+ }
+ }
+ break;
+ }
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ if (((m_state == OMX_StateLoaded)&&
+ !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources &&
+ ((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == true)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == true)))
+ ||(((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == false)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == false)) &&
+ (m_state != OMX_StateWaitForResources)))
+ {
+ DEBUG_PRINT("Set Parameter called in valid state\n");
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex "
+ "= %lu\n",portDefn->nPortIndex);
+ if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_INPUT_BUFFERS )
+ {
+ m_inp_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS;
+ }
+ input_buffer_size = portDefn->nBufferSize;
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_OUTPUT_BUFFERS )
+ {
+ m_out_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS;
+ }
+ output_buffer_size = portDefn->nBufferSize;
+ } else
+ {
+ DEBUG_PRINT(" set_parameter: Bad Port idx %d",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n");
+
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ OMX_PRIORITYMGMTTYPE *priorityMgmtype
+ = (OMX_PRIORITYMGMTTYPE*) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n",
+ priorityMgmtype->nGroupID);
+
+ DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n",
+ priorityMgmtype->nGroupPriority);
+
+ m_priority_mgm.nGroupID = priorityMgmtype->nGroupID;
+ m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority;
+
+ break;
+ }
+ case OMX_IndexParamAudioPortFormat:
+ {
+
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n");
+
+ if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex)
+ {
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\
+ " %lu\n", portFormatType->nIndex);
+ portFormatType->eEncoding = OMX_AUDIO_CodingAAC;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("set_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\
+ bufferSupplierType->eBufferSupplier);
+
+ if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX
+ || bufferSupplierType->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("set_parameter:\
+ OMX_IndexParamCompBufferSupplier\n");
+ m_buffer_supplier.eBufferSupplier =
+ bufferSupplierType->eBufferSupplier;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_param:IndexParamCompBufferSup \
+ %08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ break; }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n");
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam
+ = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+
+ memcpy(&m_pcm_param,pcmparam,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+
+ DEBUG_PRINT("set_pcm_parameter: %lu %lu",\
+ m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm "
+ "OMX_ErrorBadPortIndex %d\n",
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamSuspensionPolicy:
+ {
+ eRet = OMX_ErrorNotImplemented;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ component_Role.nSize = componentRole->nSize;
+ component_Role.nVersion = componentRole->nVersion;
+ strlcpy((char *)component_Role.cRole,
+ (const char*)componentRole->cRole,
+ sizeof(component_Role.cRole));
+ break;
+ }
+
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::GetConfig
+
+DESCRIPTION
+ OMX Get Config Method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_INOUT OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *volume =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex)
+ {
+ volume->nSize = sizeof(volume);
+ volume->nVersion.nVersion = OMX_SPEC_VERSION;
+ volume->bLinear = OMX_TRUE;
+ volume->sVolume.nValue = m_volume;
+ volume->sVolume.nMax = OMX_AENC_MAX;
+ volume->sVolume.nMin = OMX_AENC_MIN;
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute =
+ (OMX_AUDIO_CONFIG_MUTETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex)
+ {
+ mute->nSize = sizeof(mute);
+ mute->nVersion.nVersion = OMX_SPEC_VERSION;
+ mute->bMute = (BITMASK_PRESENT(&m_flags,
+ OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::SetConfig
+
+DESCRIPTION
+ OMX Set Config method implementation
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_IN OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Set Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if ( m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *vol =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData;
+ if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if ((vol->sVolume.nValue <= OMX_AENC_MAX) &&
+ (vol->sVolume.nValue >= OMX_AENC_MIN))
+ {
+ m_volume = vol->sVolume.nValue;
+ if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED))
+ {
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+
+ } else
+ {
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*)
+ configData;
+ if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if (mute->bMute == OMX_TRUE)
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */
+ } else
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::GetExtensionIndex
+
+DESCRIPTION
+ OMX GetExtensionIndex method implementaion. <TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::get_extension_index(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_STRING paramName,
+ OMX_OUT OMX_INDEXTYPE* indexType)
+{
+ if((hComp == NULL) || (paramName == NULL) || (indexType == NULL))
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId",
+ strlen("OMX.Qualcomm.index.audio.sessionId")) == 0)
+ {
+ *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId;
+ DEBUG_PRINT("Extension index type - %d\n", *indexType);
+
+ }
+ else
+ {
+ return OMX_ErrorBadParameter;
+
+ }
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::GetState
+
+DESCRIPTION
+ Returns the state information back to the caller.<TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STATETYPE* state)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ *state = m_state;
+ DEBUG_PRINT("Returning the state %d\n",*state);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::ComponentTunnelRequest
+
+DESCRIPTION
+ OMX Component Tunnel Request method implementation. <TBD>
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::component_tunnel_request
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_HANDLETYPE peerComponent,
+ OMX_IN OMX_U32 peerPort,
+ OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup)
+{
+ DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n");
+
+ if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL))
+ {
+ port = 0;
+ peerPort = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::AllocateInputBuffer
+
+DESCRIPTION
+ Helper function for allocate buffer in the input pin
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::allocate_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+ if(m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc((nBufSize + \
+ sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1);
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ free(buf_ptr);
+ return OMX_ErrorBadParameter;
+ }
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+
+ m_inp_current_buf_count++;
+ DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%d \
+ bytes=%lu",bufHdr, bufHdr->pBuffer,m_inp_current_buf_count,
+ bytes);
+
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+OMX_ERRORTYPE omx_aac_aenc::allocate_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+ buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr)+
+ sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+ DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d "\
+ "bytes=%lu",bufHdr, bufHdr->pBuffer,\
+ m_out_current_buf_count, bytes);
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+
+// AllocateBuffer -- API Call
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::AllocateBuffer
+
+DESCRIPTION
+ Returns zero if all the buffers released..
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::allocate_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type
+
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ // What if the client calls again.
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",
+ (int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("allocate_buffer: before allocate_done \n");
+ if (allocate_done())
+ {
+ DEBUG_PRINT("allocate_buffer: after allocate_done \n");
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("allocate_buffer: post idle transition event \n");
+ }
+ DEBUG_PRINT("allocate_buffer: complete \n");
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ m_out_bEnabled = OMX_TRUE;
+
+ DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("AB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ }
+ DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet);
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_buffer
+
+DESCRIPTION:
+ OMX Use Buffer method implementation.
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_aac_aenc::use_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("Checking for Output Allocate buffer Done");
+ if (allocate_done())
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("UB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ }
+ }
+ DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet);
+ return eRet;
+}
+/*=============================================================================
+FUNCTION:
+ use_input_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the input pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_aac_aenc::use_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if(bytes < input_buffer_size)
+ {
+ /* return if i\p buffer size provided by client
+ is less than min i\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+ if (m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ input_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+ m_inp_current_buf_count++;
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_output_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the output pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_aac_aenc::use_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (bytes < output_buffer_size)
+ {
+ /* return if o\p buffer size provided by client
+ is less than min o\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+
+ DEBUG_PRINT("Inside omx_aac_aenc::use_output_buffer");
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer);
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \
+ len=%lu\n", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ output_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_aac_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_input_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_input_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_aac_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_output_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_output_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+// Free Buffer - API call
+/**
+ @brief member function that handles free buffer command from IL client
+
+ This function is a block-call function that handles IL client request to
+ freeing the buffer
+
+ @param hComp handle to component instance
+ @param port id of port which holds the buffer
+ @param buffer buffer header
+ @return Error status
+*/
+OMX_ERRORTYPE omx_aac_aenc::free_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("Free_Buffer buf %p\n", buffer);
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateIdle &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ DEBUG_PRINT(" free buffer while Component in Loading pending\n");
+ } else if ((m_inp_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_INPUT_PORT_INDEX)||
+ (m_out_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_OUTPUT_PORT_INDEX))
+ {
+ DEBUG_PRINT("Free Buffer while port %lu disabled\n", port);
+ } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause)
+ {
+ DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\
+ OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ return eRet;
+ } else
+ {
+ DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\
+ disabled:OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ if (m_inp_current_buf_count != 0)
+ {
+ m_inp_bPopulated = OMX_FALSE;
+ if (true == search_input_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer);
+ m_input_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_inp_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \
+ Invalid Input buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \
+ came out Invalid\n");
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING)
+ && release_done(0))
+ {
+ DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ if (m_out_current_buf_count != 0)
+ {
+ m_out_bPopulated = OMX_FALSE;
+ if (true == search_output_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer);
+ m_output_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_out_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT("Free_Buf:Error-->free_buffer , \
+ Invalid Output buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING)
+ && release_done(1))
+ {
+ DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if ((OMX_ErrorNone == eRet) &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ if (release_done(-1))
+ {
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0)
+ DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n");
+ else
+ DEBUG_PRINT("AUDIO STOP in free buffer passed\n");
+
+ DEBUG_PRINT("Free_Buf: Free buffer\n");
+
+ // Send the callback now
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING);
+ DEBUG_PRINT("Before OMX_StateLoaded \
+ OMX_COMPONENT_GENERATE_EVENT\n");
+ post_command(OMX_CommandStateSet,
+ OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n");
+
+ }
+ }
+ return eRet;
+}
+
+
+/**
+ @brief member function that that handles empty this buffer command
+
+ This function meremly queue up the command and data would be consumed
+ in command server thread context
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_aac_aenc::empty_this_buffer(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \
+ buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf));
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("Empty this buffer in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (!m_inp_bEnabled)
+ {
+ DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\
+ "Port Status %d \n", m_inp_bEnabled);
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_aac_aenc::etb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_aac_aenc::etb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+
+ if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ if ((m_state != OMX_StateExecuting) &&
+ (m_state != OMX_StatePause))
+ {
+ DEBUG_PRINT_ERROR("Invalid state\n");
+ eRet = OMX_ErrorInvalidState;
+ }
+ if (OMX_ErrorNone == eRet)
+ {
+ if (search_input_bufhdr(buffer) == true)
+ {
+ post_input((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ pthread_mutex_lock(&in_buf_count_lock);
+ nNumInputBuf++;
+ m_aac_pb_stats.etb_cnt++;
+ pthread_mutex_unlock(&in_buf_count_lock);
+ return eRet;
+}
+/**
+ @brief member function that writes data to kernel driver
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_aac_aenc::empty_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ META_IN meta_in;
+ //Pointer to the starting location of the data to be transcoded
+ OMX_U8 *srcStart;
+ //The total length of the data to be transcoded
+ srcStart = buffer->pBuffer;
+ OMX_U8 *data = NULL;
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer);
+ memset(&meta_in,0,sizeof(meta_in));
+ if ( search_input_bufhdr(buffer) == false )
+ {
+ DEBUG_PRINT("ETBP: INVALID BUF HDR\n");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorBadParameter;
+ }
+ if (m_tmp_meta_buf)
+ {
+ data = m_tmp_meta_buf;
+
+ // copy the metadata info from the BufHdr and insert to payload
+ meta_in.offsetVal = sizeof(META_IN);
+ meta_in.nTimeStamp.LowPart =
+ ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF);
+ meta_in.nTimeStamp.HighPart =
+ (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF);
+ meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS;
+ if(buffer->nFlags & OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT("EOS OCCURED \n");
+ meta_in.nFlags |= OMX_BUFFERFLAG_EOS;
+ }
+ memcpy(data,&meta_in, meta_in.offsetVal);
+ DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags);
+ }
+
+ memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen);
+ write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN));
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (OMX_StateExecuting == state)
+ {
+ DEBUG_DETAIL("In Exe state, EBD CB");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ } else
+ {
+ /* Assume empty this buffer function has already checked
+ validity of buffer */
+ DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer);
+ post_input((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_BUFFER_DONE);
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE omx_aac_aenc::fill_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ ENC_META_OUT *meta_out = NULL;
+ int nReadbytes = 0;
+ int szadifhr = 0;
+ int numframes = 0;
+ int metainfo = 0;
+ OMX_U8 *src = buffer->pBuffer;
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (true == search_output_bufhdr(buffer))
+ {
+ if((m_aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatADIF)
+ && (adif_flag == 0))
+ {
+
+ DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd);
+ nReadbytes = read(m_drv_fd,m_tmp_out_meta_buf,output_buffer_size );
+ DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\
+ buffer->nAllocLen,m_tmp_out_meta_buf,
+ nReadbytes,nNumOutputBuf);
+ if(*m_tmp_out_meta_buf <= 0)
+ return OMX_ErrorBadParameter;
+ szadifhr = AUDAAC_MAX_ADIF_HEADER_LENGTH;
+ numframes = *m_tmp_out_meta_buf;
+ metainfo = ((sizeof(ENC_META_OUT) * numframes)+
+ sizeof(unsigned char));
+ audaac_rec_install_adif_header_variable(0,sample_idx,
+ m_aac_param.nChannels);
+ memcpy(buffer->pBuffer,m_tmp_out_meta_buf,metainfo);
+ memcpy(buffer->pBuffer + metainfo,&audaac_header_adif[0],szadifhr);
+ memcpy(buffer->pBuffer + metainfo + szadifhr,
+ m_tmp_out_meta_buf + metainfo,(nReadbytes - metainfo));
+ src += sizeof(unsigned char);
+ meta_out = (ENC_META_OUT *)src;
+ meta_out->frame_size += szadifhr;
+ numframes--;
+ while(numframes > 0)
+ {
+ src += sizeof(ENC_META_OUT);
+ meta_out = (ENC_META_OUT *)src;
+ meta_out->offset_to_frame += szadifhr;
+ numframes--;
+ }
+ buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
+ adif_flag++;
+ }
+ else if((m_aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF)
+ &&(mp4ff_flag == 0))
+ {
+ DEBUG_PRINT("OMX_AUDIO_AACStreamFormatMP4FF\n");
+ audaac_rec_install_mp4ff_header_variable(0,sample_idx,
+ m_aac_param.nChannels);
+ memcpy(buffer->pBuffer,&audaac_header_mp4ff[0],
+ AUDAAC_MAX_MP4FF_HEADER_LENGTH);
+ buffer->nFilledLen = AUDAAC_MAX_MP4FF_HEADER_LENGTH;
+ buffer->nTimeStamp = 0;
+ buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ mp4ff_flag++;
+ return OMX_ErrorNone;
+
+ }
+ else
+ {
+
+ DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd);
+ nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size );
+ DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\
+ buffer->nAllocLen,buffer->pBuffer,
+ nReadbytes,nNumOutputBuf);
+ if(nReadbytes <= 0)
+ {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorNone;
+ }
+ }
+
+ meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char));
+ buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+
+ meta_out->lsw_ts);
+
+ ts += frameduration;
+ buffer->nTimeStamp = ts;
+ nTimestamp = buffer->nTimeStamp;
+ buffer->nFlags |= meta_out->nflags;
+ buffer->nOffset = meta_out->offset_to_frame + 1;
+ buffer->nFilledLen = nReadbytes - buffer->nOffset + szadifhr;
+ DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \
+ timestamp %lld\n", meta_out->nflags,
+ meta_out->frame_size,
+ meta_out->offset_to_frame,
+ buffer->nTimeStamp);
+
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n");
+ m_cb.EventHandler(&m_cmp,
+ m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+ DEBUG_PRINT("FTBP: END OF STREAM m_eos_bm=%d\n",m_eos_bm);
+ }
+
+ return OMX_ErrorNone;
+ }
+ DEBUG_PRINT("nState %d \n",nState );
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (state == OMX_StatePause)
+ {
+ DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\
+ state);
+ post_output((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_FRAME_DONE);
+ }
+ else
+ {
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ DEBUG_PRINT("FTBP*******************************************\n");
+
+ }
+
+
+ }
+ else
+ DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n");
+
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::FillThisBuffer
+
+DESCRIPTION
+ IL client uses this method to release the frame buffer
+ after displaying them.
+
+
+
+PARAMETERS
+
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::fill_this_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_aac_aenc::ftb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_bEnabled == OMX_FALSE)
+ {
+ return OMX_ErrorIncorrectStateOperation;
+ }
+
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_aac_aenc::ftb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+ if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf++;
+ m_aac_pb_stats.ftb_cnt++;
+ DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf);
+ pthread_mutex_unlock(&out_buf_count_lock);
+ post_output((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB);
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::SetCallbacks
+
+DESCRIPTION
+ Set the callbacks.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::set_callbacks(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_CALLBACKTYPE* callbacks,
+ OMX_IN OMX_PTR appData)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ m_cb = *callbacks;
+ m_app_data = appData;
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::ComponentDeInit
+
+DESCRIPTION
+ Destroys the component and release memory allocated to the heap.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state)
+ {
+ DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n",
+ m_state);
+ }
+ deinit_encoder();
+
+ DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::deinit_encoder
+
+DESCRIPTION
+ Closes all the threads and release memory allocated to the heap.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ None.
+
+========================================================================== */
+void omx_aac_aenc::deinit_encoder()
+{
+ DEBUG_PRINT("Component-deinit being processed\n");
+ DEBUG_PRINT("********************************\n");
+ DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\
+ m_aac_pb_stats.tot_in_buf_len,
+ m_aac_pb_stats.tot_out_buf_len,
+ m_aac_pb_stats.tot_pb_time);
+ DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\
+ m_aac_pb_stats.fbd_cnt,m_aac_pb_stats.ftb_cnt,
+ m_aac_pb_stats.etb_cnt,
+ m_aac_pb_stats.ebd_cnt);
+ memset(&m_aac_pb_stats,0,sizeof(AAC_PB_STATS));
+
+ if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state))
+ {
+ DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\
+ m_state);
+ // Get back any buffers from driver
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+ // force state change to loaded so that all threads can be exited
+ pthread_mutex_lock(&m_state_lock);
+ m_state = OMX_StateLoaded;
+ pthread_mutex_unlock(&m_state_lock);
+ DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\
+ m_inp_current_buf_count,
+ m_input_buf_hdrs.size());
+ m_input_buf_hdrs.eraseall();
+ DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\
+ m_out_current_buf_count,
+ m_output_buf_hdrs.size());
+ m_output_buf_hdrs.eraseall();
+
+ }
+ if(pcm_input)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ if(pcm_input)
+ {
+ if (m_ipc_to_in_th != NULL)
+ {
+ omx_aac_thread_stop(m_ipc_to_in_th);
+ m_ipc_to_in_th = NULL;
+ }
+ }
+
+ if (m_ipc_to_cmd_th != NULL)
+ {
+ omx_aac_thread_stop(m_ipc_to_cmd_th);
+ m_ipc_to_cmd_th = NULL;
+ }
+ if (m_ipc_to_out_th != NULL)
+ {
+ DEBUG_DETAIL("Inside omx_aac_thread_stop\n");
+ omx_aac_thread_stop(m_ipc_to_out_th);
+ m_ipc_to_out_th = NULL;
+ }
+
+
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0)
+ DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n");
+
+ if(pcm_input && m_tmp_meta_buf )
+ {
+ free(m_tmp_meta_buf);
+ }
+
+ if(m_tmp_out_meta_buf)
+ {
+ free(m_tmp_out_meta_buf);
+ }
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ m_inp_current_buf_count=0;
+ m_out_current_buf_count=0;
+ m_out_act_buf_count = 0;
+ m_inp_act_buf_count = 0;
+ m_inp_bEnabled = OMX_FALSE;
+ m_out_bEnabled = OMX_FALSE;
+ m_inp_bPopulated = OMX_FALSE;
+ m_out_bPopulated = OMX_FALSE;
+ adif_flag = 0;
+ mp4ff_flag = 0;
+ ts = 0;
+ nTimestamp = 0;
+ frameduration = 0;
+ if ( m_drv_fd >= 0 )
+ {
+ if(close(m_drv_fd) < 0)
+ DEBUG_PRINT("De-init: Driver Close Failed \n");
+ m_drv_fd = -1;
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR(" AAC device already closed\n");
+ }
+ m_comp_deinit=1;
+ m_is_out_th_sleep = 1;
+ m_is_in_th_sleep = 1;
+ DEBUG_PRINT("************************************\n");
+ DEBUG_PRINT(" DEINIT COMPLETED");
+ DEBUG_PRINT("************************************\n");
+
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::UseEGLImage
+
+DESCRIPTION
+ OMX Use EGL Image method implementation <TBD>.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Not Implemented error.
+
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::use_EGL_image
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN void* eglImage)
+{
+ DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n");
+
+ if((hComp == NULL) || (appData == NULL) || (eglImage == NULL))
+ {
+ bufferHdr = NULL;
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::ComponentRoleEnum
+
+DESCRIPTION
+ OMX Component Role Enum method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_aac_aenc::component_role_enum(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_U8* role,
+ OMX_IN OMX_U32 index)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ const char *cmp_role = "audio_encoder.aac";
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (index == 0 && role)
+ {
+ memcpy(role, cmp_role, sizeof(cmp_role));
+ *(((char *) role) + sizeof(cmp_role)) = '\0';
+ } else
+ {
+ eRet = OMX_ErrorNoMore;
+ }
+ return eRet;
+}
+
+
+
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::AllocateDone
+
+DESCRIPTION
+ Checks if entire buffer pool is allocated by IL Client or not.
+ Need this to move to IDLE state.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false.
+
+========================================================================== */
+bool omx_aac_aenc::allocate_done(void)
+{
+ OMX_BOOL bRet = OMX_FALSE;
+ if (pcm_input==1)
+ {
+ if ((m_inp_act_buf_count == m_inp_current_buf_count)
+ &&(m_out_act_buf_count == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled )
+ {
+ m_inp_bPopulated = OMX_TRUE;
+ }
+
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+ } else if (pcm_input==0)
+ {
+ if (m_out_act_buf_count == m_out_current_buf_count)
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+
+ }
+ return bRet;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_aac_aenc::ReleaseDone
+
+DESCRIPTION
+ Checks if IL client has released all the buffers.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+bool omx_aac_aenc::release_done(OMX_U32 param1)
+{
+ DEBUG_PRINT("Inside omx_aac_aenc::release_done");
+ OMX_BOOL bRet = OMX_FALSE;
+
+ if (param1 == OMX_ALL)
+ {
+
+ if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_INPUT_PORT_INDEX )
+ {
+ if ((0 == m_inp_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ if ((0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ }
+ return bRet;
+}
+
+void omx_aac_aenc::audaac_rec_install_adif_header_variable (OMX_U16 byte_num,
+ OMX_U32 sample_index,
+ OMX_U8 channel_config)
+{
+ OMX_U8 buf8;
+ OMX_U32 value;
+ OMX_U32 dummy = 0;
+ OMX_U8 num_pfe, num_fce, num_sce, num_bce;
+ OMX_U8 num_lfe, num_ade, num_vce, num_com;
+ OMX_U8 pfe_index;
+ OMX_U8 i;
+ OMX_BOOL variable_bit_rate = OMX_FALSE;
+
+ (void)byte_num;
+ (void)channel_config;
+ num_pfe = num_sce = num_bce =
+ num_lfe = num_ade = num_vce = num_com = 0;
+ audaac_hdr_bit_index = 32;
+ num_fce = 1;
+ /* Store Header Id "ADIF" first */
+ memcpy(&audaac_header_adif[0], "ADIF", sizeof(OMX_U32));
+
+ /* copyright_id_present field, 1 bit */
+ value = 0;
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_COPYRIGHT_PRESENT_SIZE,
+ value,
+ &(audaac_hdr_bit_index));
+
+ if (value) {
+ /* Copyright present, 72 bits; skip it for now,
+ * just install dummy value */
+ audaac_rec_install_bits(audaac_header_adif,
+ 72,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ /* original_copy field, 1 bit */
+ value = 0;
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_ORIGINAL_COPY_SIZE,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ /* home field, 1 bit */
+ value = 0;
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_HOME_SIZE,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ /* bitstream_type = 1, varibable bit rate, 1 bit */
+ value = 0;
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_BITSTREAM_TYPE_SIZE,
+ value,
+ &(audaac_hdr_bit_index));
+
+ /* bit_rate field, 23 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_BITRATE_SIZE,
+ (OMX_U32)m_aac_param.nBitRate,
+ &(audaac_hdr_bit_index));
+
+ /* num_program_config_elements, 4 bits */
+ num_pfe = 0;
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_PFE_SIZE,
+ (OMX_U32)num_pfe,
+ &(audaac_hdr_bit_index));
+
+ /* below is to install program_config_elements field,
+ * for now only one element is supported */
+ for (pfe_index=0; pfe_index < num_pfe+1; pfe_index++) {
+
+
+ if (variable_bit_rate == OMX_FALSE) {
+ /* impossible, put dummy value for now */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_BUFFER_FULLNESS_SIZE,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ }
+
+ dummy = 0;
+
+ /* element_instance_tag field, 4 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_ELEMENT_INSTANCE_TAG_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ /* object_type, 2 bits, AAC LC is supported */
+ value = 1;
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_PROFILE_SIZE, /* object type */
+ value,
+ &(audaac_hdr_bit_index));
+
+ /* sampling_frequency_index, 4 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_SAMPLING_FREQ_INDEX_SIZE,
+ (OMX_U32)sample_index,
+ &(audaac_hdr_bit_index));
+
+ /* num_front_channel_elements, 4 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_FRONT_CHANNEL_ELEMENTS_SIZE,
+ num_fce,
+ &(audaac_hdr_bit_index));
+
+ /* num_side_channel_elements, 4 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_SIDE_CHANNEL_ELEMENTS_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ /* num_back_channel_elements, 4 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_BACK_CHANNEL_ELEMENTS_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ /* num_lfe_channel_elements, 2 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_LFE_CHANNEL_ELEMENTS_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ /* num_assoc_data_elements, 3 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_ASSOC_DATA_ELEMENTS_SIZE,
+ num_ade,
+ &(audaac_hdr_bit_index));
+
+ /* num_valid_cc_elements, 4 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_NUM_VALID_CC_ELEMENTS_SIZE,
+ num_vce,
+ &(audaac_hdr_bit_index));
+
+ /* mono_mixdown_present, 1 bits */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_MONO_MIXDOWN_PRESENT_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ if (dummy) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_MONO_MIXDOWN_ELEMENT_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ /* stereo_mixdown_present */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_STEREO_MIXDOWN_PRESENT_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ if (dummy) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_STEREO_MIXDOWN_ELEMENT_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ /* matrix_mixdown_idx_present, 1 bit */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_MATRIX_MIXDOWN_PRESENT_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+
+ if (dummy) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_MATRIX_MIXDOWN_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+ if(m_aac_param.nChannels == 2)
+ value = 16;
+ else
+ value = 0;
+ for (i=0; i<num_fce; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_FCE_SIZE,
+ value,
+ &(audaac_hdr_bit_index));
+ }
+
+ for (i=0; i<num_sce; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_SCE_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ for (i=0; i<num_bce; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_BCE_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ for (i=0; i<num_lfe; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_LFE_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ for (i=0; i<num_ade; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_ADE_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ for (i=0; i<num_vce; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_VCE_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ /* byte_alignment() */
+ buf8 = (OMX_U8)((audaac_hdr_bit_index) & (0x07));
+ if (buf8) {
+ audaac_rec_install_bits(audaac_header_adif,
+ buf8,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+ /* comment_field_bytes, 8 bits,
+ * skip the comment section */
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_COMMENT_FIELD_BYTES_SIZE,
+ num_com,
+ &(audaac_hdr_bit_index));
+
+ for (i=0; i<num_com; i++) {
+ audaac_rec_install_bits(audaac_header_adif,
+ AAC_COMMENT_FIELD_DATA_SIZE,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+ } /* for (pfe_index=0; pfe_index < num_pfe+1; pfe_index++) */
+
+ /* byte_alignment() */
+ buf8 = (OMX_U8)((audaac_hdr_bit_index) & (0x07)) ;
+ if (buf8) {
+ audaac_rec_install_bits(audaac_header_adif,
+ buf8,
+ dummy,
+ &(audaac_hdr_bit_index));
+ }
+
+}
+
+void omx_aac_aenc::audaac_rec_install_bits(OMX_U8 *input,
+ OMX_U8 num_bits_reqd,
+ OMX_U32 value,
+ OMX_U16 *hdr_bit_index)
+{
+ OMX_U32 byte_index;
+ OMX_U8 bit_index;
+ OMX_U8 bits_avail_in_byte;
+ OMX_U8 num_to_copy;
+ OMX_U8 byte_to_copy;
+
+ OMX_U8 num_remaining = num_bits_reqd;
+ OMX_U8 bit_mask;
+
+ bit_mask = 0xFF;
+
+ while (num_remaining) {
+
+ byte_index = (*hdr_bit_index) >> 3;
+ bit_index = (*hdr_bit_index) & 0x07;
+
+ bits_avail_in_byte = 8 - bit_index;
+
+ num_to_copy = min(bits_avail_in_byte, num_remaining);
+
+ byte_to_copy = ((OMX_U8)((value >> (num_remaining - num_to_copy)) & 0xFF) <<
+ (bits_avail_in_byte - num_to_copy));
+
+ input[byte_index] &= ((OMX_U8)(bit_mask << bits_avail_in_byte));
+ input[byte_index] |= byte_to_copy;
+
+ *hdr_bit_index += num_to_copy;
+
+ num_remaining -= num_to_copy;
+ }
+}
+void omx_aac_aenc::audaac_rec_install_mp4ff_header_variable (OMX_U16 byte_num,
+ OMX_U32 sample_index,
+ OMX_U8 channel_config)
+{
+ OMX_U16 audaac_hdr_bit_index;
+ (void)byte_num;
+ audaac_header_mp4ff[0] = 0;
+ audaac_header_mp4ff[1] = 0;
+ audaac_hdr_bit_index = 0;
+
+ /* Audio object type, 5 bit */
+ audaac_rec_install_bits(audaac_header_mp4ff,
+ AUDAAC_MP4FF_OBJ_TYPE,
+ 2,
+ &(audaac_hdr_bit_index));
+
+ /* Frequency index, 4 bit */
+ audaac_rec_install_bits(audaac_header_mp4ff,
+ AUDAAC_MP4FF_FREQ_IDX,
+ (OMX_U32)sample_index,
+ &(audaac_hdr_bit_index));
+
+ /* Channel config filed, 4 bit */
+ audaac_rec_install_bits(audaac_header_mp4ff,
+ AUDAAC_MP4FF_CH_CONFIG,
+ channel_config,
+ &(audaac_hdr_bit_index));
+
+}
+
diff --git a/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c b/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c
new file mode 100644
index 0000000..c3e4b0a
--- /dev/null
+++ b/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c
@@ -0,0 +1,1289 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include<unistd.h>
+#include<string.h>
+#include <pthread.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+#include <linux/ioctl.h>
+
+typedef unsigned char uint8;
+typedef unsigned char byte;
+typedef unsigned int uint32;
+typedef unsigned int uint16;
+#define AUDAAC_MAX_ADIF_HEADER_LENGTH 64
+/* ADTS variable frame header, frame length field */
+#define AUDAAC_ADTS_FRAME_LENGTH_SIZE 13
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+void audaac_rec_install_bits
+(
+ uint8 *input,
+ byte num_bits_reqd,
+ uint32 value,
+ uint16 *hdr_bit_index
+);
+
+/* maximum ADTS frame header length */
+#define AUDAAC_MAX_ADTS_HEADER_LENGTH 7
+void audaac_rec_install_adts_header_variable (uint16 byte_num);
+void Release_Encoder();
+
+#ifdef AUDIOV2
+unsigned short session_id;
+int device_id;
+int control = 0;
+const char *device="handset_tx";
+#define DIR_TX 2
+#endif
+
+#define AACHDR_LAYER_SIZE 2
+#define AACHDR_CRC_SIZE 1
+#define AAC_PROFILE_SIZE 2
+#define AAC_SAMPLING_FREQ_INDEX_SIZE 4
+#define AAC_ORIGINAL_COPY_SIZE 1
+#define AAC_HOME_SIZE 1
+
+#define MIN(A,B) (((A) < (B))?(A):(B))
+
+uint8 audaac_header[AUDAAC_MAX_ADTS_HEADER_LENGTH];
+unsigned int audaac_hdr_bit_index;
+
+
+FILE *F1 = NULL;
+
+uint32_t samplerate = 44100;
+uint32_t channels = 2;
+uint32_t bitrate = 128000;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t rectime = -1;
+uint32_t format = 1;
+uint32_t profile = OMX_AUDIO_AACObjectLC;
+#define DEBUG_PRINT printf
+unsigned to_idle_transition = 0;
+
+typedef enum adts_sample_index__ {
+
+ADTS_SAMPLE_INDEX_96000=0x0,
+ADTS_SAMPLE_INDEX_88200,
+ADTS_SAMPLE_INDEX_64000,
+ADTS_SAMPLE_INDEX_48000,
+ADTS_SAMPLE_INDEX_44100,
+ADTS_SAMPLE_INDEX_32000,
+ADTS_SAMPLE_INDEX_24000,
+ADTS_SAMPLE_INDEX_22050,
+ADTS_SAMPLE_INDEX_16000,
+ADTS_SAMPLE_INDEX_12000,
+ADTS_SAMPLE_INDEX_11025,
+ADTS_SAMPLE_INDEX_8000,
+ADTS_SAMPLE_INDEX_7350,
+ADTS_SAMPLE_INDEX_MAX
+
+}adts_sample_index;
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+pthread_mutex_t lock;
+pthread_cond_t cond;
+pthread_mutex_t elock;
+pthread_cond_t econd;
+pthread_cond_t fcond;
+pthread_mutex_t etb_lock;
+pthread_mutex_t etb_lock1;
+pthread_cond_t etb_cond;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+OMX_AUDIO_PARAM_AACPROFILETYPE aacparam;
+OMX_AUDIO_PARAM_PCMMODETYPE pcmparam;
+OMX_PORT_PARAM_TYPE portParam;
+OMX_ERRORTYPE error;
+
+
+
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+struct enc_meta_out{
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+} __attribute__ ((packed));
+
+static unsigned totaldatalen = 0;
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+volatile int etb_event_is_done = 0;
+int ebd_cnt;
+int bInputEosReached = 0;
+int bOutputEosReached = 0;
+int bInputEosReached_tunnel = 0;
+static int etb_done = 0;
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+const char *out_filename;
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* aac_enc_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Encoder(char*);
+int Play_Encoder();
+OMX_STRING aud_comp;
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *aac_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE parse_pcm_header();
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock1);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock1);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock1);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+
+ switch(eEvent) {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent,
+ nData1,nData2);
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("\n OMX_EventError \n");
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("\n OMX_EventBufferFlag \n");
+ bOutputEosReached = true;
+ event_complete();
+ break;
+ case OMX_EventPortSettingsChanged:
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ size_t bytes_writen = 0;
+ int total_bytes_writen = 0;
+ unsigned int len = 0;
+ struct enc_meta_out *meta = NULL;
+ OMX_U8 *src = pBuffer->pBuffer;
+ unsigned int num_of_frames = 1;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) {
+ DEBUG_PRINT("FBD::EOS on output port\n ");
+ bOutputEosReached = true;
+ return OMX_ErrorNone;
+ }
+ if(bInputEosReached_tunnel || bOutputEosReached)
+ {
+ DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n");
+ return OMX_ErrorNone;
+ }
+ if(num_of_frames != src[0]){
+
+ printf("Data corrupt\n");
+ return OMX_ErrorNone;
+ }
+ /* Skip the first bytes */
+
+
+
+ src += sizeof(unsigned char);
+ meta = (struct enc_meta_out *)src;
+ while (num_of_frames > 0) {
+ meta = (struct enc_meta_out *)src;
+ /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n",
+ meta->offset_to_frame,
+ meta->frame_size,
+ meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/
+ len = meta->frame_size;
+
+ if(format == 6)
+ {
+ audaac_rec_install_adts_header_variable(len + AUDAAC_MAX_ADTS_HEADER_LENGTH);
+ bytes_writen = fwrite(audaac_header,1,AUDAAC_MAX_ADTS_HEADER_LENGTH,outputBufferFile);
+ if(bytes_writen < AUDAAC_MAX_ADTS_HEADER_LENGTH)
+ {
+ DEBUG_PRINT("error: invalid adts header length\n");
+ return OMX_ErrorNone;
+ }
+ }
+ bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile);
+ if(bytes_writen < len)
+ {
+ DEBUG_PRINT("error: invalid AAC encoded data \n");
+ return OMX_ErrorNone;
+ }
+ src += sizeof(struct enc_meta_out);
+ num_of_frames--;
+ total_bytes_writen += len;
+ }
+ DEBUG_PRINT(" FillBufferDone size writen to file %d\n",total_bytes_writen);
+ totaldatalen += total_bytes_writen ;
+
+ DEBUG_PRINT(" FBD calling FTB\n");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock);
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock);
+ }
+
+
+ if(bInputEosReached)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }else if (bFlushing == true) {
+ DEBUG_PRINT("omx_aac_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (used_ip_buf_cnt == 0) {
+ bFlushing = false;
+ } else {
+ DEBUG_PRINT("omx_aac_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ return OMX_ErrorNone;
+ }
+ }
+
+ if((readBytes = Read_Buffer(pBuffer)) > 0) {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else{
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ bInputEosReached = true;
+ pBuffer->nFilledLen = 0;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id) {
+
+ /* Flush */
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(aac_enc_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ } else if (sig_id == SIGUSR2) {
+ if (bPause == true) {
+ DEBUG_PRINT("%s resume playback\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ } else {
+ DEBUG_PRINT("%s pause playback\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+ (void) signal(SIGINT, Release_Encoder);
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+
+ if (argc >= 9) {
+ in_filename = argv[1];
+ out_filename = argv[2];
+ samplerate = atoi(argv[3]);
+ channels = atoi(argv[4]);
+ tunnel = atoi(argv[5]);
+ rectime = atoi(argv[6]);
+ bitrate = atoi(argv[7]);
+ format = atoi(argv[8]);
+ profile = atoi(argv[9]);
+
+ DEBUG_PRINT("Input parameters: samplerate = %d, channels = %d, tunnel = %d,"
+ " rectime = %d, bitrate = %d, format = %d, profile = %d\n",
+ samplerate, channels, tunnel, rectime, bitrate, format, profile);
+
+ if (!((profile == 2) || (profile == 5) || (profile == 29))) {
+ DEBUG_PRINT("profile = %d, not supported. Supported "
+ "profile values are AAC_LC(2), AAC+(5), EAAC+(29)\n", profile);
+ return 0;
+ }
+ if (!((format == 1) || (format == 6))) {
+ DEBUG_PRINT("format = %d, not supported. Supported "
+ "formats are ADTS(1), RAW(6)\n", format);
+ return 0;
+ }
+ if ((channels > 2) || (channels <= 0)) {
+ DEBUG_PRINT("channels = %d, not supported. Supported "
+ "number of channels are 1 and 2\n", channels);
+ return 0;
+ }
+ if ((samplerate < 8000) && (samplerate > 48000)) {
+ DEBUG_PRINT("samplerate = %d, not supported, Supported "
+ "samplerates are 8000, 11025, 12000, 16000, 22050, "
+ "24000, 32000, 44100, 48000\n", samplerate);
+ return 0;
+ } else {
+ if ((profile == 5) || (profile == 29)) {
+ if (samplerate < 24000) {
+ DEBUG_PRINT("samplerate = %d, not supported for AAC+/EAAC+."
+ " Supported samplerates are 24000, 32000,"
+ " 44100, 48000\n", samplerate);
+ return 0;
+ }
+ }
+ }
+ } else {
+ DEBUG_PRINT(" invalid format: \n");
+ DEBUG_PRINT("ex: ./mm-aenc-omxaac INPUTFILE AAC_OUTPUTFILE SAMPFREQ CHANNEL TUNNEL RECORDTIME BITRATE FORMAT PROFILE\n");
+ DEBUG_PRINT("FOR TUNNEL MOD PASS INPUT FILE AS ZERO\n");
+ DEBUG_PRINT("RECORDTIME in seconds for AST Automation ...TUNNEL MODE ONLY\n");
+ DEBUG_PRINT("FORMAT::ADTS(1), RAW(6)\n");
+ DEBUG_PRINT("BITRATE in bits/sec \n");
+ DEBUG_PRINT("PROFILE::AAC_LC(2), AAC+(5), EAAC+(29)\n");
+ return 0;
+ }
+ if(tunnel == 0)
+ aud_comp = "OMX.qcom.audio.encoder.aac";
+ else
+ aud_comp = "OMX.qcom.audio.encoder.tunneled.aac";
+ if(Init_Encoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+
+ if(Play_Encoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+ if(rectime && tunnel)
+ {
+ sleep(rectime);
+ rectime = 0;
+ bInputEosReached_tunnel = 1;
+ DEBUG_PRINT("\EOS ON INPUT PORT\n");
+ }
+ else
+ {
+ wait_for_event();
+ }
+
+ if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel))
+ {
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+ DEBUG_PRINT("\nMoving the encoder to loaded state \n");
+ OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+ sleep(1);
+ if (!tunnel)
+ {
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(aac_enc_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ }
+
+ DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(aac_enc_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+ wait_for_event();
+
+ result = OMX_FreeHandle(aac_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+ /* Deinit OpenMAX */
+ if(tunnel)
+ {
+ #ifdef AUDIOV2
+ if (msm_route_stream(DIR_TX,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ #endif
+ }
+ OMX_Deinit();
+ ebd_cnt=0;
+ bOutputEosReached = false;
+ bInputEosReached_tunnel = false;
+ bInputEosReached = 0;
+ aac_enc_handle = NULL;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ fclose(outputBufferFile);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...AAC ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+ return 0;
+}
+
+void Release_Encoder()
+{
+ static int cnt=0;
+ OMX_ERRORTYPE result;
+
+ DEBUG_PRINT("END OF AAC ENCODING: EXITING PLEASE WAIT\n");
+ bInputEosReached_tunnel = 1;
+ event_complete();
+ cnt++;
+ if(cnt > 1)
+ {
+ /* FORCE RESET */
+ aac_enc_handle = NULL;
+ ebd_cnt=0;
+ bInputEosReached_tunnel = false;
+
+ result = OMX_FreeHandle(aac_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+
+ OMX_Deinit();
+
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...AAC ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ exit(0);
+ }
+}
+
+int Init_Encoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ typedef OMX_U8* OMX_U8_PTR;
+ char *role ="audio_encoder";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Aac_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total);
+
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&aac_enc_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component);
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(aac_enc_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+ return 0;
+}
+
+int Play_Encoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file()) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+
+ /* Query the encoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(aac_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Input Port\n");
+ return -1;
+ }
+
+ pcmparam.nPortIndex = 0;
+ pcmparam.nChannels = channels;
+ pcmparam.nSamplingRate = samplerate;
+ OMX_SetParameter(aac_enc_handle,OMX_IndexParamAudioPcm,&pcmparam);
+
+
+ /* Query the encoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(aac_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Output Port\n");
+ return -1;
+ }
+
+
+ CONFIG_VERSION_SIZE(aacparam);
+
+
+ aacparam.nPortIndex = 1;
+ aacparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/
+ aacparam.nBitRate = bitrate;
+ aacparam.nSampleRate = samplerate;
+ aacparam.eChannelMode = OMX_AUDIO_ChannelModeStereo;
+ aacparam.eAACStreamFormat = (OMX_AUDIO_AACSTREAMFORMATTYPE)format;
+ aacparam.eAACProfile = (OMX_AUDIO_AACPROFILETYPE)profile;
+ OMX_SetParameter(aac_enc_handle,OMX_IndexParamAudioAac,&aacparam);
+ OMX_GetExtensionIndex(aac_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(aac_enc_handle,index,&streaminfoparam);
+ if(tunnel)
+ {
+ #ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+
+ if (msm_route_stream(DIR_TX,session_id,device_id, 1))
+ {
+ perror("could not set stream routing\n");
+ return -1;
+ }
+ #endif
+ }
+ DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n");
+ OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+ if (tunnel == 0)
+ {
+ input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(aac_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pInputBufHdrs == NULL) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+ }
+ output_buf_cnt = outputportFmt.nBufferCountMin ;
+
+ /* Allocate buffer on encoder's O/Pp port */
+ error = Allocate_Buffer(aac_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pOutputBufHdrs == NULL) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+
+ if (tunnel == 1)
+ {
+ DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n");
+ OMX_SendCommand(aac_enc_handle, OMX_CommandPortDisable,0,0); // disable input port
+ wait_for_event();
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n");
+ OMX_SendCommand(aac_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(aac_enc_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+if(tunnel == 0)
+{
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++) {
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ bInputEosReached = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ ret = OMX_EmptyThisBuffer(aac_enc_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock);
+ if(etb_done)
+{
+ DEBUG_PRINT("Component is waiting for EBD to be released.\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock);
+}
+
+ return 0;
+}
+
+
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_enc_handle;
+
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(aac_enc_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+
+
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+
+ int bytes_read=0;
+
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile);
+
+ pBufHdr->nFilledLen = bytes_read;
+ if(bytes_read == 0)
+ {
+
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ }
+
+ return bytes_read;;
+}
+
+
+
+//In Encoder this Should Open a PCM or WAV file for input.
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+
+ if (!tunnel)
+ {
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ }
+ if(parse_pcm_header() != 0x00)
+ {
+ DEBUG_PRINT("PCM parser failed \n");
+ return -1;
+ }
+ }
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename);
+ outputBufferFile = fopen (out_filename, "wb");
+ if (outputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ out_filename);
+ error_code = -1;
+ }
+ return error_code;
+}
+
+
+void audaac_rec_install_bits
+(
+ uint8 *input,
+ byte num_bits_reqd,
+ uint32 value,
+ uint16 *hdr_bit_index
+)
+{
+ uint32 byte_index;
+ byte bit_index;
+ byte bits_avail_in_byte;
+ byte num_to_copy;
+ byte byte_to_copy;
+
+ byte num_remaining = num_bits_reqd;
+ uint8 bit_mask;
+
+ bit_mask = 0xFF;
+
+ while (num_remaining) {
+
+ byte_index = (*hdr_bit_index) >> 3;
+ bit_index = (*hdr_bit_index) & 0x07;
+
+ bits_avail_in_byte = 8 - bit_index;
+
+ num_to_copy = MIN(bits_avail_in_byte, num_remaining);
+
+ byte_to_copy = ((uint8)((value >> (num_remaining - num_to_copy)) & 0xFF) <<
+ (bits_avail_in_byte - num_to_copy));
+
+ input[byte_index] &= ((uint8)(bit_mask << bits_avail_in_byte));
+ input[byte_index] |= byte_to_copy;
+
+ *hdr_bit_index += num_to_copy;
+
+ num_remaining -= num_to_copy;
+ } /* while (num_remaining) */
+} /* audaac_rec_install_bits */
+
+adts_sample_index map_adts_sample_index(uint32 srate)
+{
+ adts_sample_index ret;
+
+ switch(srate){
+
+ case 96000:
+ ret= ADTS_SAMPLE_INDEX_96000;
+ break;
+ case 88200:
+ ret= ADTS_SAMPLE_INDEX_88200;
+ break;
+ case 64000:
+ ret= ADTS_SAMPLE_INDEX_64000;
+ break;
+ case 48000:
+ ret=ADTS_SAMPLE_INDEX_48000;
+ break;
+ case 44100:
+ ret=ADTS_SAMPLE_INDEX_44100;
+ break;
+ case 32000:
+ ret=ADTS_SAMPLE_INDEX_32000;
+ break;
+ case 24000:
+ ret=ADTS_SAMPLE_INDEX_24000;
+ break;
+ case 22050:
+ ret=ADTS_SAMPLE_INDEX_22050;
+ break;
+ case 16000:
+ ret=ADTS_SAMPLE_INDEX_16000;
+ break;
+ case 12000:
+ ret=ADTS_SAMPLE_INDEX_12000;
+ break;
+ case 11025:
+ ret=ADTS_SAMPLE_INDEX_11025;
+ break;
+ case 8000:
+ ret=ADTS_SAMPLE_INDEX_8000;
+ break;
+ case 7350:
+ ret=ADTS_SAMPLE_INDEX_7350;
+ break;
+ default:
+ ret=ADTS_SAMPLE_INDEX_44100;
+ break;
+ }
+ return ret;
+}
+
+void audaac_rec_install_adts_header_variable (uint16 byte_num)
+{
+ //uint16 bit_index=0;
+
+ adts_sample_index srate_enum;
+ uint32 value;
+
+ uint32 sample_index = samplerate;
+ uint8 channel_config = channels;
+
+ /* Store Sync word first */
+ audaac_header[0] = 0xFF;
+ audaac_header[1] = 0xF0;
+
+ audaac_hdr_bit_index = 12;
+
+ if ((format == OMX_AUDIO_AACStreamFormatRAW) &&
+ ((profile == OMX_AUDIO_AACObjectHE) ||
+ (profile == OMX_AUDIO_AACObjectHE_PS))){
+ if (samplerate >= 24000)
+ sample_index = samplerate/2;
+ }
+
+ /* ID field, 1 bit */
+ value = 1;
+ audaac_rec_install_bits(audaac_header,
+ 1,
+ value,
+ &(audaac_hdr_bit_index));
+
+ /* Layer field, 2 bits */
+ value = 0;
+ audaac_rec_install_bits(audaac_header,
+ AACHDR_LAYER_SIZE,
+ value,
+ &(audaac_hdr_bit_index));
+
+ /* Protection_absent field, 1 bit */
+ value = 1;
+ audaac_rec_install_bits(audaac_header,
+ AACHDR_CRC_SIZE,
+ value,
+ &(audaac_hdr_bit_index));
+
+ /* profile_ObjectType field, 2 bit */
+ value = 1;
+ audaac_rec_install_bits(audaac_header,
+ AAC_PROFILE_SIZE,
+ value,
+ &(audaac_hdr_bit_index));
+
+ /* sampling_frequency_index field, 4 bits */
+ srate_enum = map_adts_sample_index(sample_index);
+ audaac_rec_install_bits(audaac_header,
+ AAC_SAMPLING_FREQ_INDEX_SIZE,
+ (uint32)srate_enum,
+ &(audaac_hdr_bit_index));
+
+ DEBUG_PRINT("%s: sample_index=%d; srate_enum = %d \n",
+ __FUNCTION__, sample_index, srate_enum);
+
+ /* pravate_bit field, 1 bits */
+ audaac_rec_install_bits(audaac_header,
+ 1,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ /* channel_configuration field, 3 bits */
+ audaac_rec_install_bits(audaac_header,
+ 3,
+ channel_config,
+ &(audaac_hdr_bit_index));
+
+
+ /* original/copy field, 1 bits */
+ audaac_rec_install_bits(audaac_header,
+ AAC_ORIGINAL_COPY_SIZE,
+ 0,
+ &(audaac_hdr_bit_index));
+
+
+ /* home field, 1 bits */
+ audaac_rec_install_bits(audaac_header,
+ AAC_HOME_SIZE,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ // bit_index = audaac_hdr_bit_index;
+ // bit_index += 2;
+
+ /* copyr. id. bit, 1 bits */
+ audaac_rec_install_bits(audaac_header,
+ 1,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ /* copyr. id. start, 1 bits */
+ audaac_rec_install_bits(audaac_header,
+ 1,
+ 0,
+ &(audaac_hdr_bit_index));
+
+ /* aac_frame_length field, 13 bits */
+ audaac_rec_install_bits(audaac_header,
+ AUDAAC_ADTS_FRAME_LENGTH_SIZE,
+ byte_num,
+ &audaac_hdr_bit_index);
+
+ /* adts_buffer_fullness field, 11 bits */
+ audaac_rec_install_bits(audaac_header,
+ 11,
+ 0x660,/*0x660 = CBR,0x7FF = VBR*/
+ &audaac_hdr_bit_index);
+
+ /* number_of_raw_data_blocks_in_frame, 2 bits */
+ audaac_rec_install_bits(audaac_header,
+ 2,
+ 0,
+ &audaac_hdr_bit_index);
+
+} /* audaac_rec_install_adts_header_variable */
+
+static OMX_ERRORTYPE parse_pcm_header()
+{
+ struct wav_header hdr;
+
+ DEBUG_PRINT("\n***************************************************************\n");
+ if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr))
+ {
+ DEBUG_PRINT("Wav file cannot read header\n");
+ return -1;
+ }
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE)||
+ (hdr.fmt_id != ID_FMT))
+ {
+ DEBUG_PRINT("Wav file is not a riff/wave file\n");
+ return -1;
+ }
+
+ if (hdr.audio_format != FORMAT_PCM)
+ {
+ DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n",
+ hdr.audio_format, hdr.fmt_sz);
+ return -1;
+ }
+
+ DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate);
+ DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels);
+ DEBUG_PRINT("\n***************************************************************\n");
+
+ samplerate = hdr.sample_rate;
+ channels = hdr.num_channels;
+
+ return OMX_ErrorNone;
+}
diff --git a/mm-audio/aenc-amrnb/Android.mk b/mm-audio/aenc-amrnb/Android.mk
new file mode 100644
index 0000000..6c2f458
--- /dev/null
+++ b/mm-audio/aenc-amrnb/Android.mk
@@ -0,0 +1,26 @@
+ifeq ($(TARGET_ARCH),arm)
+
+
+AENC_AMR_PATH:= $(call my-dir)
+
+ifeq ($(call is-board-platform,msm8660),true)
+include $(AENC_AMR_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8960),true)
+include $(AENC_AMR_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8974),true)
+include $(AENC_AMR_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8226),true)
+include $(AENC_AMR_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8610),true)
+include $(AENC_AMR_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,apq8084),true)
+include $(AENC_AMR_PATH)/qdsp6/Android.mk
+endif
+
+
+endif
diff --git a/mm-audio/aenc-amrnb/Makefile b/mm-audio/aenc-amrnb/Makefile
new file mode 100644
index 0000000..83d822b
--- /dev/null
+++ b/mm-audio/aenc-amrnb/Makefile
@@ -0,0 +1,6 @@
+all:
+ @echo "invoking omxaudio make"
+ $(MAKE) -C qdsp6
+
+install:
+ $(MAKE) -C qdsp6 install
diff --git a/mm-audio/aenc-amrnb/qdsp6/Android.mk b/mm-audio/aenc-amrnb/qdsp6/Android.mk
new file mode 100644
index 0000000..b97e2e5
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/Android.mk
@@ -0,0 +1,76 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxAmrEnc-def := -g -O3
+libOmxAmrEnc-def += -DQC_MODIFIED
+libOmxAmrEnc-def += -D_ANDROID_
+libOmxAmrEnc-def += -D_ENABLE_QC_MSG_LOG_
+libOmxAmrEnc-def += -DVERBOSE
+libOmxAmrEnc-def += -D_DEBUG
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+libOmxAmrEnc-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the Shared library (libOmxAmrEnc)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+libOmxAmrEnc-inc := $(LOCAL_PATH)/inc
+libOmxAmrEnc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+
+LOCAL_MODULE := libOmxAmrEnc
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAmrEnc-def)
+LOCAL_C_INCLUDES := $(libOmxAmrEnc-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libutils liblog
+
+LOCAL_SRC_FILES := src/aenc_svr.c
+LOCAL_SRC_FILES += src/omx_amr_aenc.cpp
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+include $(BUILD_SHARED_LIBRARY)
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-aenc-omxamr-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+mm-amr-enc-test-inc := $(LOCAL_PATH)/inc
+mm-amr-enc-test-inc += $(LOCAL_PATH)/test
+
+mm-amr-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+mm-amr-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+endif
+LOCAL_MODULE := mm-aenc-omxamr-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxAmrEnc-def)
+LOCAL_C_INCLUDES := $(mm-amr-enc-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libmm-omxcore
+LOCAL_SHARED_LIBRARIES += libOmxAmrEnc
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+endif
+LOCAL_SRC_FILES := test/omx_amr_enc_test.c
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
+
diff --git a/mm-audio/aenc-amrnb/qdsp6/Makefile b/mm-audio/aenc-amrnb/qdsp6/Makefile
new file mode 100644
index 0000000..0abd31c
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/Makefile
@@ -0,0 +1,81 @@
+# ---------------------------------------------------------------------------------
+# MM-AUDIO-OSS-8K-AENC-AMR
+# ---------------------------------------------------------------------------------
+
+# cross-compiler flags
+CFLAGS += -Wall
+CFLAGS += -Wundef
+CFLAGS += -Wstrict-prototypes
+CFLAGS += -Wno-trigraphs
+
+# cross-compile flags specific to shared objects
+CFLAGS_SO += -fpic
+
+# required pre-processor flags
+CPPFLAGS := -D__packed__=
+CPPFLAGS += -DIMAGE_APPS_PROC
+CPPFLAGS += -DFEATURE_Q_SINGLE_LINK
+CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR
+CPPFLAGS += -DFEATURE_LINUX
+CPPFLAGS += -DFEATURE_NATIVELINUX
+CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS
+
+CPPFLAGS += -g
+CPPFALGS += -D_DEBUG
+CPPFLAGS += -Iinc
+
+# linker flags
+LDFLAGS += -L$(SYSROOT)/usr/lib
+
+# linker flags for shared objects
+LDFLAGS_SO := -shared
+
+# defintions
+LIBMAJOR := $(basename $(basename $(LIBVER)))
+LIBINSTALLDIR := $(DESTDIR)usr/lib
+INCINSTALLDIR := $(DESTDIR)usr/include
+BININSTALLDIR := $(DESTDIR)usr/bin
+
+# ---------------------------------------------------------------------------------
+# BUILD
+# ---------------------------------------------------------------------------------
+all: libOmxAmrEnc.so.$(LIBVER) mm-aenc-omxamr-test
+
+install:
+ echo "intalling aenc-amr in $(DESTDIR)"
+ if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi
+ if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi
+ if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi
+ install -m 555 libOmxAmrEnc.so.$(LIBVER) $(LIBINSTALLDIR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxAmrEnc.so.$(LIBVER) libOmxAmrEnc.so.$(LIBMAJOR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxAmrEnc.so.$(LIBMAJOR) libOmxAmrEnc.so
+ install -m 555 mm-aenc-omxamr-test $(BININSTALLDIR)
+
+# ---------------------------------------------------------------------------------
+# COMPILE LIBRARY
+# ---------------------------------------------------------------------------------
+LDLIBS := -lpthread
+LDLIBS += -lstdc++
+LDLIBS += -lOmxCore
+
+SRCS := src/omx_amr_aenc.cpp
+SRCS += src/aenc_svr.c
+
+libOmxAmrEnc.so.$(LIBVER): $(SRCS)
+ $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxAmrEnc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# COMPILE TEST APP
+# ---------------------------------------------------------------------------------
+TEST_LDLIBS := -lpthread
+TEST_LDLIBS += -ldl
+TEST_LDLIBS += -lOmxCore
+
+TEST_SRCS := test/omx_amr_enc_test.c
+
+mm-aenc-omxamr-test: libOmxAmrEnc.so.$(LIBVER) $(TEST_SRCS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/aenc-amrnb/qdsp6/inc/Map.h b/mm-audio/aenc-amrnb/qdsp6/inc/Map.h
new file mode 100644
index 0000000..aac96fd
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/inc/Map.h
@@ -0,0 +1,244 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdio.h>
+using namespace std;
+
+template <typename T,typename T2>
+class Map
+{
+ struct node
+ {
+ T data;
+ T2 data2;
+ node* prev;
+ node* next;
+ node(T t, T2 t2,node* p, node* n) :
+ data(t), data2(t2), prev(p), next(n) {}
+ };
+ node* head;
+ node* tail;
+ node* tmp;
+ unsigned size_of_list;
+ static Map<T,T2> *m_self;
+public:
+ Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {}
+ bool empty() const { return ( !head || !tail ); }
+ operator bool() const { return !empty(); }
+ void insert(T,T2);
+ void show();
+ int size();
+ T2 find(T); // Return VALUE
+ T find_ele(T);// Check if the KEY is present or not
+ T2 begin(); //give the first ele
+ bool erase(T);
+ bool eraseall();
+ bool isempty();
+ ~Map()
+ {
+ while(head)
+ {
+ node* temp(head);
+ head=head->next;
+ size_of_list--;
+ delete temp;
+ }
+ }
+};
+
+template <typename T,typename T2>
+T2 Map<T,T2>::find(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data2;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T Map<T,T2>::find_ele(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T2 Map<T,T2>::begin()
+{
+ tmp = head;
+ if(tmp)
+ {
+ return (tmp->data2);
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::show()
+{
+ tmp = head;
+ while(tmp)
+ {
+ printf("%d-->%d\n",tmp->data,tmp->data2);
+ tmp = tmp->next;
+ }
+}
+
+template <typename T,typename T2>
+int Map<T,T2>::size()
+{
+ int count =0;
+ tmp = head;
+ while(tmp)
+ {
+ tmp = tmp->next;
+ count++;
+ }
+ return count;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::insert(T data, T2 data2)
+{
+ tail = new node(data, data2,tail, NULL);
+ if( tail->prev )
+ tail->prev->next = tail;
+
+ if( empty() )
+ {
+ head = tail;
+ tmp=head;
+ }
+ tmp = head;
+ size_of_list++;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::erase(T d)
+{
+ bool found = false;
+ tmp = head;
+ node* prevnode = tmp;
+ node *tempnode;
+
+ while(tmp)
+ {
+ if((head == tail) && (head->data == d))
+ {
+ found = true;
+ tempnode = head;
+ head = tail = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp ==head) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ tmp = tmp->next;
+ tmp->prev = NULL;
+ head = tmp;
+ tempnode->next = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp == tail) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ prevnode->next = NULL;
+ tmp->prev = NULL;
+ tail = prevnode;
+ delete tempnode;
+ break;
+ }
+ if(tmp->data == d)
+ {
+ found = true;
+ prevnode->next = tmp->next;
+ tmp->next->prev = prevnode->next;
+ tempnode = tmp;
+ //tmp = tmp->next;
+ delete tempnode;
+ break;
+ }
+ prevnode = tmp;
+ tmp = tmp->next;
+ }
+ if(found)size_of_list--;
+ return found;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::eraseall()
+{
+ // Be careful while using this method
+ // it not only removes the node but FREES(not delete) the allocated
+ // memory.
+ node *tempnode;
+ tmp = head;
+ while(head)
+ {
+ tempnode = head;
+ head = head->next;
+ tempnode->next = NULL;
+ if(tempnode->data)
+ free(tempnode->data);
+ if(tempnode->data2)
+ free(tempnode->data2);
+ delete tempnode;
+ }
+ tail = head = NULL;
+ return true;
+}
+
+
+template <typename T,typename T2>
+bool Map<T,T2>::isempty()
+{
+ if(!size_of_list) return true;
+ else return false;
+}
+
+#endif // _MAP_H_
diff --git a/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h
new file mode 100644
index 0000000..782641b
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h
@@ -0,0 +1,120 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef AENC_SVR_H
+#define AENC_SVR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <pthread.h>
+#include <sched.h>
+#include <utils/Log.h>
+
+#ifdef _ANDROID_
+#define LOG_TAG "QC_AMRENC"
+#endif
+
+#ifndef LOGE
+#define LOGE ALOGE
+#endif
+
+#ifndef LOGW
+#define LOGW ALOGW
+#endif
+
+#ifndef LOGD
+#define LOGD ALOGD
+#endif
+
+#ifndef LOGV
+#define LOGV ALOGV
+#endif
+
+#ifndef LOGI
+#define LOGI ALOGI
+#endif
+
+#define DEBUG_PRINT_ERROR LOGE
+#define DEBUG_PRINT LOGI
+#define DEBUG_DETAIL LOGV
+
+typedef void (*message_func)(void* client_data, unsigned char id);
+
+/**
+ @brief audio encoder ipc info structure
+
+ */
+struct amr_ipc_info
+{
+ pthread_t thr;
+ int pipe_in;
+ int pipe_out;
+ int dead;
+ message_func process_msg_cb;
+ void *client_data;
+ char thread_name[128];
+};
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to command server
+ */
+struct amr_ipc_info *omx_amr_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+
+struct amr_ipc_info *omx_amr_event_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+/**
+ @brief This function stop command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_amr_thread_stop(struct amr_ipc_info *amr_ipc);
+
+
+/**
+ @brief This function post message in the command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_amr_post_msg(struct amr_ipc_info *amr_ipc,
+ unsigned char id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AENC_SVR */
diff --git a/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h b/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h
new file mode 100644
index 0000000..4b89765
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h
@@ -0,0 +1,538 @@
+/*--------------------------------------------------------------------------
+
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _AMR_ENC_H_
+#define _AMR_ENC_H_
+/*============================================================================
+ Audio Encoder
+
+@file omx_amr_aenc.h
+This module contains the class definition for openMAX encoder component.
+
+
+
+============================================================================*/
+
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see
+ * all DEBUG_PRINT or LOGV messaging */
+#include<stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#include "OMX_Core.h"
+#include "OMX_Audio.h"
+#include "aenc_svr.h"
+#include "qc_omx_component.h"
+#include "Map.h"
+#include <semaphore.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_amrnb.h>
+extern "C" {
+ void * get_omx_component_factory_fn(void);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Module specific globals
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+#define OMX_SPEC_VERSION 0x00000101
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (x >= y?x:y)
+
+//////////////////////////////////////////////////////////////////////////////
+// Macros
+//////////////////////////////////////////////////////////////////////////////
+//
+
+
+#define PrintFrameHdr(i,bufHdr) \
+ DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\
+ i,\
+ (unsigned) bufHdr, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\
+ ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags)
+
+
+// BitMask Management logic
+#define BITS_PER_BYTE 8
+#define BITMASK_SIZE(mIndex) \
+ (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE)
+#define BITMASK_OFFSET(mIndex)\
+ ((mIndex)/BITS_PER_BYTE)
+#define BITMASK_FLAG(mIndex) \
+ (1 << ((mIndex) % BITS_PER_BYTE))
+#define BITMASK_CLEAR(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex))
+#define BITMASK_SET(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex)
+#define BITMASK_PRESENT(mArray,mIndex)\
+ ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex))
+#define BITMASK_ABSENT(mArray,mIndex)\
+ (((mArray)[BITMASK_OFFSET(mIndex)] & \
+ BITMASK_FLAG(mIndex)) == 0x0)
+
+#define OMX_CORE_NUM_INPUT_BUFFERS 2
+#define OMX_CORE_NUM_OUTPUT_BUFFERS 16
+
+#define OMX_CORE_INPUT_BUFFER_SIZE 8160 // Multiple of 160
+#define OMX_CORE_CONTROL_CMDQ_SIZE 100
+#define OMX_AENC_VOLUME_STEP 0x147
+#define OMX_AENC_MIN 0
+#define OMX_AENC_MAX 100
+#define NON_TUNNEL 1
+#define TUNNEL 0
+#define IP_PORT_BITMASK 0x02
+#define OP_PORT_BITMASK 0x01
+#define IP_OP_PORT_BITMASK 0x03
+
+#define OMX_AMR_DEFAULT_SF 8000
+#define OMX_AMR_DEFAULT_CH_CFG 1
+#define OMX_AMR_DEFAULT_VOL 25
+// 14 bytes for input meta data
+#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14)
+
+#define TRUE 1
+#define FALSE 0
+
+#define NUMOFFRAMES 1
+#define MAXFRAMELENGTH 32
+#define OMX_AMR_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT) + MAXFRAMELENGTH) \
+ + 1))
+#define FRAMEDURATION 20000
+
+class omx_amr_aenc;
+
+// OMX AMR audio encoder class
+class omx_amr_aenc: public qc_omx_component
+{
+public:
+ omx_amr_aenc(); // constructor
+ virtual ~omx_amr_aenc(); // destructor
+
+ OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+
+ OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp);
+
+ OMX_ERRORTYPE component_init(OMX_STRING role);
+
+ OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp,
+ OMX_U8 *role,
+ OMX_U32 index);
+
+ OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_HANDLETYPE peerComponent,
+ OMX_U32 peerPort,
+ OMX_TUNNELSETUPTYPE *tunnelSetup);
+
+ OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp,
+ OMX_STRING componentName,
+ OMX_VERSIONTYPE *componentVersion,
+ OMX_VERSIONTYPE * specVersion,
+ OMX_UUIDTYPE *componentUUID);
+
+ OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp,
+ OMX_STRING paramName,
+ OMX_INDEXTYPE *indexType);
+
+ OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp,
+ OMX_STATETYPE *state);
+
+ static void process_in_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_out_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_command_msg(void *client_data,
+ unsigned char id);
+
+ static void process_event_cb(void *client_data,
+ unsigned char id);
+
+
+ OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp,
+ OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData);
+
+ OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes,
+ OMX_U8 *buffer);
+
+ OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ void * eglImage);
+
+ bool post_command(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ // Deferred callback identifiers
+ enum
+ {
+ //Event Callbacks from the component thread context
+ OMX_COMPONENT_GENERATE_EVENT = 0x1,
+ //Buffer Done callbacks from component thread context
+ OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2,
+ OMX_COMPONENT_GENERATE_ETB = 0x3,
+ //Command
+ OMX_COMPONENT_GENERATE_COMMAND = 0x4,
+ OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05,
+ OMX_COMPONENT_GENERATE_FTB = 0x06,
+ OMX_COMPONENT_GENERATE_EOS = 0x07,
+ OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08,
+ OMX_COMPONENT_SUSPEND = 0x09,
+ OMX_COMPONENT_RESUME = 0x0a
+ };
+private:
+
+ ///////////////////////////////////////////////////////////
+ // Type definitions
+ ///////////////////////////////////////////////////////////
+ // Bit Positions
+ enum flags_bit_positions
+ {
+ // Defer transition to IDLE
+ OMX_COMPONENT_IDLE_PENDING =0x1,
+ // Defer transition to LOADING
+ OMX_COMPONENT_LOADING_PENDING =0x2,
+
+ OMX_COMPONENT_MUTED =0x3,
+
+ // Defer transition to Enable
+ OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4,
+ // Defer transition to Enable
+ OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5,
+ // Defer transition to Disable
+ OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6,
+ // Defer transition to Disable
+ OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7
+ };
+
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ input_buffer_map;
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ output_buffer_map;
+
+ enum port_indexes
+ {
+ OMX_CORE_INPUT_PORT_INDEX =0,
+ OMX_CORE_OUTPUT_PORT_INDEX =1
+ };
+
+ struct omx_event
+ {
+ unsigned param1;
+ unsigned param2;
+ unsigned id;
+ };
+
+ struct omx_cmd_queue
+ {
+ omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE];
+ unsigned m_read;
+ unsigned m_write;
+ unsigned m_size;
+
+ omx_cmd_queue();
+ ~omx_cmd_queue();
+ bool insert_entry(unsigned p1, unsigned p2, unsigned id);
+ bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id);
+ bool get_msg_id(unsigned *id);
+ bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id);
+ };
+
+ typedef struct TIMESTAMP
+ {
+ unsigned long LowPart;
+ unsigned long HighPart;
+ }__attribute__((packed)) TIMESTAMP;
+
+ typedef struct metadata_input
+ {
+ unsigned short offsetVal;
+ TIMESTAMP nTimeStamp;
+ unsigned int nFlags;
+ }__attribute__((packed)) META_IN;
+
+ typedef struct enc_meta_out
+ {
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+ } __attribute__ ((packed))ENC_META_OUT;
+
+ typedef struct
+ {
+ OMX_U32 tot_in_buf_len;
+ OMX_U32 tot_out_buf_len;
+ OMX_U32 tot_pb_time;
+ OMX_U32 fbd_cnt;
+ OMX_U32 ftb_cnt;
+ OMX_U32 etb_cnt;
+ OMX_U32 ebd_cnt;
+ }AMR_PB_STATS;
+
+ ///////////////////////////////////////////////////////////
+ // Member variables
+ ///////////////////////////////////////////////////////////
+ OMX_U8 *m_tmp_meta_buf;
+ OMX_U8 *m_tmp_out_meta_buf;
+ OMX_U8 m_flush_cnt ;
+ OMX_U8 m_comp_deinit;
+
+ // the below var doesnt hold good if combo of use and alloc bufs are used
+ OMX_S32 m_volume;//Unit to be determined
+ OMX_PTR m_app_data;// Application data
+ int nNumInputBuf;
+ int nNumOutputBuf;
+ int m_drv_fd; // Kernel device node file handle
+ bool bFlushinprogress;
+ bool is_in_th_sleep;
+ bool is_out_th_sleep;
+ unsigned int m_flags; //encapsulate the waiting states.
+ OMX_U64 nTimestamp;
+ OMX_U64 ts;
+ unsigned int pcm_input; //tunnel or non-tunnel
+ unsigned int m_inp_act_buf_count; // Num of Input Buffers
+ unsigned int m_out_act_buf_count; // Numb of Output Buffers
+ unsigned int m_inp_current_buf_count; // Num of Input Buffers
+ unsigned int m_out_current_buf_count; // Numb of Output Buffers
+ unsigned int output_buffer_size;
+ unsigned int input_buffer_size;
+ unsigned short m_session_id;
+ // store I/P PORT state
+ OMX_BOOL m_inp_bEnabled;
+ // store O/P PORT state
+ OMX_BOOL m_out_bEnabled;
+ //Input port Populated
+ OMX_BOOL m_inp_bPopulated;
+ //Output port Populated
+ OMX_BOOL m_out_bPopulated;
+ sem_t sem_States;
+ sem_t sem_read_msg;
+ sem_t sem_write_msg;
+
+ volatile int m_is_event_done;
+ volatile int m_is_in_th_sleep;
+ volatile int m_is_out_th_sleep;
+ input_buffer_map m_input_buf_hdrs;
+ output_buffer_map m_output_buf_hdrs;
+ omx_cmd_queue m_input_q;
+ omx_cmd_queue m_input_ctrl_cmd_q;
+ omx_cmd_queue m_input_ctrl_ebd_q;
+ omx_cmd_queue m_command_q;
+ omx_cmd_queue m_output_q;
+ omx_cmd_queue m_output_ctrl_cmd_q;
+ omx_cmd_queue m_output_ctrl_fbd_q;
+ pthread_mutexattr_t m_outputlock_attr;
+ pthread_mutexattr_t m_commandlock_attr;
+ pthread_mutexattr_t m_lock_attr;
+ pthread_mutexattr_t m_state_attr;
+ pthread_mutexattr_t m_flush_attr;
+ pthread_mutexattr_t m_in_th_attr_1;
+ pthread_mutexattr_t m_out_th_attr_1;
+ pthread_mutexattr_t m_event_attr;
+ pthread_mutexattr_t m_in_th_attr;
+ pthread_mutexattr_t m_out_th_attr;
+ pthread_mutexattr_t out_buf_count_lock_attr;
+ pthread_mutexattr_t in_buf_count_lock_attr;
+ pthread_cond_t cond;
+ pthread_cond_t in_cond;
+ pthread_cond_t out_cond;
+ pthread_mutex_t m_lock;
+ pthread_mutex_t m_commandlock;
+ pthread_mutex_t m_outputlock;
+ // Mutexes for state change
+ pthread_mutex_t m_state_lock;
+ // Mutexes for flush acks from input and output threads
+ pthread_mutex_t m_flush_lock;
+ pthread_mutex_t m_event_lock;
+ pthread_mutex_t m_in_th_lock;
+ pthread_mutex_t m_out_th_lock;
+ pthread_mutex_t m_in_th_lock_1;
+ pthread_mutex_t m_out_th_lock_1;
+ pthread_mutex_t out_buf_count_lock;
+ pthread_mutex_t in_buf_count_lock;
+
+ OMX_STATETYPE m_state; // OMX State
+ OMX_STATETYPE nState;
+ OMX_CALLBACKTYPE m_cb; // Application callbacks
+ AMR_PB_STATS m_amr_pb_stats;
+ struct amr_ipc_info *m_ipc_to_in_th; // for input thread
+ struct amr_ipc_info *m_ipc_to_out_th; // for output thread
+ struct amr_ipc_info *m_ipc_to_cmd_th; // for command thread
+ OMX_PRIORITYMGMTTYPE m_priority_mgm ;
+ OMX_AUDIO_PARAM_AMRTYPE m_amr_param; // Cache AMR encoder parameter
+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter
+ OMX_PARAM_COMPONENTROLETYPE component_Role;
+ OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier;
+
+ ///////////////////////////////////////////////////////////
+ // Private methods
+ ///////////////////////////////////////////////////////////
+ OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ bool allocate_done(void);
+
+ bool release_done(OMX_U32 param1);
+
+ bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true);
+
+ bool execute_input_omx_flush(void);
+
+ bool execute_output_omx_flush(void);
+
+ bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool post_input(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ bool post_output(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ void process_events(omx_amr_aenc *client_data);
+
+ void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void wait_for_event();
+
+ void event_complete();
+
+ void in_th_goto_sleep();
+
+ void in_th_wakeup();
+
+ void out_th_goto_sleep();
+
+ void out_th_wakeup();
+
+ void flush_ack();
+ void deinit_encoder();
+
+};
+#endif
diff --git a/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c b/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c
new file mode 100644
index 0000000..199358f
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c
@@ -0,0 +1,205 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <aenc_svr.h>
+
+/**
+ @brief This function processes posted messages
+
+ Once thread is being spawned, this function is run to
+ start processing commands posted by client
+
+ @param info pointer to context
+
+ */
+void *omx_amr_msg(void *info)
+{
+ struct amr_ipc_info *amr_info = (struct amr_ipc_info*)info;
+ unsigned char id;
+ int n;
+
+ DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__);
+ while (!amr_info->dead)
+ {
+ n = read(amr_info->pipe_in, &id, 1);
+ if (0 == n) break;
+ if (1 == n)
+ {
+ DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n",
+ amr_info->thread_name,
+ amr_info->pipe_in,
+ amr_info->pipe_out);
+
+ amr_info->process_msg_cb(amr_info->client_data, id);
+ }
+ if ((n < 0) && (errno != EINTR)) break;
+ }
+ DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__);
+
+ return 0;
+}
+
+void *omx_amr_events(void *info)
+{
+ struct amr_ipc_info *amr_info = (struct amr_ipc_info*)info;
+ unsigned char id = 0;
+
+ DEBUG_DETAIL("%s: message thread start\n", amr_info->thread_name);
+ amr_info->process_msg_cb(amr_info->client_data, id);
+ DEBUG_DETAIL("%s: message thread stop\n", amr_info->thread_name);
+ return 0;
+}
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to msging thread
+ */
+struct amr_ipc_info *omx_amr_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct amr_ipc_info *amr_info;
+
+ amr_info = calloc(1, sizeof(struct amr_ipc_info));
+ if (!amr_info)
+ {
+ return 0;
+ }
+
+ amr_info->client_data = client_data;
+ amr_info->process_msg_cb = cb;
+ strlcpy(amr_info->thread_name, th_name, sizeof(amr_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ amr_info->pipe_in = fds[0];
+ amr_info->pipe_out = fds[1];
+
+ r = pthread_create(&amr_info->thr, 0, omx_amr_msg, amr_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", amr_info->thread_name);
+ return amr_info;
+
+
+fail_thread:
+ close(amr_info->pipe_in);
+ close(amr_info->pipe_out);
+
+fail_pipe:
+ free(amr_info);
+
+ return 0;
+}
+
+/**
+ * @brief This function starts command server
+ *
+ * @param cb pointer to callback function from the client
+ * @param client_data reference client wants to get back
+ * through callback
+ * @return handle to msging thread
+ * */
+struct amr_ipc_info *omx_amr_event_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct amr_ipc_info *amr_info;
+
+ amr_info = calloc(1, sizeof(struct amr_ipc_info));
+ if (!amr_info)
+ {
+ return 0;
+ }
+
+ amr_info->client_data = client_data;
+ amr_info->process_msg_cb = cb;
+ strlcpy(amr_info->thread_name, th_name, sizeof(amr_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ amr_info->pipe_in = fds[0];
+ amr_info->pipe_out = fds[1];
+
+ r = pthread_create(&amr_info->thr, 0, omx_amr_events, amr_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", amr_info->thread_name);
+ return amr_info;
+
+
+fail_thread:
+ close(amr_info->pipe_in);
+ close(amr_info->pipe_out);
+
+fail_pipe:
+ free(amr_info);
+
+ return 0;
+}
+
+void omx_amr_thread_stop(struct amr_ipc_info *amr_info) {
+ DEBUG_DETAIL("%s stop server\n", __FUNCTION__);
+ close(amr_info->pipe_in);
+ close(amr_info->pipe_out);
+ pthread_join(amr_info->thr,NULL);
+ amr_info->pipe_out = -1;
+ amr_info->pipe_in = -1;
+ DEBUG_DETAIL("%s: message thread close fds%d %d\n", amr_info->thread_name,
+ amr_info->pipe_in,amr_info->pipe_out);
+ free(amr_info);
+}
+
+void omx_amr_post_msg(struct amr_ipc_info *amr_info, unsigned char id) {
+ DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id);
+ write(amr_info->pipe_out, &id, 1);
+}
diff --git a/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp b/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp
new file mode 100644
index 0000000..c6233f8
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp
@@ -0,0 +1,4531 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+/*============================================================================
+@file omx_aenc_amr.c
+ This module contains the implementation of the OpenMAX core & component.
+
+*//*========================================================================*/
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+
+#include<string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "omx_amr_aenc.h"
+#include <errno.h>
+
+using namespace std;
+#define SLEEP_MS 100
+
+// omx_cmd_queue destructor
+omx_amr_aenc::omx_cmd_queue::~omx_cmd_queue()
+{
+ // Nothing to do
+}
+
+// omx cmd queue constructor
+omx_amr_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0)
+{
+ memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE);
+}
+
+// omx cmd queue insert
+bool omx_amr_aenc::omx_cmd_queue::insert_entry(unsigned p1,
+ unsigned p2,
+ unsigned id)
+{
+ bool ret = true;
+ if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_q[m_write].id = id;
+ m_q[m_write].param1 = p1;
+ m_q[m_write].param2 = p2;
+ m_write++;
+ m_size ++;
+ if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_write = 0;
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full");
+ }
+ return ret;
+}
+
+bool omx_amr_aenc::omx_cmd_queue::pop_entry(unsigned *p1,
+ unsigned *p2, unsigned *id)
+{
+ bool ret = true;
+ if (m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ *p1 = m_q[m_read].param1;
+ *p2 = m_q[m_read].param2;
+ // Move the read pointer ahead
+ ++m_read;
+ --m_size;
+ if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_read = 0;
+
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty");
+ }
+ return ret;
+}
+
+// factory function executed by the core to create instances
+void *get_omx_component_factory_fn(void)
+{
+ return(new omx_amr_aenc);
+}
+bool omx_amr_aenc::omx_cmd_queue::get_msg_id(unsigned *id)
+{
+ if(m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ DEBUG_PRINT("get_msg_id=%d\n",*id);
+ }
+ else{
+ return false;
+ }
+ return true;
+}
+/*=============================================================================
+FUNCTION:
+ wait_for_event
+
+DESCRIPTION:
+ waits for a particular event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_amr_aenc::wait_for_event()
+{
+ int rc;
+ struct timespec ts;
+ pthread_mutex_lock(&m_event_lock);
+ while (0 == m_is_event_done)
+ {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += (SLEEP_MS/1000);
+ ts.tv_nsec += ((SLEEP_MS%1000) * 1000000);
+ rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts);
+ if (rc == ETIMEDOUT && !m_is_event_done) {
+ DEBUG_PRINT("Timed out waiting for flush");
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ }
+ }
+ m_is_event_done = 0;
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+/*=============================================================================
+FUNCTION:
+ event_complete
+
+DESCRIPTION:
+ informs about the occurance of an event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_amr_aenc::event_complete()
+{
+ pthread_mutex_lock(&m_event_lock);
+ if (0 == m_is_event_done)
+ {
+ m_is_event_done = 1;
+ pthread_cond_signal(&cond);
+ }
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+// All this non-sense because of a single amr object
+void omx_amr_aenc::in_th_goto_sleep()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ while (0 == m_is_in_th_sleep)
+ {
+ pthread_cond_wait(&in_cond, &m_in_th_lock);
+ }
+ m_is_in_th_sleep = 0;
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_amr_aenc::in_th_wakeup()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ if (0 == m_is_in_th_sleep)
+ {
+ m_is_in_th_sleep = 1;
+ pthread_cond_signal(&in_cond);
+ }
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_amr_aenc::out_th_goto_sleep()
+{
+
+ pthread_mutex_lock(&m_out_th_lock);
+ while (0 == m_is_out_th_sleep)
+ {
+ pthread_cond_wait(&out_cond, &m_out_th_lock);
+ }
+ m_is_out_th_sleep = 0;
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+
+void omx_amr_aenc::out_th_wakeup()
+{
+ pthread_mutex_lock(&m_out_th_lock);
+ if (0 == m_is_out_th_sleep)
+ {
+ m_is_out_th_sleep = 1;
+ pthread_cond_signal(&out_cond);
+ }
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::omx_amr_aenc
+
+DESCRIPTION
+ Constructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_amr_aenc::omx_amr_aenc(): m_tmp_meta_buf(NULL),
+ m_tmp_out_meta_buf(NULL),
+ m_flush_cnt(255),
+ m_comp_deinit(0),
+ m_app_data(NULL),
+ m_drv_fd(-1),
+ bFlushinprogress(0),
+ is_in_th_sleep(false),
+ is_out_th_sleep(false),
+ m_flags(0),
+ nTimestamp(0),
+ ts(0),
+ m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS),
+ m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS),
+ m_inp_current_buf_count(0),
+ m_out_current_buf_count(0),
+ output_buffer_size(OMX_AMR_OUTPUT_BUFFER_SIZE),
+ input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE),
+ m_inp_bEnabled(OMX_TRUE),
+ m_out_bEnabled(OMX_TRUE),
+ m_inp_bPopulated(OMX_FALSE),
+ m_out_bPopulated(OMX_FALSE),
+ m_is_event_done(0),
+ m_state(OMX_StateInvalid),
+ m_ipc_to_in_th(NULL),
+ m_ipc_to_out_th(NULL),
+ m_ipc_to_cmd_th(NULL),
+ pcm_input(0),
+ m_volume(25),
+ m_session_id(0),
+ nNumOutputBuf(0),
+ nNumInputBuf(0)
+{
+ int cond_ret = 0;
+ component_Role.nSize = 0;
+ memset(&m_cmp, 0, sizeof(m_cmp));
+ memset(&m_cb, 0, sizeof(m_cb));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ memset(&m_amr_param, 0, sizeof(m_amr_param));
+ memset(&m_amr_pb_stats, 0, sizeof(m_amr_pb_stats));
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+
+ pthread_mutexattr_init(&m_lock_attr);
+ pthread_mutex_init(&m_lock, &m_lock_attr);
+ pthread_mutexattr_init(&m_commandlock_attr);
+ pthread_mutex_init(&m_commandlock, &m_commandlock_attr);
+
+ pthread_mutexattr_init(&m_outputlock_attr);
+ pthread_mutex_init(&m_outputlock, &m_outputlock_attr);
+
+ pthread_mutexattr_init(&m_state_attr);
+ pthread_mutex_init(&m_state_lock, &m_state_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_flush_attr);
+ pthread_mutex_init(&m_flush_lock, &m_flush_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr);
+ pthread_mutex_init(&m_in_th_lock, &m_in_th_attr);
+
+ pthread_mutexattr_init(&m_out_th_attr);
+ pthread_mutex_init(&m_out_th_lock, &m_out_th_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr_1);
+ pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1);
+
+ pthread_mutexattr_init(&m_out_th_attr_1);
+ pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1);
+
+ pthread_mutexattr_init(&out_buf_count_lock_attr);
+ pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr);
+
+ pthread_mutexattr_init(&in_buf_count_lock_attr);
+ pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr);
+ if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+
+ sem_init(&sem_read_msg,0, 0);
+ sem_init(&sem_write_msg,0, 0);
+ sem_init(&sem_States,0, 0);
+ return;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::~omx_amr_aenc
+
+DESCRIPTION
+ Destructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_amr_aenc::~omx_amr_aenc()
+{
+ DEBUG_PRINT_ERROR("AMR Object getting destroyed comp-deinit=%d\n",
+ m_comp_deinit);
+ if ( !m_comp_deinit )
+ {
+ deinit_encoder();
+ }
+ pthread_mutexattr_destroy(&m_lock_attr);
+ pthread_mutex_destroy(&m_lock);
+
+ pthread_mutexattr_destroy(&m_commandlock_attr);
+ pthread_mutex_destroy(&m_commandlock);
+
+ pthread_mutexattr_destroy(&m_outputlock_attr);
+ pthread_mutex_destroy(&m_outputlock);
+
+ pthread_mutexattr_destroy(&m_state_attr);
+ pthread_mutex_destroy(&m_state_lock);
+
+ pthread_mutexattr_destroy(&m_event_attr);
+ pthread_mutex_destroy(&m_event_lock);
+
+ pthread_mutexattr_destroy(&m_flush_attr);
+ pthread_mutex_destroy(&m_flush_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr);
+ pthread_mutex_destroy(&m_in_th_lock);
+
+ pthread_mutexattr_destroy(&m_out_th_attr);
+ pthread_mutex_destroy(&m_out_th_lock);
+
+ pthread_mutexattr_destroy(&out_buf_count_lock_attr);
+ pthread_mutex_destroy(&out_buf_count_lock);
+
+ pthread_mutexattr_destroy(&in_buf_count_lock_attr);
+ pthread_mutex_destroy(&in_buf_count_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr_1);
+ pthread_mutex_destroy(&m_in_th_lock_1);
+
+ pthread_mutexattr_destroy(&m_out_th_attr_1);
+ pthread_mutex_destroy(&m_out_th_lock_1);
+ pthread_mutex_destroy(&out_buf_count_lock);
+ pthread_mutex_destroy(&in_buf_count_lock);
+ pthread_cond_destroy(&cond);
+ pthread_cond_destroy(&in_cond);
+ pthread_cond_destroy(&out_cond);
+ sem_destroy (&sem_read_msg);
+ sem_destroy (&sem_write_msg);
+ sem_destroy (&sem_States);
+ DEBUG_PRINT_ERROR("OMX AMR component destroyed\n");
+ return;
+}
+
+/**
+ @brief memory function for sending EmptyBufferDone event
+ back to IL client
+
+ @param bufHdr OMX buffer header to be passed back to IL client
+ @return none
+ */
+void omx_amr_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.EmptyBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr);
+ bufHdr->nFilledLen = 0;
+
+ m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr);
+ pthread_mutex_lock(&in_buf_count_lock);
+ m_amr_pb_stats.ebd_cnt++;
+ nNumInputBuf--;
+ DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\
+ m_amr_pb_stats.tot_in_buf_len,
+ nNumInputBuf, m_amr_pb_stats.ebd_cnt);
+ pthread_mutex_unlock(&in_buf_count_lock);
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ flush_ack
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_amr_aenc::flush_ack()
+{
+ // Decrement the FLUSH ACK count and notify the waiting recepients
+ pthread_mutex_lock(&m_flush_lock);
+ --m_flush_cnt;
+ if (0 == m_flush_cnt)
+ {
+ event_complete();
+ }
+ DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt);
+ pthread_mutex_unlock(&m_flush_lock);
+}
+void omx_amr_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.FillBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr);
+ m_amr_pb_stats.fbd_cnt++;
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf--;
+ DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\
+ nNumOutputBuf,
+ m_amr_pb_stats.tot_out_buf_len,
+ m_amr_pb_stats.fbd_cnt);
+ m_amr_pb_stats.tot_out_buf_len += bufHdr->nFilledLen;
+ m_amr_pb_stats.tot_pb_time = bufHdr->nTimeStamp;
+ DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n",
+ m_amr_pb_stats.tot_in_buf_len,
+ m_amr_pb_stats.tot_out_buf_len);
+
+ pthread_mutex_unlock(&out_buf_count_lock);
+ m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_out_port_msg
+
+DESCRIPTION:
+ Function for handling all commands from IL client
+IL client commands are processed and callbacks are generated through
+this routine Audio Command Server provides the thread context for this routine
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_amr_aenc::process_out_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0; // qsize
+ unsigned tot_qsize = 0;
+ omx_amr_aenc *pThis = (omx_amr_aenc *) client_data;
+ OMX_STATETYPE state;
+
+loopback_out:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n");
+ return;
+ }
+ pthread_mutex_lock(&pThis->m_outputlock);
+
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize);
+ return;
+ }
+ if ( (state != OMX_StateExecuting) && !qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+
+ if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) )
+ {
+ // case where no port reconfig and nothing in the flush q
+ DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\
+ qsize,tot_qsize);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress))
+ {
+ DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+ }
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size,state);
+
+
+ if (qsize)
+ {
+ // process FLUSH message
+ pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // if no FLUSH and FBD's then process FTB's
+ pThis->m_output_q.pop_entry(&p1,&p2,&ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pThis->out_th_goto_sleep();
+ goto loopback_out;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_outputlock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ ident = 0;
+ DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id )
+ {
+ pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_FTB == id )
+ {
+ pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_EOS == id )
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+
+ }
+ else if(id == OMX_COMPONENT_RESUME)
+ {
+ DEBUG_PRINT("RESUMED...\n");
+ }
+ else if(id == OMX_COMPONENT_GENERATE_COMMAND)
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL("Executing FLUSH command on Output port\n");
+ pThis->execute_output_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n");
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_command_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_amr_aenc::process_command_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ omx_amr_aenc *pThis = (omx_amr_aenc*)client_data;
+ pthread_mutex_lock(&pThis->m_commandlock);
+
+ qsize = pThis->m_command_q.m_size;
+ DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size,
+ pThis->m_state);
+
+ if (!qsize)
+ {
+ DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n");
+ pthread_mutex_unlock(&pThis->m_commandlock);
+ return;
+ } else
+ {
+ pThis->m_command_q.pop_entry(&p1,&p2,&ident);
+ }
+ pthread_mutex_unlock(&pThis->m_commandlock);
+
+ id = ident;
+ DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\
+ pThis->m_state,ident, \
+ pThis->m_command_q.m_size);
+
+ if (OMX_COMPONENT_GENERATE_EVENT == id)
+ {
+ if (pThis->m_cb.EventHandler)
+ {
+ if (OMX_CommandStateSet == p1)
+ {
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->m_state = (OMX_STATETYPE) p2;
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_PRINT("CMD:Process->state set to %d \n", \
+ pThis->m_state);
+
+ if (pThis->m_state == OMX_StateExecuting ||
+ pThis->m_state == OMX_StateLoaded)
+ {
+
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ if (pThis->is_in_th_sleep)
+ {
+ pThis->is_in_th_sleep = false;
+ DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n");
+ pThis->in_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ if (pThis->is_out_th_sleep)
+ {
+ DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n");
+ pThis->is_out_th_sleep = false;
+ pThis->out_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ }
+ }
+ if (OMX_StateInvalid == pThis->m_state)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ } else if ((signed)p2 == OMX_ErrorPortUnpopulated)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ p2,
+ NULL,
+ NULL );
+ } else
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventCmdComplete,
+ p1, p2, NULL );
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n");
+ }
+ } else if (OMX_COMPONENT_GENERATE_COMMAND == id)
+ {
+ pThis->send_command_proxy(&pThis->m_cmp,
+ (OMX_COMMANDTYPE)p1,
+ (OMX_U32)p2,(OMX_PTR)NULL);
+ } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id)
+ {
+ DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED");
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventPortSettingsChanged,
+ 1, 1, NULL );
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_in_port_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_amr_aenc::process_in_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ unsigned tot_qsize = 0;
+ omx_amr_aenc *pThis = (omx_amr_aenc *) client_data;
+ OMX_STATETYPE state;
+
+ if (!pThis)
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n");
+ return;
+ }
+loopback_in:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n");
+ return;
+ }
+ // Protect the shared queue data structure
+ pthread_mutex_lock(&pThis->m_lock);
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP");
+ pthread_mutex_unlock(&pThis->m_lock);
+ return;
+ }
+
+ if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_DETAIL("SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ else if ((state == OMX_StatePause))
+ {
+ if(!(pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ DEBUG_DETAIL("IN: SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ }
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size, state);
+
+
+ if ( qsize )
+ {
+ // process FLUSH message
+ pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) &&
+ (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident);
+ } else if ((qsize = pThis->m_input_q.m_size) &&
+ (state == OMX_StateExecuting))
+ {
+ // if no FLUSH and EBD's then process ETB's
+ pThis->m_input_q.pop_entry(&p1, &p2, &ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\
+ state,pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_lock);
+ pThis->in_th_goto_sleep();
+ goto loopback_in;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+ if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id )
+ {
+ pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ }
+ else if(id == OMX_COMPONENT_GENERATE_EOS)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
+ OMX_EventBufferFlag, 0, 1, NULL );
+ } else if ( OMX_COMPONENT_GENERATE_ETB == id )
+ {
+ pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_COMMAND == id )
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL(" Executing FLUSH command on Input port\n");
+ pThis->execute_input_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n");
+ }
+ return;
+}
+
+/**
+ @brief member function for performing component initialization
+
+ @param role C string mandating role of this component
+ @return Error status
+ */
+OMX_ERRORTYPE omx_amr_aenc::component_init(OMX_STRING role)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ m_state = OMX_StateLoaded;
+
+ /* DSP does not give information about the bitstream
+ randomly assign the value right now. Query will result in
+ incorrect param */
+ memset(&m_amr_param, 0, sizeof(m_amr_param));
+ m_amr_param.nSize = sizeof(m_amr_param);
+ m_amr_param.nChannels = OMX_AMR_DEFAULT_CH_CFG;
+ m_volume = OMX_AMR_DEFAULT_VOL; /* Close to unity gain */
+ memset(&m_amr_pb_stats,0,sizeof(AMR_PB_STATS));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ m_pcm_param.nSize = sizeof(m_pcm_param);
+ m_pcm_param.nChannels = OMX_AMR_DEFAULT_CH_CFG;
+ m_pcm_param.nSamplingRate = OMX_AMR_DEFAULT_SF;
+ nTimestamp = 0;
+ ts = 0;
+
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ m_ipc_to_in_th = NULL; // Command server instance
+ m_ipc_to_out_th = NULL; // Client server instance
+ m_ipc_to_cmd_th = NULL; // command instance
+ m_is_out_th_sleep = 0;
+ m_is_in_th_sleep = 0;
+ is_out_th_sleep= false;
+
+ is_in_th_sleep=false;
+
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+ m_priority_mgm.nGroupID =0;
+ m_priority_mgm.nGroupPriority=0;
+
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified;
+
+ DEBUG_PRINT_ERROR(" component init: role = %s\n",role);
+
+ DEBUG_PRINT(" component init: role = %s\n",role);
+ component_Role.nVersion.nVersion = OMX_SPEC_VERSION;
+ if (!strcmp(role,"OMX.qcom.audio.encoder.amrnb"))
+ {
+ pcm_input = 1;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole, (const char*)role,
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.amrnb"))
+ {
+ pcm_input = 0;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole, (const char*)role,
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else
+ {
+ component_Role.nSize = sizeof("\0");
+ strlcpy((char *)component_Role.cRole, (const char*)"\0",
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED is invalid\n", role);
+ }
+ if(pcm_input)
+ {
+ m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) *
+ (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN)));
+
+ if (m_tmp_meta_buf == NULL){
+ DEBUG_PRINT_ERROR("Mem alloc failed for tmp meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ m_tmp_out_meta_buf =
+ (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_AMR_OUTPUT_BUFFER_SIZE);
+ if ( m_tmp_out_meta_buf == NULL ){
+ DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+
+ if(0 == pcm_input)
+ {
+ m_drv_fd = open("/dev/msm_amrnb_in",O_RDONLY);
+ DEBUG_PRINT("Driver in Tunnel mode open\n");
+ }
+ else
+ {
+ m_drv_fd = open("/dev/msm_amrnb_in",O_RDWR);
+ DEBUG_PRINT("Driver in Non Tunnel mode open\n");
+ }
+ if (m_drv_fd < 0)
+ {
+ DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\
+ m_drv_fd,errno);
+
+ return OMX_ErrorInsufficientResources;
+ }
+ if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1)
+ {
+ DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n");
+ }
+ if(pcm_input)
+ {
+ if (!m_ipc_to_in_th)
+ {
+ m_ipc_to_in_th = omx_amr_thread_create(process_in_port_msg,
+ this, (char *)"INPUT_THREAD");
+ if (!m_ipc_to_in_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start \
+ Input port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ }
+
+ if (!m_ipc_to_cmd_th)
+ {
+ m_ipc_to_cmd_th = omx_amr_thread_create(process_command_msg,
+ this, (char *)"CMD_THREAD");
+ if (!m_ipc_to_cmd_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!!Failed to start "
+ "command message thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+
+ if (!m_ipc_to_out_th)
+ {
+ m_ipc_to_out_th = omx_amr_thread_create(process_out_port_msg,
+ this, (char *)"OUTPUT_THREAD");
+ if (!m_ipc_to_out_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start output "
+ "port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ return eRet;
+}
+
+/**
+
+ @brief member function to retrieve version of component
+
+
+
+ @param hComp handle to this component instance
+ @param componentName name of component
+ @param componentVersion pointer to memory space which stores the
+ version number
+ @param specVersion pointer to memory sapce which stores version of
+ openMax specification
+ @param componentUUID
+ @return Error status
+ */
+OMX_ERRORTYPE omx_amr_aenc::get_component_version
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STRING componentName,
+ OMX_OUT OMX_VERSIONTYPE* componentVersion,
+ OMX_OUT OMX_VERSIONTYPE* specVersion,
+ OMX_OUT OMX_UUIDTYPE* componentUUID)
+{
+ if((hComp == NULL) || (componentName == NULL) ||
+ (specVersion == NULL) || (componentUUID == NULL))
+ {
+ componentVersion = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ componentVersion->nVersion = OMX_SPEC_VERSION;
+ specVersion->nVersion = OMX_SPEC_VERSION;
+ return OMX_ErrorNone;
+}
+/**
+ @brief member function handles command from IL client
+
+ This function simply queue up commands from IL client.
+ Commands will be processed in command server thread context later
+
+ @param hComp handle to component instance
+ @param cmd type of command
+ @param param1 parameters associated with the command type
+ @param cmdData
+ @return Error status
+*/
+OMX_ERRORTYPE omx_amr_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ int portIndex = (int)param1;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateInvalid == m_state)
+ {
+ return OMX_ErrorInvalidState;
+ }
+ if ( (cmd == OMX_CommandFlush) && (portIndex > 1) )
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND);
+ DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n");
+ DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1);
+ sem_wait (&sem_States);
+ DEBUG_PRINT("send_command : recieved state after semwait\n");
+ return OMX_ErrorNone;
+}
+
+/**
+ @brief member function performs actual processing of commands excluding
+ empty buffer call
+
+ @param hComp handle to component
+ @param cmd command type
+ @param param1 parameter associated with the command
+ @param cmdData
+
+ @return error status
+*/
+OMX_ERRORTYPE omx_amr_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ // Handle only IDLE and executing
+ OMX_STATETYPE eState = (OMX_STATETYPE) param1;
+ int bFlag = 1;
+ nState = eState;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_CommandStateSet == cmd)
+ {
+ /***************************/
+ /* Current State is Loaded */
+ /***************************/
+ if (OMX_StateLoaded == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+
+ if (allocate_done() ||
+ (m_inp_bEnabled == OMX_FALSE
+ && m_out_bEnabled == OMX_FALSE))
+ {
+ DEBUG_PRINT("SCP-->Allocate Done Complete\n");
+ }
+ else
+ {
+ DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ bFlag = 0;
+ }
+
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ }
+
+ else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n");
+ eRet = OMX_ErrorNone;
+ }
+
+ else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ m_state = OMX_StateInvalid;
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /***************************/
+ /* Current State is IDLE */
+ /***************************/
+ else if (OMX_StateIdle == m_state)
+ {
+ if (OMX_StateLoaded == eState)
+ {
+ if (release_done(-1))
+ {
+ if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("SCP:Idle->Loaded,\
+ ioctl stop failed %d\n", errno);
+ }
+
+ nTimestamp=0;
+ ts = 0;
+ DEBUG_PRINT("SCP-->Idle to Loaded\n");
+ } else
+ {
+ DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING);
+ // Skip the event notification
+ bFlag = 0;
+ }
+ }
+ else if (OMX_StateExecuting == eState)
+ {
+
+ struct msm_audio_amrnb_enc_config_v2 drv_amr_enc_config;
+ struct msm_audio_stream_config drv_stream_config;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+
+ if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+ if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+
+ if(ioctl(m_drv_fd, AUDIO_GET_AMRNB_ENC_CONFIG_V2,
+ &drv_amr_enc_config) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_AMRNB_ENC_CONFIG_V2 \
+ failed, errno[%d]\n", errno);
+ }
+ drv_amr_enc_config.band_mode = m_amr_param.eAMRBandMode;
+ drv_amr_enc_config.dtx_enable = m_amr_param.eAMRDTXMode;
+ drv_amr_enc_config.frame_format = m_amr_param.eAMRFrameFormat;
+ if(ioctl(m_drv_fd, AUDIO_SET_AMRNB_ENC_CONFIG_V2, &drv_amr_enc_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_AMRNB_ENC_CONFIG_V2 \
+ failed, errno[%d]\n", errno);
+ }
+ if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ buf_cfg.meta_info_enable = 1;
+ buf_cfg.frames_per_buf = NUMOFFRAMES;
+ if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ if(pcm_input)
+ {
+ if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ pcm_cfg.channel_count = m_pcm_param.nChannels;
+ pcm_cfg.sample_rate = m_pcm_param.nSamplingRate;
+ DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+
+ if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ }
+ if(ioctl(m_drv_fd, AUDIO_START, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n",
+ errno);
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ }
+ DEBUG_PRINT("SCP-->Idle to Executing\n");
+ nState = eState;
+ } else if (eState == OMX_StateIdle)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n");
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /******************************/
+ /* Current State is Executing */
+ /******************************/
+ else if (OMX_StateExecuting == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+ DEBUG_PRINT("SCP-->Executing to Idle \n");
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+
+ } else if (OMX_StatePause == eState)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED PAUSE STATE\n");
+ DEBUG_DETAIL("*************************\n");
+ //ioctl(m_drv_fd, AUDIO_PAUSE, 0);
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n",
+ eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /***************************/
+ /* Current State is Pause */
+ /***************************/
+ else if (OMX_StatePause == m_state)
+ {
+ if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) )
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if(is_out_th_sleep)
+ {
+ DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n");
+ is_out_th_sleep = false;
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ }
+ if ( OMX_StateExecuting == eState )
+ {
+ nState = eState;
+ } else if ( OMX_StateIdle == eState )
+ {
+ DEBUG_PRINT("SCP-->Paused to Idle \n");
+ DEBUG_PRINT ("\n Internal flush issued");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+ } else if ( eState == OMX_StateLoaded )
+ {
+ DEBUG_PRINT("\n Pause --> loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n Pause --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("\n Pause --> Pause \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n Pause --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /**************************************/
+ /* Current State is WaitForResources */
+ /**************************************/
+ else if (m_state == OMX_StateWaitForResources)
+ {
+ if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n");
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: \
+ WaitForResources-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n",
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /****************************/
+ /* Current State is Invalid */
+ /****************************/
+ else if (m_state == OMX_StateInvalid)
+ {
+ if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState
+ || OMX_StateIdle == eState || OMX_StateExecuting == eState
+ || OMX_StatePause == eState || OMX_StateInvalid == eState)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing"
+ "/Pause/Invalid/WaitForResources\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else if (OMX_CommandFlush == cmd)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1);
+ DEBUG_DETAIL("*************************\n");
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX ||
+ param1 == OMX_CORE_OUTPUT_PORT_INDEX ||
+ (signed)param1 == -1 )
+ {
+ execute_omx_flush(param1);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError,
+ OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL );
+ }
+ } else if ( cmd == OMX_CommandPortDisable )
+ {
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL )
+ {
+ DEBUG_PRINT("SCP: Disabling Input port Indx\n");
+ m_inp_bEnabled = OMX_FALSE;
+ if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(0) )
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_inp_bEnabled=%d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+
+ else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\
+ " param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+
+ }
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+
+ DEBUG_PRINT("SCP: Disabling Output port Indx\n");
+ m_out_bEnabled = OMX_FALSE;
+ if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(1))
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_out_bEnabled=%d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\
+ "param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID");
+ }
+
+ } else if (cmd == OMX_CommandPortEnable)
+ {
+ bFlag = 0;
+ if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ m_inp_bEnabled = OMX_TRUE;
+ DEBUG_PRINT("SCP: Enabling Input port Indx\n");
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_inp_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+
+ } else
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ }
+
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ DEBUG_PRINT("SCP: Enabling Output port Indx\n");
+ m_out_bEnabled = OMX_TRUE;
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_out_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID");
+ }
+
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd);
+ eRet = OMX_ErrorNotImplemented;
+ }
+ DEBUG_PRINT("posting sem_States\n");
+ sem_post (&sem_States);
+ if (eRet == OMX_ErrorNone && bFlag)
+ {
+ post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT);
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] param1
+ [IN] cmd_cmpl
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_amr_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl)
+{
+ bool bRet = true;
+
+ DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1);
+ struct timespec abs_timeout;
+ abs_timeout.tv_sec = 1;
+ abs_timeout.tv_nsec = 0;
+
+ if ((signed)param1 == -1)
+ {
+ bFlushinprogress = true;
+ DEBUG_PRINT("Execute flush for both I/p O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+
+ // Send Flush commands to input and output threads
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ // Send Flush to the kernel so that the in and out buffers are released
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+
+ DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\
+ param1,cmd_cmpl);
+
+ // If not going to idle state, Send FLUSH complete message
+ // to the Client, now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n");
+ }
+ bFlushinprogress = false;
+ }
+ else if (param1 == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("Execute FLUSH for I/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ //sleep till the FLUSH ACK are done by both the input and output threads
+ DEBUG_DETAIL("Executing FLUSH for I/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+ DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1);
+
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1)
+ {
+ DEBUG_PRINT("Executing FLUSH for O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ DEBUG_DETAIL("Executing FLUSH for O/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1)
+ DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ wait_for_event();
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ }
+ DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1);
+ } else
+ {
+ DEBUG_PRINT("Invalid Port ID[%lu]",param1);
+ }
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_input_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_amr_aenc::execute_input_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on input port");
+
+ pthread_mutex_lock(&m_lock);
+ do
+ {
+ qsize = m_input_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += m_input_ctrl_ebd_q.m_size;
+
+ DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,qsize);
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_lock);
+ break;
+ }
+ if (qsize)
+ {
+ m_input_q.pop_entry(&p1, &p2, &ident);
+ if ((ident == OMX_COMPONENT_GENERATE_ETB) ||
+ (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf);
+ omx_buf->nFilledLen = 0;
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else if (m_input_ctrl_ebd_q.m_size)
+ {
+ m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident);
+ if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ omx_buf->nFilledLen = 0;
+ DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf);
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else
+ {
+ }
+ }while (tot_qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("IN-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_lock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_output_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_amr_aenc::execute_output_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on output port");
+
+ pthread_mutex_lock(&m_outputlock);
+ do
+ {
+ qsize = m_output_q.m_size;
+ DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,qsize);
+ tot_qsize = qsize;
+ tot_qsize += m_output_ctrl_fbd_q.m_size;
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_outputlock);
+ break;
+ }
+ if (qsize)
+ {
+ m_output_q.pop_entry(&p1,&p2,&ident);
+ if ( (OMX_COMPONENT_GENERATE_FTB == ident) ||
+ (OMX_COMPONENT_GENERATE_FRAME_DONE == ident))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FBD FROM FLUSH");
+ }
+ } else if ((qsize = m_output_ctrl_fbd_q.m_size))
+ {
+ m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident);
+ if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH");
+ }
+ }
+ }while (qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("OUT-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_outputlock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_input
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_amr_aenc::post_input(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+ pthread_mutex_lock(&m_lock);
+
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND))
+ {
+ // insert flush message and ebd
+ m_input_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id))
+ {
+ // insert ebd
+ m_input_ctrl_ebd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ // ETBS in this queue
+ m_input_q.insert_entry(p1,p2,id);
+ }
+
+ if (m_ipc_to_in_th)
+ {
+ bRet = true;
+ omx_amr_post_msg(m_ipc_to_in_th, id);
+ }
+
+ DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\
+ m_state,
+ id,
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,
+ m_input_q.m_size);
+
+ pthread_mutex_unlock(&m_lock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_command
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_amr_aenc::post_command(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_commandlock);
+
+ m_command_q.insert_entry(p1,p2,id);
+
+ if (m_ipc_to_cmd_th)
+ {
+ bRet = true;
+ omx_amr_post_msg(m_ipc_to_cmd_th, id);
+ }
+
+ DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\
+ m_state,
+ id,
+ m_command_q.m_size,
+ m_flags >> 3);
+
+ pthread_mutex_unlock(&m_commandlock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_output
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_amr_aenc::post_output(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_outputlock);
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)
+ || (id == OMX_COMPONENT_RESUME))
+ {
+ // insert flush message and fbd
+ m_output_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) )
+ {
+ // insert flush message and fbd
+ m_output_ctrl_fbd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ m_output_q.insert_entry(p1,p2,id);
+ }
+ if ( m_ipc_to_out_th )
+ {
+ bRet = true;
+ omx_amr_post_msg(m_ipc_to_out_th, id);
+ }
+ DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ m_state,
+ id,
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,
+ m_output_q.m_size);
+
+ pthread_mutex_unlock(&m_outputlock);
+ return bRet;
+}
+/**
+ @brief member function that return parameters to IL client
+
+ @param hComp handle to component instance
+ @param paramIndex Parameter type
+ @param paramData pointer to memory space which would hold the
+ paramter
+ @return error status
+*/
+OMX_ERRORTYPE omx_amr_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_INOUT OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Param in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("get_parameter: paramData is NULL\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ DEBUG_PRINT("OMX_IndexParamPortDefinition " \
+ "portDefn->nPortIndex = %lu\n",
+ portDefn->nPortIndex);
+
+ portDefn->nVersion.nVersion = OMX_SPEC_VERSION;
+ portDefn->nSize = sizeof(portDefn);
+ portDefn->eDomain = OMX_PortDomainAudio;
+
+ if (0 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirInput;
+ portDefn->bEnabled = m_inp_bEnabled;
+ portDefn->bPopulated = m_inp_bPopulated;
+ portDefn->nBufferCountActual = m_inp_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS;
+ portDefn->nBufferSize = input_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+ portDefn->format.audio.pNativeRender = 0;
+ } else if (1 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirOutput;
+ portDefn->bEnabled = m_out_bEnabled;
+ portDefn->bPopulated = m_out_bPopulated;
+ portDefn->nBufferCountActual = m_out_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS;
+ portDefn->nBufferSize = output_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+ portDefn->format.audio.pNativeRender = 0;
+ } else
+ {
+ portDefn->eDir = OMX_DirMax;
+ DEBUG_PRINT_ERROR("Bad Port idx %d\n",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioInit\n");
+
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 2;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n");
+ portFormatType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portFormatType->nSize = sizeof(portFormatType);
+
+ if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex)
+ {
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\
+ "%lu\n", portFormatType->nIndex);
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingAMR;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n",
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioAmr:
+ {
+ OMX_AUDIO_PARAM_AMRTYPE *amrParam =
+ (OMX_AUDIO_PARAM_AMRTYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioAmr\n");
+ if (OMX_CORE_OUTPUT_PORT_INDEX== amrParam->nPortIndex)
+ {
+ memcpy(amrParam,&m_amr_param,
+ sizeof(OMX_AUDIO_PARAM_AMRTYPE));
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioAmr "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)amrParam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case QOMX_IndexParamAudioSessionId:
+ {
+ QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam =
+ (QOMX_AUDIO_STREAM_INFO_DATA *) paramData;
+ streaminfoparam->sessionId = m_session_id;
+ break;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(pcmparam,&m_pcm_param,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+ DEBUG_PRINT("get_parameter: Sampling rate %lu",\
+ pcmparam->nSamplingRate);
+ DEBUG_PRINT("get_parameter: Number of channels %lu",\
+ pcmparam->nChannels);
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamComponentSuspended:
+ {
+ OMX_PARAM_SUSPENSIONTYPE *suspend=
+ (OMX_PARAM_SUSPENSIONTYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n",
+ suspend);
+ break;
+ }
+ case OMX_IndexParamVideoInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ OMX_PRIORITYMGMTTYPE *priorityMgmtType =
+ (OMX_PRIORITYMGMTTYPE*)paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n");
+ priorityMgmtType->nSize = sizeof(priorityMgmtType);
+ priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION;
+ priorityMgmtType->nGroupID = m_priority_mgm.nGroupID;
+ priorityMgmtType->nGroupPriority =
+ m_priority_mgm.nGroupPriority;
+ break;
+ }
+ case OMX_IndexParamImageInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+
+ bufferSupplierType->nSize = sizeof(bufferSupplierType);
+ bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION;
+ if (OMX_CORE_INPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:"\
+ "OMX_IndexParamCompBufferSupplier eRet"\
+ "%08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ /*Component should support this port definition*/
+ case OMX_IndexParamOtherInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ componentRole->nSize = component_Role.nSize;
+ componentRole->nVersion = component_Role.nVersion;
+ strlcpy((char *)componentRole->cRole,
+ (const char*)component_Role.cRole,
+ sizeof(componentRole->cRole));
+ DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n",
+ component_Role.nSize,
+ component_Role.nVersion,
+ component_Role.cRole);
+ break;
+
+ }
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+
+}
+
+/**
+ @brief member function that set paramter from IL client
+
+ @param hComp handle to component instance
+ @param paramIndex parameter type
+ @param paramData pointer to memory space which holds the paramter
+ @return error status
+ */
+OMX_ERRORTYPE omx_amr_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_IN OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("set_parameter is not in proper state\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("param data is NULL");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamAudioAmr:
+ {
+ DEBUG_PRINT("OMX_IndexParamAudioAmr");
+ OMX_AUDIO_PARAM_AMRTYPE *amrparam
+ = (OMX_AUDIO_PARAM_AMRTYPE *) paramData;
+ memcpy(&m_amr_param,amrparam,
+ sizeof(OMX_AUDIO_PARAM_AMRTYPE));
+ break;
+ }
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ if (((m_state == OMX_StateLoaded)&&
+ !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources &&
+ ((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == true)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == true)))
+ ||(((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == false)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == false)) &&
+ (m_state != OMX_StateWaitForResources)))
+ {
+ DEBUG_PRINT("Set Parameter called in valid state\n");
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex "
+ "= %lu\n",portDefn->nPortIndex);
+ if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_INPUT_BUFFERS )
+ {
+ m_inp_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS;
+ }
+ input_buffer_size = portDefn->nBufferSize;
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_OUTPUT_BUFFERS )
+ {
+ m_out_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS;
+ }
+ output_buffer_size = portDefn->nBufferSize;
+ } else
+ {
+ DEBUG_PRINT(" set_parameter: Bad Port idx %d",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n");
+
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ OMX_PRIORITYMGMTTYPE *priorityMgmtype
+ = (OMX_PRIORITYMGMTTYPE*) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n",
+ priorityMgmtype->nGroupID);
+
+ DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n",
+ priorityMgmtype->nGroupPriority);
+
+ m_priority_mgm.nGroupID = priorityMgmtype->nGroupID;
+ m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority;
+
+ break;
+ }
+ case OMX_IndexParamAudioPortFormat:
+ {
+
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n");
+
+ if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex)
+ {
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\
+ " %lu\n", portFormatType->nIndex);
+ portFormatType->eEncoding = OMX_AUDIO_CodingAMR;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("set_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\
+ bufferSupplierType->eBufferSupplier);
+
+ if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX
+ || bufferSupplierType->nPortIndex ==
+ OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("set_parameter:\
+ OMX_IndexParamCompBufferSupplier\n");
+ m_buffer_supplier.eBufferSupplier =
+ bufferSupplierType->eBufferSupplier;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_param:\
+ IndexParamCompBufferSup %08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ break; }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n");
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam
+ = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(&m_pcm_param,pcmparam,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+ DEBUG_PRINT("set_pcm_parameter: %lu %lu",\
+ m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm "
+ "OMX_ErrorBadPortIndex %d\n",
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamSuspensionPolicy:
+ {
+ eRet = OMX_ErrorNotImplemented;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ component_Role.nSize = componentRole->nSize;
+ component_Role.nVersion = componentRole->nVersion;
+ strlcpy((char *)component_Role.cRole,
+ (const char*)componentRole->cRole,
+ sizeof(component_Role.cRole));
+ break;
+ }
+
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::GetConfig
+
+DESCRIPTION
+ OMX Get Config Method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_INOUT OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *volume =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex)
+ {
+ volume->nSize = sizeof(volume);
+ volume->nVersion.nVersion = OMX_SPEC_VERSION;
+ volume->bLinear = OMX_TRUE;
+ volume->sVolume.nValue = m_volume;
+ volume->sVolume.nMax = OMX_AENC_MAX;
+ volume->sVolume.nMin = OMX_AENC_MIN;
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute =
+ (OMX_AUDIO_CONFIG_MUTETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex)
+ {
+ mute->nSize = sizeof(mute);
+ mute->nVersion.nVersion = OMX_SPEC_VERSION;
+ mute->bMute = (BITMASK_PRESENT(&m_flags,
+ OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::SetConfig
+
+DESCRIPTION
+ OMX Set Config method implementation
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_IN OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Set Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if ( m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *vol =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData;
+ if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if ((vol->sVolume.nValue <= OMX_AENC_MAX) &&
+ (vol->sVolume.nValue >= OMX_AENC_MIN))
+ {
+ m_volume = vol->sVolume.nValue;
+ if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED))
+ {
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+
+ } else
+ {
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*)
+ configData;
+ if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if (mute->bMute == OMX_TRUE)
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */
+ } else
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::GetExtensionIndex
+
+DESCRIPTION
+ OMX GetExtensionIndex method implementaion. <TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::get_extension_index(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_STRING paramName,
+ OMX_OUT OMX_INDEXTYPE* indexType)
+{
+ if((hComp == NULL) || (paramName == NULL) || (indexType == NULL))
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId",
+ strlen("OMX.Qualcomm.index.audio.sessionId")) == 0)
+ {
+ *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId;
+ DEBUG_PRINT("Extension index type - %d\n", *indexType);
+
+ }
+ else
+ {
+ return OMX_ErrorBadParameter;
+
+ }
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::GetState
+
+DESCRIPTION
+ Returns the state information back to the caller.<TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STATETYPE* state)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ *state = m_state;
+ DEBUG_PRINT("Returning the state %d\n",*state);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::ComponentTunnelRequest
+
+DESCRIPTION
+ OMX Component Tunnel Request method implementation. <TBD>
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::component_tunnel_request
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_HANDLETYPE peerComponent,
+ OMX_IN OMX_U32 peerPort,
+ OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup)
+{
+ DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n");
+
+ if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL))
+ {
+ port = 0;
+ peerPort = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::AllocateInputBuffer
+
+DESCRIPTION
+ Helper function for allocate buffer in the input pin
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::allocate_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+ if(m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc((nBufSize + \
+ sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1);
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ free(buf_ptr);
+ return OMX_ErrorBadParameter;
+ }
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+
+ m_inp_current_buf_count++;
+ DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%d \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,m_inp_current_buf_count,
+ bytes);
+
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+OMX_ERRORTYPE omx_amr_aenc::allocate_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+ buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) +
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+ DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d"\
+ "bytes=%lu",bufHdr, bufHdr->pBuffer,\
+ m_out_current_buf_count, bytes);
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+
+// AllocateBuffer -- API Call
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::AllocateBuffer
+
+DESCRIPTION
+ Returns zero if all the buffers released..
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::allocate_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type
+
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ // What if the client calls again.
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",
+ (int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("allocate_buffer: before allocate_done \n");
+ if (allocate_done())
+ {
+ DEBUG_PRINT("allocate_buffer: after allocate_done \n");
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("allocate_buffer: post idle transition event \n");
+ }
+ DEBUG_PRINT("allocate_buffer: complete \n");
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ m_out_bEnabled = OMX_TRUE;
+
+ DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("AB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ }
+ DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet);
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_buffer
+
+DESCRIPTION:
+ OMX Use Buffer method implementation.
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_amr_aenc::use_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("Checking for Output Allocate buffer Done");
+ if (allocate_done())
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("UB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ }
+ }
+ DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet);
+ return eRet;
+}
+/*=============================================================================
+FUNCTION:
+ use_input_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the input pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_amr_aenc::use_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if(bytes < input_buffer_size)
+ {
+ /* return if i\p buffer size provided by client
+ is less than min i\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+ if (m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ input_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+ m_inp_current_buf_count++;
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_output_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the output pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_amr_aenc::use_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (bytes < output_buffer_size)
+ {
+ /* return if o\p buffer size provided by client
+ is less than min o\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+
+ DEBUG_PRINT("Inside omx_amr_aenc::use_output_buffer");
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer);
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \
+ len=%lu", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ output_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_amr_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_input_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_input_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_amr_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_output_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_output_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+// Free Buffer - API call
+/**
+ @brief member function that handles free buffer command from IL client
+
+ This function is a block-call function that handles IL client request to
+ freeing the buffer
+
+ @param hComp handle to component instance
+ @param port id of port which holds the buffer
+ @param buffer buffer header
+ @return Error status
+*/
+OMX_ERRORTYPE omx_amr_aenc::free_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("Free_Buffer buf %p\n", buffer);
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateIdle &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ DEBUG_PRINT(" free buffer while Component in Loading pending\n");
+ } else if ((m_inp_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_INPUT_PORT_INDEX)||
+ (m_out_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_OUTPUT_PORT_INDEX))
+ {
+ DEBUG_PRINT("Free Buffer while port %lu disabled\n", port);
+ } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause)
+ {
+ DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\
+ OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ return eRet;
+ } else
+ {
+ DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\
+ disabled:OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ if (m_inp_current_buf_count != 0)
+ {
+ m_inp_bPopulated = OMX_FALSE;
+ if (true == search_input_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer);
+ m_input_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_inp_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \
+ Invalid Input buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \
+ came out Invalid\n");
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING)
+ && release_done(0))
+ {
+ DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ if (m_out_current_buf_count != 0)
+ {
+ m_out_bPopulated = OMX_FALSE;
+ if (true == search_output_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer);
+ m_output_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_out_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT("Free_Buf:Error-->free_buffer , \
+ Invalid Output buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING)
+ && release_done(1))
+ {
+ DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if ((OMX_ErrorNone == eRet) &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ if (release_done(-1))
+ {
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0)
+ DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n");
+ else
+ DEBUG_PRINT("AUDIO STOP in free buffer passed\n");
+
+
+ DEBUG_PRINT("Free_Buf: Free buffer\n");
+
+
+ // Send the callback now
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING);
+ DEBUG_PRINT("Before OMX_StateLoaded \
+ OMX_COMPONENT_GENERATE_EVENT\n");
+ post_command(OMX_CommandStateSet,
+ OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n");
+
+ }
+ }
+ return eRet;
+}
+
+
+/**
+ @brief member function that that handles empty this buffer command
+
+ This function meremly queue up the command and data would be consumed
+ in command server thread context
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_amr_aenc::empty_this_buffer(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \
+ buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf));
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("Empty this buffer in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (!m_inp_bEnabled)
+ {
+ DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\
+ "Port Status %d \n", m_inp_bEnabled);
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_amr_aenc::etb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_amr_aenc::etb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+
+ if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ if ((m_state != OMX_StateExecuting) &&
+ (m_state != OMX_StatePause))
+ {
+ DEBUG_PRINT_ERROR("Invalid state\n");
+ eRet = OMX_ErrorInvalidState;
+ }
+ if (OMX_ErrorNone == eRet)
+ {
+ if (search_input_bufhdr(buffer) == true)
+ {
+ post_input((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ pthread_mutex_lock(&in_buf_count_lock);
+ nNumInputBuf++;
+ m_amr_pb_stats.etb_cnt++;
+ pthread_mutex_unlock(&in_buf_count_lock);
+ return eRet;
+}
+/**
+ @brief member function that writes data to kernel driver
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_amr_aenc::empty_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ META_IN meta_in;
+ //Pointer to the starting location of the data to be transcoded
+ OMX_U8 *srcStart;
+ //The total length of the data to be transcoded
+ srcStart = buffer->pBuffer;
+ OMX_U8 *data = NULL;
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer);
+ memset(&meta_in,0,sizeof(meta_in));
+ if ( search_input_bufhdr(buffer) == false )
+ {
+ DEBUG_PRINT("ETBP: INVALID BUF HDR\n");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorBadParameter;
+ }
+ if (m_tmp_meta_buf)
+ {
+ data = m_tmp_meta_buf;
+
+ // copy the metadata info from the BufHdr and insert to payload
+ meta_in.offsetVal = sizeof(META_IN);
+ meta_in.nTimeStamp.LowPart =
+ ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF);
+ meta_in.nTimeStamp.HighPart =
+ (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF);
+ meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS;
+ if(buffer->nFlags & OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT("EOS OCCURED \n");
+ meta_in.nFlags |= OMX_BUFFERFLAG_EOS;
+ }
+ memcpy(data,&meta_in, meta_in.offsetVal);
+ DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags);
+ }
+
+ memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen);
+ write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN));
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (OMX_StateExecuting == state)
+ {
+ DEBUG_DETAIL("In Exe state, EBD CB");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ } else
+ {
+ /* Assume empty this buffer function has already checked
+ validity of buffer */
+ DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer);
+ post_input((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_BUFFER_DONE);
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE omx_amr_aenc::fill_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ ENC_META_OUT *meta_out = NULL;
+ int nReadbytes = 0;
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (true == search_output_bufhdr(buffer))
+ {
+ DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd);
+ nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size );
+ DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\
+ buffer->nAllocLen,buffer->pBuffer,
+ nReadbytes,nNumOutputBuf);
+ if (nReadbytes <= 0) {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorNone;
+ } else
+ DEBUG_PRINT("Read bytes %d\n",nReadbytes);
+ // Buffer from Driver will have
+ // 1 byte => Nr of frame field
+ // (sizeof(ENC_META_OUT) * Nr of frame) bytes => meta_out->offset_to_frame
+ // Frame Size * Nr of frame =>
+
+ meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char));
+ buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+
+ meta_out->lsw_ts);
+ buffer->nFlags |= meta_out->nflags;
+ buffer->nOffset = meta_out->offset_to_frame + sizeof(unsigned char);
+ buffer->nFilledLen = nReadbytes - buffer->nOffset;
+ ts += FRAMEDURATION;
+ buffer->nTimeStamp = ts;
+ nTimestamp = buffer->nTimeStamp;
+ DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \
+ timestamp %lld\n", meta_out->nflags, meta_out->frame_size,
+ meta_out->offset_to_frame, buffer->nTimeStamp);
+
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n");
+ m_cb.EventHandler(&m_cmp,
+ m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+ }
+
+ return OMX_ErrorNone;
+ }
+ DEBUG_PRINT("nState %d \n",nState );
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (state == OMX_StatePause)
+ {
+ DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\
+ state);
+ post_output((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_FRAME_DONE);
+ }
+ else
+ {
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+
+ }
+
+ }
+ else
+ DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n");
+
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::FillThisBuffer
+
+DESCRIPTION
+ IL client uses this method to release the frame buffer
+ after displaying them.
+
+
+
+PARAMETERS
+
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::fill_this_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_amr_aenc::ftb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_bEnabled == OMX_FALSE)
+ {
+ return OMX_ErrorIncorrectStateOperation;
+ }
+
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_amr_aenc::ftb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+ if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf++;
+ m_amr_pb_stats.ftb_cnt++;
+ DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf);
+ pthread_mutex_unlock(&out_buf_count_lock);
+ post_output((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB);
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::SetCallbacks
+
+DESCRIPTION
+ Set the callbacks.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::set_callbacks(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_CALLBACKTYPE* callbacks,
+ OMX_IN OMX_PTR appData)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ m_cb = *callbacks;
+ m_app_data = appData;
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::ComponentDeInit
+
+DESCRIPTION
+ Destroys the component and release memory allocated to the heap.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state)
+ {
+ DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n",
+ m_state);
+ }
+ deinit_encoder();
+
+DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::deinit_encoder
+
+DESCRIPTION
+ Closes all the threads and release memory allocated to the heap.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ None.
+
+========================================================================== */
+void omx_amr_aenc::deinit_encoder()
+{
+ DEBUG_PRINT("Component-deinit being processed\n");
+ DEBUG_PRINT("********************************\n");
+ DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\
+ m_amr_pb_stats.tot_in_buf_len,
+ m_amr_pb_stats.tot_out_buf_len,
+ m_amr_pb_stats.tot_pb_time);
+ DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\
+ m_amr_pb_stats.fbd_cnt,m_amr_pb_stats.ftb_cnt,
+ m_amr_pb_stats.etb_cnt,
+ m_amr_pb_stats.ebd_cnt);
+ memset(&m_amr_pb_stats,0,sizeof(AMR_PB_STATS));
+
+ if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state))
+ {
+ DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\
+ m_state);
+ // Get back any buffers from driver
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+ // force state change to loaded so that all threads can be exited
+ pthread_mutex_lock(&m_state_lock);
+ m_state = OMX_StateLoaded;
+ pthread_mutex_unlock(&m_state_lock);
+ DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\
+ m_inp_current_buf_count,
+ m_input_buf_hdrs.size());
+ m_input_buf_hdrs.eraseall();
+ DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\
+ m_out_current_buf_count,
+ m_output_buf_hdrs.size());
+ m_output_buf_hdrs.eraseall();
+
+ }
+ if(pcm_input)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ if(pcm_input)
+ {
+ if (m_ipc_to_in_th != NULL)
+ {
+ omx_amr_thread_stop(m_ipc_to_in_th);
+ m_ipc_to_in_th = NULL;
+ }
+ }
+
+ if (m_ipc_to_cmd_th != NULL)
+ {
+ omx_amr_thread_stop(m_ipc_to_cmd_th);
+ m_ipc_to_cmd_th = NULL;
+ }
+ if (m_ipc_to_out_th != NULL)
+ {
+ DEBUG_DETAIL("Inside omx_amr_thread_stop\n");
+ omx_amr_thread_stop(m_ipc_to_out_th);
+ m_ipc_to_out_th = NULL;
+ }
+
+
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0)
+ DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n");
+
+ if(pcm_input && m_tmp_meta_buf )
+ {
+ free(m_tmp_meta_buf);
+ }
+
+ if(m_tmp_out_meta_buf)
+ {
+ free(m_tmp_out_meta_buf);
+ }
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ bFlushinprogress = 0;
+
+ m_inp_current_buf_count=0;
+ m_out_current_buf_count=0;
+ m_out_act_buf_count = 0;
+ m_inp_act_buf_count = 0;
+ m_inp_bEnabled = OMX_FALSE;
+ m_out_bEnabled = OMX_FALSE;
+ m_inp_bPopulated = OMX_FALSE;
+ m_out_bPopulated = OMX_FALSE;
+ nTimestamp = 0;
+ ts = 0;
+
+ if ( m_drv_fd >= 0 )
+ {
+ if(close(m_drv_fd) < 0)
+ DEBUG_PRINT("De-init: Driver Close Failed \n");
+ m_drv_fd = -1;
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR(" AMR device already closed\n");
+ }
+ m_comp_deinit=1;
+ m_is_out_th_sleep = 1;
+ m_is_in_th_sleep = 1;
+ DEBUG_PRINT("************************************\n");
+ DEBUG_PRINT(" DEINIT COMPLETED");
+ DEBUG_PRINT("************************************\n");
+
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::UseEGLImage
+
+DESCRIPTION
+ OMX Use EGL Image method implementation <TBD>.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Not Implemented error.
+
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::use_EGL_image
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN void* eglImage)
+{
+ DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n");
+
+ if((hComp == NULL) || (appData == NULL) || (eglImage == NULL))
+ {
+ bufferHdr = NULL;
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::ComponentRoleEnum
+
+DESCRIPTION
+ OMX Component Role Enum method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_amr_aenc::component_role_enum(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_U8* role,
+ OMX_IN OMX_U32 index)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ const char *cmp_role = "audio_encoder.amr";
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (index == 0 && role)
+ {
+ memcpy(role, cmp_role, sizeof(cmp_role));
+ *(((char *) role) + sizeof(cmp_role)) = '\0';
+ } else
+ {
+ eRet = OMX_ErrorNoMore;
+ }
+ return eRet;
+}
+
+
+
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::AllocateDone
+
+DESCRIPTION
+ Checks if entire buffer pool is allocated by IL Client or not.
+ Need this to move to IDLE state.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false.
+
+========================================================================== */
+bool omx_amr_aenc::allocate_done(void)
+{
+ OMX_BOOL bRet = OMX_FALSE;
+ if (pcm_input==1)
+ {
+ if ((m_inp_act_buf_count == m_inp_current_buf_count)
+ &&(m_out_act_buf_count == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled )
+ {
+ m_inp_bPopulated = OMX_TRUE;
+ }
+
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+ } else if (pcm_input==0)
+ {
+ if (m_out_act_buf_count == m_out_current_buf_count)
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+
+ }
+ return bRet;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_amr_aenc::ReleaseDone
+
+DESCRIPTION
+ Checks if IL client has released all the buffers.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+bool omx_amr_aenc::release_done(OMX_U32 param1)
+{
+ DEBUG_PRINT("Inside omx_amr_aenc::release_done");
+ OMX_BOOL bRet = OMX_FALSE;
+
+ if (param1 == OMX_ALL)
+ {
+ if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_INPUT_PORT_INDEX )
+ {
+ if ((0 == m_inp_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ if ((0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ }
+ return bRet;
+}
diff --git a/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c b/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c
new file mode 100644
index 0000000..a3c91b1
--- /dev/null
+++ b/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c
@@ -0,0 +1,1051 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include<unistd.h>
+#include<string.h>
+#include <pthread.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+
+
+#include <linux/ioctl.h>
+
+typedef unsigned char uint8;
+typedef unsigned char byte;
+typedef unsigned int uint32;
+typedef unsigned int uint16;
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+/* maximum ADTS frame header length */
+void Release_Encoder();
+
+#ifdef AUDIOV2
+unsigned short session_id;
+int device_id;
+int control = 0;
+const char *device="handset_tx";
+#define DIR_TX 2
+#endif
+
+uint32_t samplerate = 8000;
+uint32_t channels = 1;
+uint32_t bandmode = 7;
+uint32_t dtxenable = 0;
+uint32_t rectime = -1;
+uint32_t recpath = -1;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t format = 1;
+#define DEBUG_PRINT printf
+unsigned to_idle_transition = 0;
+unsigned long total_pcm_bytes;
+
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define MIN_BITRATE 4 /* Bit rate 1 - 13.6 , 2 - 6.2 , 3 - 2.7 , 4 - 1.0 kbps*/
+#define MAX_BITRATE 4
+#define AMR_HEADER_SIZE 6
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+pthread_mutex_t lock;
+pthread_cond_t cond;
+pthread_mutex_t elock;
+pthread_cond_t econd;
+pthread_cond_t fcond;
+pthread_mutex_t etb_lock;
+pthread_mutex_t etb_lock1;
+pthread_cond_t etb_cond;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+OMX_AUDIO_PARAM_AMRTYPE amrparam;
+OMX_AUDIO_PARAM_PCMMODETYPE pcmparam;
+OMX_PORT_PARAM_TYPE portParam;
+OMX_PORT_PARAM_TYPE portFmt;
+OMX_ERRORTYPE error;
+
+
+
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+struct enc_meta_out{
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+} __attribute__ ((packed));
+
+struct qcp_header {
+ /* RIFF Section */
+ char riff[4];
+ unsigned int s_riff;
+ char qlcm[4];
+
+ /* Format chunk */
+ char fmt[4];
+ unsigned int s_fmt;
+ char mjr;
+ char mnr;
+ unsigned int data1; /* UNIQUE ID of the codec */
+ unsigned short data2;
+ unsigned short data3;
+ char data4[8];
+ unsigned short ver; /* Codec Info */
+ char name[80];
+ unsigned short abps; /* average bits per sec of the codec */
+ unsigned short bytes_per_pkt;
+ unsigned short samp_per_block;
+ unsigned short samp_per_sec;
+ unsigned short bits_per_samp;
+ unsigned char vr_num_of_rates; /* Rate Header fmt info */
+ unsigned char rvd1[3];
+ unsigned short vr_bytes_per_pkt[8];
+ unsigned int rvd2[5];
+
+ /* Vrat chunk */
+ unsigned char vrat[4];
+ unsigned int s_vrat;
+ unsigned int v_rate;
+ unsigned int size_in_pkts;
+
+ /* Data chunk */
+ unsigned char data[4];
+ unsigned int s_data;
+} __attribute__ ((packed));
+
+static unsigned totaldatalen = 0;
+static unsigned framecnt = 0;
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+volatile int etb_event_is_done = 0;
+int ebd_cnt;
+int bInputEosReached = 0;
+int bOutputEosReached = 0;
+int bInputEosReached_tunnel = 0;
+static int etb_done = 0;
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+const char *out_filename;
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* amr_enc_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Encoder(char*);
+int Play_Encoder();
+OMX_STRING aud_comp;
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *amr_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE parse_pcm_header();
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock1);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock1);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock1);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+ switch(eEvent) {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent,
+ nData1,nData2);
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("\n OMX_EventError \n");
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("\n OMX_EventBufferFlag \n");
+ bOutputEosReached = true;
+ event_complete();
+ break;
+ case OMX_EventPortSettingsChanged:
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ size_t bytes_writen = 0;
+ int total_bytes_writen = 0;
+ unsigned int len = 0;
+ struct enc_meta_out *meta = NULL;
+ OMX_U8 *src = pBuffer->pBuffer;
+ unsigned int num_of_frames = 1;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) {
+ DEBUG_PRINT("FBD::EOS on output port\n ");
+ bOutputEosReached = true;
+ return OMX_ErrorNone;
+ }
+ if(bInputEosReached_tunnel || bOutputEosReached)
+ {
+ DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n");
+ return OMX_ErrorNone;
+ }
+ if(num_of_frames != src[0]){
+
+ printf("Data corrupt\n");
+ return OMX_ErrorNone;
+ }
+ /* Skip the first bytes */
+
+
+
+ src += sizeof(unsigned char);
+ meta = (struct enc_meta_out *)src;
+ while (num_of_frames > 0) {
+ meta = (struct enc_meta_out *)src;
+ /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n",
+ meta->offset_to_frame,
+ meta->frame_size,
+ meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/
+ len = meta->frame_size;
+
+ bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile);
+ if(bytes_writen < len)
+ {
+ DEBUG_PRINT("error: invalid AMR encoded data \n");
+ return OMX_ErrorNone;
+ }
+ src += sizeof(struct enc_meta_out);
+ num_of_frames--;
+ total_bytes_writen += len;
+ }
+ DEBUG_PRINT(" FillBufferDone size writen to file %d count %d\n",total_bytes_writen, framecnt);
+ totaldatalen += total_bytes_writen ;
+ framecnt++;
+
+ DEBUG_PRINT(" FBD calling FTB\n");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock);
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock);
+ }
+
+
+ if(bInputEosReached)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }else if (bFlushing == true) {
+ DEBUG_PRINT("omx_amr_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (used_ip_buf_cnt == 0) {
+ bFlushing = false;
+ } else {
+ DEBUG_PRINT("omx_amr_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ return OMX_ErrorNone;
+ }
+ }
+
+ if((readBytes = Read_Buffer(pBuffer)) > 0) {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else{
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ bInputEosReached = true;
+ pBuffer->nFilledLen = 0;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id) {
+
+ /* Flush */
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(amr_enc_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ } else if (sig_id == SIGUSR2) {
+ if (bPause == true) {
+ DEBUG_PRINT("%s resume record\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ } else {
+ DEBUG_PRINT("%s pause record\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+
+ struct sigaction sa;
+ char amr_header[6] = {0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A};
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+ (void) signal(SIGINT, Release_Encoder);
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+
+ if (argc >= 8) {
+ in_filename = argv[1];
+ out_filename = argv[2];
+ tunnel = atoi(argv[3]);
+ bandmode = atoi(argv[4]);
+ dtxenable = atoi(argv[5]);
+ recpath = atoi(argv[6]); // No configuration support yet..
+ rectime = atoi(argv[7]);
+
+ } else {
+ DEBUG_PRINT(" invalid format: \n");
+ DEBUG_PRINT("ex: ./mm-aenc-omxamr-test INPUTFILE OUTPUTFILE Tunnel BANDMODE DTXENABLE RECORDPATH RECORDTIME\n");
+ DEBUG_PRINT("Bandmode 1-7, dtxenable 0-1\n");
+ DEBUG_PRINT("RECORDPATH 0(TX),1(RX),2(BOTH),3(MIC)\n");
+ DEBUG_PRINT("RECORDTIME in seconds for AST Automation\n");
+ return 0;
+ }
+ if(recpath != 3) {
+ DEBUG_PRINT("For RECORDPATH Only MIC supported\n");
+ return 0;
+ }
+ if(tunnel == 0)
+ aud_comp = "OMX.qcom.audio.encoder.amrnb";
+ else
+ aud_comp = "OMX.qcom.audio.encoder.tunneled.amrnb";
+ if(Init_Encoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+
+ if(Play_Encoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+ if(rectime && tunnel)
+ {
+ sleep(rectime);
+ rectime = 0;
+ bInputEosReached_tunnel = 1;
+ DEBUG_PRINT("\EOS ON INPUT PORT\n");
+ }
+ else
+ {
+ wait_for_event();
+ }
+
+ if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel))
+ {
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+
+ DEBUG_PRINT("\nMoving the encoder to loaded state \n");
+ OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+ sleep(1);
+ if (!tunnel)
+ {
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(amr_enc_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ }
+
+ DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(amr_enc_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+ wait_for_event();
+ fseek(outputBufferFile, 0,SEEK_SET);
+ fwrite(amr_header,1,AMR_HEADER_SIZE,outputBufferFile);
+
+ result = OMX_FreeHandle(amr_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+ if(tunnel)
+ {
+ #ifdef AUDIOV2
+ if (msm_route_stream(DIR_TX,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ #endif
+ }
+ OMX_Deinit();
+ ebd_cnt=0;
+ bOutputEosReached = false;
+ bInputEosReached_tunnel = false;
+ bInputEosReached = 0;
+ amr_enc_handle = NULL;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ fclose(outputBufferFile);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...AMR ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+ return 0;
+}
+
+void Release_Encoder()
+{
+ static int cnt=0;
+ OMX_ERRORTYPE result;
+
+ DEBUG_PRINT("END OF AMR ENCODING: EXITING PLEASE WAIT\n");
+ bInputEosReached_tunnel = 1;
+ event_complete();
+ cnt++;
+ if(cnt > 1)
+ {
+ /* FORCE RESET */
+ amr_enc_handle = NULL;
+ ebd_cnt=0;
+ bInputEosReached_tunnel = false;
+
+ result = OMX_FreeHandle(amr_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+
+ OMX_Deinit();
+
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...AMR ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ exit(0);
+ }
+}
+
+int Init_Encoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ typedef OMX_U8* OMX_U8_PTR;
+ char *role ="audio_encoder";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Amr_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total);
+
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&amr_enc_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component);
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(amr_enc_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+
+ if(OMX_ErrorNone != omxresult)
+ {
+ DEBUG_PRINT("Set parameter failed");
+ }
+
+ return 0;
+}
+
+int Play_Encoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file()) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+
+ /* Query the encoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(amr_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Input Port\n");
+ return -1;
+ }
+
+ pcmparam.nPortIndex = 0;
+ pcmparam.nChannels = channels;
+ pcmparam.nSamplingRate = samplerate;
+ OMX_SetParameter(amr_enc_handle,OMX_IndexParamAudioPcm,&pcmparam);
+
+
+ /* Query the encoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(amr_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Output Port\n");
+ return -1;
+ }
+
+
+ CONFIG_VERSION_SIZE(amrparam);
+
+ amrparam.nPortIndex = 1;
+ amrparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/
+ amrparam.eAMRBandMode = bandmode;
+ amrparam.eAMRDTXMode = dtxenable;
+ OMX_SetParameter(amr_enc_handle,OMX_IndexParamAudioAmr,&amrparam);
+ OMX_GetExtensionIndex(amr_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(amr_enc_handle,index,&streaminfoparam);
+ if(tunnel) {
+ #ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+ if (msm_route_stream(DIR_TX,session_id,device_id, 1))
+ {
+ perror("could not set stream routing\n");
+ return -1;
+ }
+ #endif
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n");
+ OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+ if (tunnel == 0)
+ {
+ input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(amr_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pInputBufHdrs == NULL ) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+ }
+ output_buf_cnt = outputportFmt.nBufferCountMin ;
+
+ /* Allocate buffer on encoder's O/Pp port */
+ error = Allocate_Buffer(amr_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pOutputBufHdrs == NULL ) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+
+ if (tunnel == 1)
+ {
+ DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n");
+ OMX_SendCommand(amr_enc_handle, OMX_CommandPortDisable,0,0); // disable input port
+ wait_for_event();
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n");
+ OMX_SendCommand(amr_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(amr_enc_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+if(tunnel == 0)
+{
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++) {
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ bInputEosReached = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ ret = OMX_EmptyThisBuffer(amr_enc_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock);
+ if(etb_done)
+{
+ DEBUG_PRINT("Component is waiting for EBD to be released.\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock);
+}
+
+ return 0;
+}
+
+
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_enc_handle;
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(amr_enc_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+
+
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+
+ int bytes_read=0;
+
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile);
+
+ pBufHdr->nFilledLen = bytes_read;
+ // Time stamp logic
+ ((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp = \
+
+ (unsigned long) ((total_pcm_bytes * 1000)/(samplerate * channels *2));
+
+ DEBUG_PRINT ("\n--time stamp -- %ld\n", (unsigned long)((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp);
+ if(bytes_read == 0)
+ {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+
+ total_pcm_bytes += bytes_read;
+ }
+
+ return bytes_read;;
+}
+
+
+
+//In Encoder this Should Open a PCM or WAV file for input.
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+
+ if (!tunnel)
+ {
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ }
+ if(parse_pcm_header() != 0x00)
+ {
+ DEBUG_PRINT("PCM parser failed \n");
+ return -1;
+ }
+ }
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename);
+ outputBufferFile = fopen (out_filename, "wb");
+ if (outputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ out_filename);
+ error_code = -1;
+ return error_code;
+ }
+ fseek(outputBufferFile, AMR_HEADER_SIZE, SEEK_SET);
+ return error_code;
+}
+
+static OMX_ERRORTYPE parse_pcm_header()
+{
+ struct wav_header hdr;
+
+ DEBUG_PRINT("\n***************************************************************\n");
+ if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr))
+ {
+ DEBUG_PRINT("Wav file cannot read header\n");
+ return -1;
+ }
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE)||
+ (hdr.fmt_id != ID_FMT))
+ {
+ DEBUG_PRINT("Wav file is not a riff/wave file\n");
+ return -1;
+ }
+
+ if (hdr.audio_format != FORMAT_PCM)
+ {
+ DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n",
+ hdr.audio_format, hdr.fmt_sz);
+ return -1;
+ }
+
+ DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate);
+ DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels);
+ DEBUG_PRINT("\n***************************************************************\n");
+
+ samplerate = hdr.sample_rate;
+ channels = hdr.num_channels;
+ total_pcm_bytes = 0;
+
+ return OMX_ErrorNone;
+}
diff --git a/mm-audio/aenc-evrc/Android.mk b/mm-audio/aenc-evrc/Android.mk
new file mode 100644
index 0000000..c8ee1ed
--- /dev/null
+++ b/mm-audio/aenc-evrc/Android.mk
@@ -0,0 +1,26 @@
+ifeq ($(TARGET_ARCH),arm)
+
+
+AENC_EVRC_PATH:= $(call my-dir)
+
+ifeq ($(call is-board-platform,msm8660),true)
+include $(AENC_EVRC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8960),true)
+include $(AENC_EVRC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8974),true)
+include $(AENC_EVRC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8226),true)
+include $(AENC_EVRC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8610),true)
+include $(AENC_EVRC_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,apq8084),true)
+include $(AENC_EVRC_PATH)/qdsp6/Android.mk
+endif
+
+
+endif
diff --git a/mm-audio/aenc-evrc/Makefile b/mm-audio/aenc-evrc/Makefile
new file mode 100644
index 0000000..83d822b
--- /dev/null
+++ b/mm-audio/aenc-evrc/Makefile
@@ -0,0 +1,6 @@
+all:
+ @echo "invoking omxaudio make"
+ $(MAKE) -C qdsp6
+
+install:
+ $(MAKE) -C qdsp6 install
diff --git a/mm-audio/aenc-evrc/qdsp6/Android.mk b/mm-audio/aenc-evrc/qdsp6/Android.mk
new file mode 100644
index 0000000..d38d004
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/Android.mk
@@ -0,0 +1,75 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxEvrcEnc-def := -g -O3
+libOmxEvrcEnc-def += -DQC_MODIFIED
+libOmxEvrcEnc-def += -D_ANDROID_
+libOmxEvrcEnc-def += -D_ENABLE_QC_MSG_LOG_
+libOmxEvrcEnc-def += -DVERBOSE
+libOmxEvrcEnc-def += -D_DEBUG
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+libOmxEvrcEnc-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the Shared library (libOmxEvrcEnc)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+libOmxEvrcEnc-inc := $(LOCAL_PATH)/inc
+libOmxEvrcEnc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+
+LOCAL_MODULE := libOmxEvrcEnc
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxEvrcEnc-def)
+LOCAL_C_INCLUDES := $(libOmxEvrcEnc-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libutils liblog
+
+LOCAL_SRC_FILES := src/aenc_svr.c
+LOCAL_SRC_FILES += src/omx_evrc_aenc.cpp
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+include $(BUILD_SHARED_LIBRARY)
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-aenc-omxevrc-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+mm-evrc-enc-test-inc := $(LOCAL_PATH)/inc
+mm-evrc-enc-test-inc += $(LOCAL_PATH)/test
+mm-evrc-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+mm-evrc-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+endif
+LOCAL_MODULE := mm-aenc-omxevrc-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxEvrcEnc-def)
+LOCAL_C_INCLUDES := $(mm-evrc-enc-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libmm-omxcore
+LOCAL_SHARED_LIBRARIES += libOmxEvrcEnc
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+endif
+LOCAL_SRC_FILES := test/omx_evrc_enc_test.c
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
+
diff --git a/mm-audio/aenc-evrc/qdsp6/Makefile b/mm-audio/aenc-evrc/qdsp6/Makefile
new file mode 100644
index 0000000..d0871de
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/Makefile
@@ -0,0 +1,81 @@
+# ---------------------------------------------------------------------------------
+# MM-AUDIO-OSS-8K-AENC-EVRC
+# ---------------------------------------------------------------------------------
+
+# cross-compiler flags
+CFLAGS += -Wall
+CFLAGS += -Wundef
+CFLAGS += -Wstrict-prototypes
+CFLAGS += -Wno-trigraphs
+
+# cross-compile flags specific to shared objects
+CFLAGS_SO += -fpic
+
+# required pre-processor flags
+CPPFLAGS := -D__packed__=
+CPPFLAGS += -DIMAGE_APPS_PROC
+CPPFLAGS += -DFEATURE_Q_SINGLE_LINK
+CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR
+CPPFLAGS += -DFEATURE_LINUX
+CPPFLAGS += -DFEATURE_NATIVELINUX
+CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS
+
+CPPFLAGS += -g
+CPPFALGS += -D_DEBUG
+CPPFLAGS += -Iinc
+
+# linker flags
+LDFLAGS += -L$(SYSROOT)/usr/lib
+
+# linker flags for shared objects
+LDFLAGS_SO := -shared
+
+# defintions
+LIBMAJOR := $(basename $(basename $(LIBVER)))
+LIBINSTALLDIR := $(DESTDIR)usr/lib
+INCINSTALLDIR := $(DESTDIR)usr/include
+BININSTALLDIR := $(DESTDIR)usr/bin
+
+# ---------------------------------------------------------------------------------
+# BUILD
+# ---------------------------------------------------------------------------------
+all: libOmxEvrcEnc.so.$(LIBVER) mm-aenc-omxevrc-test
+
+install:
+ echo "intalling aenc-evrc in $(DESTDIR)"
+ if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi
+ if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi
+ if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi
+ install -m 555 libOmxEvrcEnc.so.$(LIBVER) $(LIBINSTALLDIR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxEvrcEnc.so.$(LIBVER) libOmxEvrcEnc.so.$(LIBMAJOR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxEvrcEnc.so.$(LIBMAJOR) libOmxEvrcEnc.so
+ install -m 555 mm-aenc-omxevrc-test $(BININSTALLDIR)
+
+# ---------------------------------------------------------------------------------
+# COMPILE LIBRARY
+# ---------------------------------------------------------------------------------
+LDLIBS := -lpthread
+LDLIBS += -lstdc++
+LDLIBS += -lOmxCore
+
+SRCS := src/omx_evrc_aenc.cpp
+SRCS += src/aenc_svr.c
+
+libOmxEvrcEnc.so.$(LIBVER): $(SRCS)
+ $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxEvrcEnc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# COMPILE TEST APP
+# ---------------------------------------------------------------------------------
+TEST_LDLIBS := -lpthread
+TEST_LDLIBS += -ldl
+TEST_LDLIBS += -lOmxCore
+
+TEST_SRCS := test/omx_evrc_enc_test.c
+
+mm-aenc-omxevrc-test: libOmxEvrcEnc.so.$(LIBVER) $(TEST_SRCS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/aenc-evrc/qdsp6/inc/Map.h b/mm-audio/aenc-evrc/qdsp6/inc/Map.h
new file mode 100644
index 0000000..aac96fd
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/inc/Map.h
@@ -0,0 +1,244 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdio.h>
+using namespace std;
+
+template <typename T,typename T2>
+class Map
+{
+ struct node
+ {
+ T data;
+ T2 data2;
+ node* prev;
+ node* next;
+ node(T t, T2 t2,node* p, node* n) :
+ data(t), data2(t2), prev(p), next(n) {}
+ };
+ node* head;
+ node* tail;
+ node* tmp;
+ unsigned size_of_list;
+ static Map<T,T2> *m_self;
+public:
+ Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {}
+ bool empty() const { return ( !head || !tail ); }
+ operator bool() const { return !empty(); }
+ void insert(T,T2);
+ void show();
+ int size();
+ T2 find(T); // Return VALUE
+ T find_ele(T);// Check if the KEY is present or not
+ T2 begin(); //give the first ele
+ bool erase(T);
+ bool eraseall();
+ bool isempty();
+ ~Map()
+ {
+ while(head)
+ {
+ node* temp(head);
+ head=head->next;
+ size_of_list--;
+ delete temp;
+ }
+ }
+};
+
+template <typename T,typename T2>
+T2 Map<T,T2>::find(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data2;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T Map<T,T2>::find_ele(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T2 Map<T,T2>::begin()
+{
+ tmp = head;
+ if(tmp)
+ {
+ return (tmp->data2);
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::show()
+{
+ tmp = head;
+ while(tmp)
+ {
+ printf("%d-->%d\n",tmp->data,tmp->data2);
+ tmp = tmp->next;
+ }
+}
+
+template <typename T,typename T2>
+int Map<T,T2>::size()
+{
+ int count =0;
+ tmp = head;
+ while(tmp)
+ {
+ tmp = tmp->next;
+ count++;
+ }
+ return count;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::insert(T data, T2 data2)
+{
+ tail = new node(data, data2,tail, NULL);
+ if( tail->prev )
+ tail->prev->next = tail;
+
+ if( empty() )
+ {
+ head = tail;
+ tmp=head;
+ }
+ tmp = head;
+ size_of_list++;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::erase(T d)
+{
+ bool found = false;
+ tmp = head;
+ node* prevnode = tmp;
+ node *tempnode;
+
+ while(tmp)
+ {
+ if((head == tail) && (head->data == d))
+ {
+ found = true;
+ tempnode = head;
+ head = tail = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp ==head) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ tmp = tmp->next;
+ tmp->prev = NULL;
+ head = tmp;
+ tempnode->next = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp == tail) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ prevnode->next = NULL;
+ tmp->prev = NULL;
+ tail = prevnode;
+ delete tempnode;
+ break;
+ }
+ if(tmp->data == d)
+ {
+ found = true;
+ prevnode->next = tmp->next;
+ tmp->next->prev = prevnode->next;
+ tempnode = tmp;
+ //tmp = tmp->next;
+ delete tempnode;
+ break;
+ }
+ prevnode = tmp;
+ tmp = tmp->next;
+ }
+ if(found)size_of_list--;
+ return found;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::eraseall()
+{
+ // Be careful while using this method
+ // it not only removes the node but FREES(not delete) the allocated
+ // memory.
+ node *tempnode;
+ tmp = head;
+ while(head)
+ {
+ tempnode = head;
+ head = head->next;
+ tempnode->next = NULL;
+ if(tempnode->data)
+ free(tempnode->data);
+ if(tempnode->data2)
+ free(tempnode->data2);
+ delete tempnode;
+ }
+ tail = head = NULL;
+ return true;
+}
+
+
+template <typename T,typename T2>
+bool Map<T,T2>::isempty()
+{
+ if(!size_of_list) return true;
+ else return false;
+}
+
+#endif // _MAP_H_
diff --git a/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h
new file mode 100644
index 0000000..46f40ee
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h
@@ -0,0 +1,122 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef AENC_SVR_H
+#define AENC_SVR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <pthread.h>
+#include <sched.h>
+#include <utils/Log.h>
+
+#ifdef _ANDROID_
+#define LOG_TAG "QC_EVRCENC"
+#endif
+
+#ifndef LOGE
+#define LOGE ALOGE
+#endif
+
+#ifndef LOGW
+#define LOGW ALOGW
+#endif
+
+#ifndef LOGD
+#define LOGD ALOGD
+#endif
+
+#ifndef LOGV
+#define LOGV ALOGV
+#endif
+
+#ifndef LOGI
+#define LOGI ALOGI
+#endif
+
+#define DEBUG_PRINT_ERROR LOGE
+#define DEBUG_PRINT LOGI
+#define DEBUG_DETAIL LOGV
+
+typedef void (*message_func)(void* client_data, unsigned char id);
+
+/**
+ @brief audio encoder ipc info structure
+
+ */
+struct evrc_ipc_info
+{
+ pthread_t thr;
+ int pipe_in;
+ int pipe_out;
+ int dead;
+ message_func process_msg_cb;
+ void *client_data;
+ char thread_name[128];
+};
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to command server
+ */
+struct evrc_ipc_info *omx_evrc_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+
+struct evrc_ipc_info *omx_evrc_event_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+/**
+ @brief This function stop command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_evrc_thread_stop(struct evrc_ipc_info *evrc_ipc);
+
+
+/**
+ @brief This function post message in the command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_evrc_post_msg(struct evrc_ipc_info *evrc_ipc,
+ unsigned char id);
+
+void* omx_evrc_comp_timer_handler(void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AENC_SVR */
diff --git a/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h b/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h
new file mode 100644
index 0000000..fa83230
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h
@@ -0,0 +1,539 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _EVRC_ENC_H_
+#define _EVRC_ENC_H_
+/*============================================================================
+ Audio Encoder
+
+@file omx_evrc_aenc.h
+This module contains the class definition for openMAX encoder component.
+
+
+
+============================================================================*/
+
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see
+ * all DEBUG_PRINT or LOGV messaging */
+#include<stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#include "OMX_Core.h"
+#include "OMX_Audio.h"
+#include "aenc_svr.h"
+#include "qc_omx_component.h"
+#include "Map.h"
+#include <semaphore.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_qcp.h>
+extern "C" {
+ void * get_omx_component_factory_fn(void);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Module specific globals
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+#define OMX_SPEC_VERSION 0x00000101
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (x >= y?x:y)
+
+//////////////////////////////////////////////////////////////////////////////
+// Macros
+//////////////////////////////////////////////////////////////////////////////
+//
+
+
+#define PrintFrameHdr(i,bufHdr) \
+ DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\
+ i,\
+ (unsigned) bufHdr, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\
+ ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags)
+
+
+// BitMask Management logic
+#define BITS_PER_BYTE 8
+#define BITMASK_SIZE(mIndex) \
+ (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE)
+#define BITMASK_OFFSET(mIndex)\
+ ((mIndex)/BITS_PER_BYTE)
+#define BITMASK_FLAG(mIndex) \
+ (1 << ((mIndex) % BITS_PER_BYTE))
+#define BITMASK_CLEAR(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex))
+#define BITMASK_SET(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex)
+#define BITMASK_PRESENT(mArray,mIndex)\
+ ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex))
+#define BITMASK_ABSENT(mArray,mIndex)\
+ (((mArray)[BITMASK_OFFSET(mIndex)] & \
+ BITMASK_FLAG(mIndex)) == 0x0)
+
+#define OMX_CORE_NUM_INPUT_BUFFERS 2
+#define OMX_CORE_NUM_OUTPUT_BUFFERS 16
+
+#define OMX_CORE_INPUT_BUFFER_SIZE 8160 // Multiple of 160
+#define OMX_CORE_CONTROL_CMDQ_SIZE 100
+#define OMX_AENC_VOLUME_STEP 0x147
+#define OMX_AENC_MIN 0
+#define OMX_AENC_MAX 100
+#define NON_TUNNEL 1
+#define TUNNEL 0
+#define IP_PORT_BITMASK 0x02
+#define OP_PORT_BITMASK 0x01
+#define IP_OP_PORT_BITMASK 0x03
+
+#define OMX_EVRC_DEFAULT_SF 8000
+#define OMX_EVRC_DEFAULT_CH_CFG 1
+#define OMX_EVRC_DEFAULT_VOL 25
+// 14 bytes for input meta data
+#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14)
+
+#define TRUE 1
+#define FALSE 0
+
+#define NUMOFFRAMES 1
+#define MAXFRAMELENGTH 25
+#define OMX_EVRC_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT) + MAXFRAMELENGTH) \
+ + 1))
+
+#define OMX_EVRC_DEFAULT_MINRATE 4
+#define OMX_EVRC_DEFAULT_MAXRATE 4
+
+class omx_evrc_aenc;
+
+// OMX EVRC audio encoder class
+class omx_evrc_aenc: public qc_omx_component
+{
+public:
+ omx_evrc_aenc(); // constructor
+ virtual ~omx_evrc_aenc(); // destructor
+
+ OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+
+ OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp);
+
+ OMX_ERRORTYPE component_init(OMX_STRING role);
+
+ OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp,
+ OMX_U8 *role,
+ OMX_U32 index);
+
+ OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_HANDLETYPE peerComponent,
+ OMX_U32 peerPort,
+ OMX_TUNNELSETUPTYPE *tunnelSetup);
+
+ OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp,
+ OMX_STRING componentName,
+ OMX_VERSIONTYPE *componentVersion,
+ OMX_VERSIONTYPE * specVersion,
+ OMX_UUIDTYPE *componentUUID);
+
+ OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp,
+ OMX_STRING paramName,
+ OMX_INDEXTYPE *indexType);
+
+ OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp,
+ OMX_STATETYPE *state);
+
+ static void process_in_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_out_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_command_msg(void *client_data,
+ unsigned char id);
+
+ static void process_event_cb(void *client_data,
+ unsigned char id);
+
+
+ OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp,
+ OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData);
+
+ OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes,
+ OMX_U8 *buffer);
+
+ OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ void * eglImage);
+
+ bool post_command(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ // Deferred callback identifiers
+ enum
+ {
+ //Event Callbacks from the component thread context
+ OMX_COMPONENT_GENERATE_EVENT = 0x1,
+ //Buffer Done callbacks from component thread context
+ OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2,
+ OMX_COMPONENT_GENERATE_ETB = 0x3,
+ //Command
+ OMX_COMPONENT_GENERATE_COMMAND = 0x4,
+ OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05,
+ OMX_COMPONENT_GENERATE_FTB = 0x06,
+ OMX_COMPONENT_GENERATE_EOS = 0x07,
+ OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08,
+ OMX_COMPONENT_SUSPEND = 0x09,
+ OMX_COMPONENT_RESUME = 0x0a
+ };
+private:
+
+ ///////////////////////////////////////////////////////////
+ // Type definitions
+ ///////////////////////////////////////////////////////////
+ // Bit Positions
+ enum flags_bit_positions
+ {
+ // Defer transition to IDLE
+ OMX_COMPONENT_IDLE_PENDING =0x1,
+ // Defer transition to LOADING
+ OMX_COMPONENT_LOADING_PENDING =0x2,
+
+ OMX_COMPONENT_MUTED =0x3,
+
+ // Defer transition to Enable
+ OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4,
+ // Defer transition to Enable
+ OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5,
+ // Defer transition to Disable
+ OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6,
+ // Defer transition to Disable
+ OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7
+ };
+
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ input_buffer_map;
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ output_buffer_map;
+
+ enum port_indexes
+ {
+ OMX_CORE_INPUT_PORT_INDEX =0,
+ OMX_CORE_OUTPUT_PORT_INDEX =1
+ };
+
+ struct omx_event
+ {
+ unsigned param1;
+ unsigned param2;
+ unsigned id;
+ };
+
+ struct omx_cmd_queue
+ {
+ omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE];
+ unsigned m_read;
+ unsigned m_write;
+ unsigned m_size;
+
+ omx_cmd_queue();
+ ~omx_cmd_queue();
+ bool insert_entry(unsigned p1, unsigned p2, unsigned id);
+ bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id);
+ bool get_msg_id(unsigned *id);
+ bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id);
+ };
+
+ typedef struct TIMESTAMP
+ {
+ unsigned long LowPart;
+ unsigned long HighPart;
+ }__attribute__((packed)) TIMESTAMP;
+
+ typedef struct metadata_input
+ {
+ unsigned short offsetVal;
+ TIMESTAMP nTimeStamp;
+ unsigned int nFlags;
+ }__attribute__((packed)) META_IN;
+
+ typedef struct enc_meta_out
+ {
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+ } __attribute__ ((packed))ENC_META_OUT;
+
+ typedef struct
+ {
+ OMX_U32 tot_in_buf_len;
+ OMX_U32 tot_out_buf_len;
+ OMX_U32 tot_pb_time;
+ OMX_U32 fbd_cnt;
+ OMX_U32 ftb_cnt;
+ OMX_U32 etb_cnt;
+ OMX_U32 ebd_cnt;
+ }EVRC_PB_STATS;
+
+ ///////////////////////////////////////////////////////////
+ // Member variables
+ ///////////////////////////////////////////////////////////
+ OMX_U8 *m_tmp_meta_buf;
+ OMX_U8 *m_tmp_out_meta_buf;
+ OMX_U8 m_flush_cnt ;
+ OMX_U8 m_comp_deinit;
+
+ // the below var doesnt hold good if combo of use and alloc bufs are used
+ OMX_S32 m_volume;//Unit to be determined
+ OMX_PTR m_app_data;// Application data
+ int nNumInputBuf;
+ int nNumOutputBuf;
+ int m_drv_fd; // Kernel device node file handle
+ bool bFlushinprogress;
+ bool is_in_th_sleep;
+ bool is_out_th_sleep;
+ unsigned int m_flags; //encapsulate the waiting states.
+ unsigned int nTimestamp;
+ unsigned int pcm_input; //tunnel or non-tunnel
+ unsigned int m_inp_act_buf_count; // Num of Input Buffers
+ unsigned int m_out_act_buf_count; // Numb of Output Buffers
+ unsigned int m_inp_current_buf_count; // Num of Input Buffers
+ unsigned int m_out_current_buf_count; // Numb of Output Buffers
+ unsigned int output_buffer_size;
+ unsigned int input_buffer_size;
+ unsigned short m_session_id;
+ // store I/P PORT state
+ OMX_BOOL m_inp_bEnabled;
+ // store O/P PORT state
+ OMX_BOOL m_out_bEnabled;
+ //Input port Populated
+ OMX_BOOL m_inp_bPopulated;
+ //Output port Populated
+ OMX_BOOL m_out_bPopulated;
+ sem_t sem_States;
+ sem_t sem_read_msg;
+ sem_t sem_write_msg;
+
+ volatile int m_is_event_done;
+ volatile int m_is_in_th_sleep;
+ volatile int m_is_out_th_sleep;
+ input_buffer_map m_input_buf_hdrs;
+ output_buffer_map m_output_buf_hdrs;
+ omx_cmd_queue m_input_q;
+ omx_cmd_queue m_input_ctrl_cmd_q;
+ omx_cmd_queue m_input_ctrl_ebd_q;
+ omx_cmd_queue m_command_q;
+ omx_cmd_queue m_output_q;
+ omx_cmd_queue m_output_ctrl_cmd_q;
+ omx_cmd_queue m_output_ctrl_fbd_q;
+ pthread_mutexattr_t m_outputlock_attr;
+ pthread_mutexattr_t m_commandlock_attr;
+ pthread_mutexattr_t m_lock_attr;
+ pthread_mutexattr_t m_state_attr;
+ pthread_mutexattr_t m_flush_attr;
+ pthread_mutexattr_t m_in_th_attr_1;
+ pthread_mutexattr_t m_out_th_attr_1;
+ pthread_mutexattr_t m_event_attr;
+ pthread_mutexattr_t m_in_th_attr;
+ pthread_mutexattr_t m_out_th_attr;
+ pthread_mutexattr_t out_buf_count_lock_attr;
+ pthread_mutexattr_t in_buf_count_lock_attr;
+ pthread_cond_t cond;
+ pthread_cond_t in_cond;
+ pthread_cond_t out_cond;
+ pthread_mutex_t m_lock;
+ pthread_mutex_t m_commandlock;
+ pthread_mutex_t m_outputlock;
+ // Mutexes for state change
+ pthread_mutex_t m_state_lock;
+ // Mutexes for flush acks from input and output threads
+ pthread_mutex_t m_flush_lock;
+ pthread_mutex_t m_event_lock;
+ pthread_mutex_t m_in_th_lock;
+ pthread_mutex_t m_out_th_lock;
+ pthread_mutex_t m_in_th_lock_1;
+ pthread_mutex_t m_out_th_lock_1;
+ pthread_mutex_t out_buf_count_lock;
+ pthread_mutex_t in_buf_count_lock;
+
+ OMX_STATETYPE m_state; // OMX State
+ OMX_STATETYPE nState;
+ OMX_CALLBACKTYPE m_cb; // Application callbacks
+ EVRC_PB_STATS m_evrc_pb_stats;
+ struct evrc_ipc_info *m_ipc_to_in_th; // for input thread
+ struct evrc_ipc_info *m_ipc_to_out_th; // for output thread
+ struct evrc_ipc_info *m_ipc_to_cmd_th; // for command thread
+ struct evrc_ipc_info *m_ipc_to_event_th; //for txco event thread
+ OMX_PRIORITYMGMTTYPE m_priority_mgm ;
+ OMX_AUDIO_PARAM_EVRCTYPE m_evrc_param; // Cache EVRC encoder parameter
+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter
+ OMX_PARAM_COMPONENTROLETYPE component_Role;
+ OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier;
+
+ ///////////////////////////////////////////////////////////
+ // Private methods
+ ///////////////////////////////////////////////////////////
+ OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ bool allocate_done(void);
+
+ bool release_done(OMX_U32 param1);
+
+ bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true);
+
+ bool execute_input_omx_flush(void);
+
+ bool execute_output_omx_flush(void);
+
+ bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool post_input(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ bool post_output(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ void process_events(omx_evrc_aenc *client_data);
+
+ void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void wait_for_event();
+
+ void event_complete();
+
+ void in_th_goto_sleep();
+
+ void in_th_wakeup();
+
+ void out_th_goto_sleep();
+
+ void out_th_wakeup();
+
+ void flush_ack();
+ void deinit_encoder();
+
+};
+#endif
diff --git a/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c b/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c
new file mode 100644
index 0000000..2128718
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c
@@ -0,0 +1,205 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <aenc_svr.h>
+
+/**
+ @brief This function processes posted messages
+
+ Once thread is being spawned, this function is run to
+ start processing commands posted by client
+
+ @param info pointer to context
+
+ */
+void *omx_evrc_msg(void *info)
+{
+ struct evrc_ipc_info *evrc_info = (struct evrc_ipc_info*)info;
+ unsigned char id;
+ int n;
+
+ DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__);
+ while (!evrc_info->dead)
+ {
+ n = read(evrc_info->pipe_in, &id, 1);
+ if (0 == n) break;
+ if (1 == n)
+ {
+ DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n",
+ evrc_info->thread_name,
+ evrc_info->pipe_in,
+ evrc_info->pipe_out);
+
+ evrc_info->process_msg_cb(evrc_info->client_data, id);
+ }
+ if ((n < 0) && (errno != EINTR)) break;
+ }
+ DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__);
+
+ return 0;
+}
+
+void *omx_evrc_events(void *info)
+{
+ struct evrc_ipc_info *evrc_info = (struct evrc_ipc_info*)info;
+ unsigned char id = 0;
+
+ DEBUG_DETAIL("%s: message thread start\n", evrc_info->thread_name);
+ evrc_info->process_msg_cb(evrc_info->client_data, id);
+ DEBUG_DETAIL("%s: message thread stop\n", evrc_info->thread_name);
+ return 0;
+}
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to msging thread
+ */
+struct evrc_ipc_info *omx_evrc_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct evrc_ipc_info *evrc_info;
+
+ evrc_info = calloc(1, sizeof(struct evrc_ipc_info));
+ if (!evrc_info)
+ {
+ return 0;
+ }
+
+ evrc_info->client_data = client_data;
+ evrc_info->process_msg_cb = cb;
+ strlcpy(evrc_info->thread_name, th_name, sizeof(evrc_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ evrc_info->pipe_in = fds[0];
+ evrc_info->pipe_out = fds[1];
+
+ r = pthread_create(&evrc_info->thr, 0, omx_evrc_msg, evrc_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", evrc_info->thread_name);
+ return evrc_info;
+
+
+fail_thread:
+ close(evrc_info->pipe_in);
+ close(evrc_info->pipe_out);
+
+fail_pipe:
+ free(evrc_info);
+
+ return 0;
+}
+
+/**
+ * @brief This function starts command server
+ *
+ * @param cb pointer to callback function from the client
+ * @param client_data reference client wants to get back
+ * through callback
+ * @return handle to msging thread
+ * */
+struct evrc_ipc_info *omx_evrc_event_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct evrc_ipc_info *evrc_info;
+
+ evrc_info = calloc(1, sizeof(struct evrc_ipc_info));
+ if (!evrc_info)
+ {
+ return 0;
+ }
+
+ evrc_info->client_data = client_data;
+ evrc_info->process_msg_cb = cb;
+ strlcpy(evrc_info->thread_name, th_name, sizeof(evrc_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ evrc_info->pipe_in = fds[0];
+ evrc_info->pipe_out = fds[1];
+
+ r = pthread_create(&evrc_info->thr, 0, omx_evrc_events, evrc_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", evrc_info->thread_name);
+ return evrc_info;
+
+
+fail_thread:
+ close(evrc_info->pipe_in);
+ close(evrc_info->pipe_out);
+
+fail_pipe:
+ free(evrc_info);
+
+ return 0;
+}
+
+void omx_evrc_thread_stop(struct evrc_ipc_info *evrc_info) {
+ DEBUG_DETAIL("%s stop server\n", __FUNCTION__);
+ close(evrc_info->pipe_in);
+ close(evrc_info->pipe_out);
+ pthread_join(evrc_info->thr,NULL);
+ evrc_info->pipe_out = -1;
+ evrc_info->pipe_in = -1;
+ DEBUG_DETAIL("%s: message thread close fds%d %d\n", evrc_info->thread_name,
+ evrc_info->pipe_in,evrc_info->pipe_out);
+ free(evrc_info);
+}
+
+void omx_evrc_post_msg(struct evrc_ipc_info *evrc_info, unsigned char id) {
+ DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id);
+ write(evrc_info->pipe_out, &id, 1);
+}
diff --git a/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp b/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp
new file mode 100644
index 0000000..073f1ac
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp
@@ -0,0 +1,4530 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+/*============================================================================
+@file omx_aenc_evrc.c
+ This module contains the implementation of the OpenMAX core & component.
+
+*//*========================================================================*/
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+
+#include<string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "omx_evrc_aenc.h"
+#include <errno.h>
+
+using namespace std;
+#define SLEEP_MS 100
+
+// omx_cmd_queue destructor
+omx_evrc_aenc::omx_cmd_queue::~omx_cmd_queue()
+{
+ // Nothing to do
+}
+
+// omx cmd queue constructor
+omx_evrc_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0)
+{
+ memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE);
+}
+
+// omx cmd queue insert
+bool omx_evrc_aenc::omx_cmd_queue::insert_entry(unsigned p1,
+ unsigned p2,
+ unsigned id)
+{
+ bool ret = true;
+ if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_q[m_write].id = id;
+ m_q[m_write].param1 = p1;
+ m_q[m_write].param2 = p2;
+ m_write++;
+ m_size ++;
+ if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_write = 0;
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full");
+ }
+ return ret;
+}
+
+bool omx_evrc_aenc::omx_cmd_queue::pop_entry(unsigned *p1,
+ unsigned *p2, unsigned *id)
+{
+ bool ret = true;
+ if (m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ *p1 = m_q[m_read].param1;
+ *p2 = m_q[m_read].param2;
+ // Move the read pointer ahead
+ ++m_read;
+ --m_size;
+ if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_read = 0;
+
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty");
+ }
+ return ret;
+}
+
+// factory function executed by the core to create instances
+void *get_omx_component_factory_fn(void)
+{
+ return(new omx_evrc_aenc);
+}
+bool omx_evrc_aenc::omx_cmd_queue::get_msg_id(unsigned *id)
+{
+ if(m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ DEBUG_PRINT("get_msg_id=%d\n",*id);
+ }
+ else{
+ return false;
+ }
+ return true;
+}
+/*=============================================================================
+FUNCTION:
+ wait_for_event
+
+DESCRIPTION:
+ waits for a particular event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_evrc_aenc::wait_for_event()
+{
+ int rc;
+ struct timespec ts;
+ pthread_mutex_lock(&m_event_lock);
+ while (0 == m_is_event_done)
+ {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += (SLEEP_MS/1000);
+ ts.tv_nsec += ((SLEEP_MS%1000) * 1000000);
+ rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts);
+ if (rc == ETIMEDOUT && !m_is_event_done) {
+ DEBUG_PRINT("Timed out waiting for flush");
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ }
+ }
+ m_is_event_done = 0;
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+/*=============================================================================
+FUNCTION:
+ event_complete
+
+DESCRIPTION:
+ informs about the occurance of an event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_evrc_aenc::event_complete()
+{
+ pthread_mutex_lock(&m_event_lock);
+ if (0 == m_is_event_done)
+ {
+ m_is_event_done = 1;
+ pthread_cond_signal(&cond);
+ }
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+// All this non-sense because of a single evrc object
+void omx_evrc_aenc::in_th_goto_sleep()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ while (0 == m_is_in_th_sleep)
+ {
+ pthread_cond_wait(&in_cond, &m_in_th_lock);
+ }
+ m_is_in_th_sleep = 0;
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_evrc_aenc::in_th_wakeup()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ if (0 == m_is_in_th_sleep)
+ {
+ m_is_in_th_sleep = 1;
+ pthread_cond_signal(&in_cond);
+ }
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_evrc_aenc::out_th_goto_sleep()
+{
+
+ pthread_mutex_lock(&m_out_th_lock);
+ while (0 == m_is_out_th_sleep)
+ {
+ pthread_cond_wait(&out_cond, &m_out_th_lock);
+ }
+ m_is_out_th_sleep = 0;
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+
+void omx_evrc_aenc::out_th_wakeup()
+{
+ pthread_mutex_lock(&m_out_th_lock);
+ if (0 == m_is_out_th_sleep)
+ {
+ m_is_out_th_sleep = 1;
+ pthread_cond_signal(&out_cond);
+ }
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::omx_evrc_aenc
+
+DESCRIPTION
+ Constructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_evrc_aenc::omx_evrc_aenc(): m_tmp_meta_buf(NULL),
+ m_tmp_out_meta_buf(NULL),
+ m_flush_cnt(255),
+ m_comp_deinit(0),
+ m_app_data(NULL),
+ m_drv_fd(-1),
+ bFlushinprogress(0),
+ is_in_th_sleep(false),
+ is_out_th_sleep(false),
+ m_flags(0),
+ nTimestamp(0),
+ m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS),
+ m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS),
+ m_inp_current_buf_count(0),
+ m_out_current_buf_count(0),
+ output_buffer_size(OMX_EVRC_OUTPUT_BUFFER_SIZE),
+ input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE),
+ m_inp_bEnabled(OMX_TRUE),
+ m_out_bEnabled(OMX_TRUE),
+ m_inp_bPopulated(OMX_FALSE),
+ m_out_bPopulated(OMX_FALSE),
+ m_is_event_done(0),
+ m_state(OMX_StateInvalid),
+ m_ipc_to_in_th(NULL),
+ m_ipc_to_out_th(NULL),
+ m_ipc_to_cmd_th(NULL),
+ nNumOutputBuf(0),
+ nNumInputBuf(0),
+ m_volume(25)
+{
+ int cond_ret = 0;
+ memset(&m_cmp, 0, sizeof(m_cmp));
+ memset(&m_cb, 0, sizeof(m_cb));
+ memset(&m_evrc_param, 0, sizeof(m_evrc_param));
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ memset(&m_evrc_pb_stats, 0, sizeof(m_evrc_pb_stats));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+
+ pthread_mutexattr_init(&m_lock_attr);
+ pthread_mutex_init(&m_lock, &m_lock_attr);
+ pthread_mutexattr_init(&m_commandlock_attr);
+ pthread_mutex_init(&m_commandlock, &m_commandlock_attr);
+
+ pthread_mutexattr_init(&m_outputlock_attr);
+ pthread_mutex_init(&m_outputlock, &m_outputlock_attr);
+
+ pthread_mutexattr_init(&m_state_attr);
+ pthread_mutex_init(&m_state_lock, &m_state_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_flush_attr);
+ pthread_mutex_init(&m_flush_lock, &m_flush_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr);
+ pthread_mutex_init(&m_in_th_lock, &m_in_th_attr);
+
+ pthread_mutexattr_init(&m_out_th_attr);
+ pthread_mutex_init(&m_out_th_lock, &m_out_th_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr_1);
+ pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1);
+
+ pthread_mutexattr_init(&m_out_th_attr_1);
+ pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1);
+
+ pthread_mutexattr_init(&out_buf_count_lock_attr);
+ pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr);
+
+ pthread_mutexattr_init(&in_buf_count_lock_attr);
+ pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr);
+ if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+
+ sem_init(&sem_read_msg,0, 0);
+ sem_init(&sem_write_msg,0, 0);
+ sem_init(&sem_States,0, 0);
+ return;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::~omx_evrc_aenc
+
+DESCRIPTION
+ Destructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_evrc_aenc::~omx_evrc_aenc()
+{
+ DEBUG_PRINT_ERROR("EVRC Object getting destroyed comp-deinit=%d\n",
+ m_comp_deinit);
+ if ( !m_comp_deinit )
+ {
+ deinit_encoder();
+ }
+ pthread_mutexattr_destroy(&m_lock_attr);
+ pthread_mutex_destroy(&m_lock);
+
+ pthread_mutexattr_destroy(&m_commandlock_attr);
+ pthread_mutex_destroy(&m_commandlock);
+
+ pthread_mutexattr_destroy(&m_outputlock_attr);
+ pthread_mutex_destroy(&m_outputlock);
+
+ pthread_mutexattr_destroy(&m_state_attr);
+ pthread_mutex_destroy(&m_state_lock);
+
+ pthread_mutexattr_destroy(&m_event_attr);
+ pthread_mutex_destroy(&m_event_lock);
+
+ pthread_mutexattr_destroy(&m_flush_attr);
+ pthread_mutex_destroy(&m_flush_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr);
+ pthread_mutex_destroy(&m_in_th_lock);
+
+ pthread_mutexattr_destroy(&m_out_th_attr);
+ pthread_mutex_destroy(&m_out_th_lock);
+
+ pthread_mutexattr_destroy(&out_buf_count_lock_attr);
+ pthread_mutex_destroy(&out_buf_count_lock);
+
+ pthread_mutexattr_destroy(&in_buf_count_lock_attr);
+ pthread_mutex_destroy(&in_buf_count_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr_1);
+ pthread_mutex_destroy(&m_in_th_lock_1);
+
+ pthread_mutexattr_destroy(&m_out_th_attr_1);
+ pthread_mutex_destroy(&m_out_th_lock_1);
+ pthread_mutex_destroy(&out_buf_count_lock);
+ pthread_mutex_destroy(&in_buf_count_lock);
+ pthread_cond_destroy(&cond);
+ pthread_cond_destroy(&in_cond);
+ pthread_cond_destroy(&out_cond);
+ sem_destroy (&sem_read_msg);
+ sem_destroy (&sem_write_msg);
+ sem_destroy (&sem_States);
+ DEBUG_PRINT_ERROR("OMX EVRC component destroyed\n");
+ return;
+}
+
+/**
+ @brief memory function for sending EmptyBufferDone event
+ back to IL client
+
+ @param bufHdr OMX buffer header to be passed back to IL client
+ @return none
+ */
+void omx_evrc_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.EmptyBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr);
+ bufHdr->nFilledLen = 0;
+
+ m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr);
+ pthread_mutex_lock(&in_buf_count_lock);
+ m_evrc_pb_stats.ebd_cnt++;
+ nNumInputBuf--;
+ DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\
+ m_evrc_pb_stats.tot_in_buf_len,
+ nNumInputBuf, m_evrc_pb_stats.ebd_cnt);
+ pthread_mutex_unlock(&in_buf_count_lock);
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ flush_ack
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_evrc_aenc::flush_ack()
+{
+ // Decrement the FLUSH ACK count and notify the waiting recepients
+ pthread_mutex_lock(&m_flush_lock);
+ --m_flush_cnt;
+ if (0 == m_flush_cnt)
+ {
+ event_complete();
+ }
+ DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt);
+ pthread_mutex_unlock(&m_flush_lock);
+}
+void omx_evrc_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.FillBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr);
+ m_evrc_pb_stats.fbd_cnt++;
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf--;
+ DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\
+ nNumOutputBuf,
+ m_evrc_pb_stats.tot_out_buf_len,
+ m_evrc_pb_stats.fbd_cnt);
+ m_evrc_pb_stats.tot_out_buf_len += bufHdr->nFilledLen;
+ m_evrc_pb_stats.tot_pb_time = bufHdr->nTimeStamp;
+ DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n",
+ m_evrc_pb_stats.tot_in_buf_len,
+ m_evrc_pb_stats.tot_out_buf_len);
+
+ pthread_mutex_unlock(&out_buf_count_lock);
+ m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_out_port_msg
+
+DESCRIPTION:
+ Function for handling all commands from IL client
+IL client commands are processed and callbacks are generated through
+this routine Audio Command Server provides the thread context for this routine
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_evrc_aenc::process_out_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0; // qsize
+ unsigned tot_qsize = 0;
+ omx_evrc_aenc *pThis = (omx_evrc_aenc *) client_data;
+ OMX_STATETYPE state;
+
+loopback_out:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n");
+ return;
+ }
+ pthread_mutex_lock(&pThis->m_outputlock);
+
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize);
+ return;
+ }
+ if ( (state != OMX_StateExecuting) && !qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+
+ if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) )
+ {
+ // case where no port reconfig and nothing in the flush q
+ DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\
+ qsize,tot_qsize);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress))
+ {
+ DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+ }
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size,state);
+
+
+ if (qsize)
+ {
+ // process FLUSH message
+ pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // if no FLUSH and FBD's then process FTB's
+ pThis->m_output_q.pop_entry(&p1,&p2,&ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pThis->out_th_goto_sleep();
+ goto loopback_out;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_outputlock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ ident = 0;
+ DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id )
+ {
+ pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_FTB == id )
+ {
+ pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_EOS == id )
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+
+ }
+ else if(id == OMX_COMPONENT_RESUME)
+ {
+ DEBUG_PRINT("RESUMED...\n");
+ }
+ else if(id == OMX_COMPONENT_GENERATE_COMMAND)
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL("Executing FLUSH command on Output port\n");
+ pThis->execute_output_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n");
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_command_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_evrc_aenc::process_command_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ omx_evrc_aenc *pThis = (omx_evrc_aenc*)client_data;
+ pthread_mutex_lock(&pThis->m_commandlock);
+
+ qsize = pThis->m_command_q.m_size;
+ DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size,
+ pThis->m_state);
+
+ if (!qsize)
+ {
+ DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n");
+ pthread_mutex_unlock(&pThis->m_commandlock);
+ return;
+ } else
+ {
+ pThis->m_command_q.pop_entry(&p1,&p2,&ident);
+ }
+ pthread_mutex_unlock(&pThis->m_commandlock);
+
+ id = ident;
+ DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\
+ pThis->m_state,ident, \
+ pThis->m_command_q.m_size);
+
+ if (OMX_COMPONENT_GENERATE_EVENT == id)
+ {
+ if (pThis->m_cb.EventHandler)
+ {
+ if (OMX_CommandStateSet == p1)
+ {
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->m_state = (OMX_STATETYPE) p2;
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_PRINT("CMD:Process->state set to %d \n", \
+ pThis->m_state);
+
+ if (pThis->m_state == OMX_StateExecuting ||
+ pThis->m_state == OMX_StateLoaded)
+ {
+
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ if (pThis->is_in_th_sleep)
+ {
+ pThis->is_in_th_sleep = false;
+ DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n");
+ pThis->in_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ if (pThis->is_out_th_sleep)
+ {
+ DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n");
+ pThis->is_out_th_sleep = false;
+ pThis->out_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ }
+ }
+ if (OMX_StateInvalid == pThis->m_state)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ } else if ((signed)p2 == OMX_ErrorPortUnpopulated)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ p2,
+ NULL,
+ NULL );
+ } else
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventCmdComplete,
+ p1, p2, NULL );
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n");
+ }
+ } else if (OMX_COMPONENT_GENERATE_COMMAND == id)
+ {
+ pThis->send_command_proxy(&pThis->m_cmp,
+ (OMX_COMMANDTYPE)p1,
+ (OMX_U32)p2,(OMX_PTR)NULL);
+ } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id)
+ {
+ DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED");
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventPortSettingsChanged,
+ 1, 1, NULL );
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_in_port_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_evrc_aenc::process_in_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ unsigned tot_qsize = 0;
+ omx_evrc_aenc *pThis = (omx_evrc_aenc *) client_data;
+ OMX_STATETYPE state;
+
+ if (!pThis)
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n");
+ return;
+ }
+loopback_in:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n");
+ return;
+ }
+ // Protect the shared queue data structure
+ pthread_mutex_lock(&pThis->m_lock);
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP");
+ pthread_mutex_unlock(&pThis->m_lock);
+ return;
+ }
+
+ if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_DETAIL("SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ else if ((state == OMX_StatePause))
+ {
+ if(!(pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ DEBUG_DETAIL("IN: SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ }
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size, state);
+
+
+ if ( qsize )
+ {
+ // process FLUSH message
+ pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) &&
+ (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident);
+ } else if ((qsize = pThis->m_input_q.m_size) &&
+ (state == OMX_StateExecuting))
+ {
+ // if no FLUSH and EBD's then process ETB's
+ pThis->m_input_q.pop_entry(&p1, &p2, &ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\
+ state,pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_lock);
+ pThis->in_th_goto_sleep();
+ goto loopback_in;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+ if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id )
+ {
+ pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ }
+ else if(id == OMX_COMPONENT_GENERATE_EOS)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
+ OMX_EventBufferFlag, 0, 1, NULL );
+ } else if ( OMX_COMPONENT_GENERATE_ETB == id )
+ {
+ pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_COMMAND == id )
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL(" Executing FLUSH command on Input port\n");
+ pThis->execute_input_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n");
+ }
+ return;
+}
+
+/**
+ @brief member function for performing component initialization
+
+ @param role C string mandating role of this component
+ @return Error status
+ */
+OMX_ERRORTYPE omx_evrc_aenc::component_init(OMX_STRING role)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ m_state = OMX_StateLoaded;
+
+ /* DSP does not give information about the bitstream
+ randomly assign the value right now. Query will result in
+ incorrect param */
+ memset(&m_evrc_param, 0, sizeof(m_evrc_param));
+ m_evrc_param.nSize = sizeof(m_evrc_param);
+ m_evrc_param.nChannels = OMX_EVRC_DEFAULT_CH_CFG;
+ //Current DSP does not have config
+ m_evrc_param.eCDMARate = OMX_AUDIO_CDMARateFull;
+ m_evrc_param.nMinBitRate = OMX_EVRC_DEFAULT_MINRATE;
+ m_evrc_param.nMaxBitRate = OMX_EVRC_DEFAULT_MAXRATE;
+ m_volume = OMX_EVRC_DEFAULT_VOL; /* Close to unity gain */
+ memset(&m_evrc_pb_stats,0,sizeof(EVRC_PB_STATS));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ m_pcm_param.nSize = sizeof(m_pcm_param);
+ m_pcm_param.nChannels = OMX_EVRC_DEFAULT_CH_CFG;
+ m_pcm_param.nSamplingRate = OMX_EVRC_DEFAULT_SF;
+ nTimestamp = 0;
+
+
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ m_ipc_to_in_th = NULL; // Command server instance
+ m_ipc_to_out_th = NULL; // Client server instance
+ m_ipc_to_cmd_th = NULL; // command instance
+ m_is_out_th_sleep = 0;
+ m_is_in_th_sleep = 0;
+ is_out_th_sleep= false;
+
+ is_in_th_sleep=false;
+
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+ m_priority_mgm.nGroupID =0;
+ m_priority_mgm.nGroupPriority=0;
+
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified;
+
+ DEBUG_PRINT_ERROR(" component init: role = %s\n",role);
+
+ DEBUG_PRINT(" component init: role = %s\n",role);
+ component_Role.nVersion.nVersion = OMX_SPEC_VERSION;
+ if (!strcmp(role,"OMX.qcom.audio.encoder.evrc"))
+ {
+ pcm_input = 1;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole,
+ (const char*)role, sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.evrc"))
+ {
+ pcm_input = 0;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole,
+ (const char*)role, sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else
+ {
+ component_Role.nSize = sizeof("\0");
+ strlcpy((char *)component_Role.cRole,
+ (const char*)"\0",sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED is invalid\n", role);
+ }
+ if(pcm_input)
+ {
+
+
+ m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) *
+ (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN)));
+
+ if (m_tmp_meta_buf == NULL){
+ DEBUG_PRINT_ERROR("Mem alloc failed for in meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ m_tmp_out_meta_buf =
+ (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_EVRC_OUTPUT_BUFFER_SIZE);
+ if ( m_tmp_out_meta_buf == NULL ) {
+ DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+
+ if(0 == pcm_input)
+ {
+ m_drv_fd = open("/dev/msm_evrc_in",O_RDONLY);
+ DEBUG_PRINT("Driver in Tunnel mode open\n");
+ }
+ else
+ {
+ m_drv_fd = open("/dev/msm_evrc_in",O_RDWR);
+ DEBUG_PRINT("Driver in Non Tunnel mode open\n");
+ }
+ if (m_drv_fd < 0)
+ {
+ DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\
+ m_drv_fd,errno);
+
+ return OMX_ErrorInsufficientResources;
+ }
+ if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1)
+ {
+ DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n");
+ }
+ if(pcm_input)
+ {
+ if (!m_ipc_to_in_th)
+ {
+ m_ipc_to_in_th = omx_evrc_thread_create(process_in_port_msg,
+ this, (char *)"INPUT_THREAD");
+ if (!m_ipc_to_in_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start \
+ Input port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ }
+
+ if (!m_ipc_to_cmd_th)
+ {
+ m_ipc_to_cmd_th = omx_evrc_thread_create(process_command_msg,
+ this, (char *)"CMD_THREAD");
+ if (!m_ipc_to_cmd_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!!Failed to start "
+ "command message thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+
+ if (!m_ipc_to_out_th)
+ {
+ m_ipc_to_out_th = omx_evrc_thread_create(process_out_port_msg,
+ this, (char *)"OUTPUT_THREAD");
+ if (!m_ipc_to_out_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start output "
+ "port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ return eRet;
+}
+
+/**
+
+ @brief member function to retrieve version of component
+
+
+
+ @param hComp handle to this component instance
+ @param componentName name of component
+ @param componentVersion pointer to memory space which stores the
+ version number
+ @param specVersion pointer to memory sapce which stores version of
+ openMax specification
+ @param componentUUID
+ @return Error status
+ */
+OMX_ERRORTYPE omx_evrc_aenc::get_component_version
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STRING componentName,
+ OMX_OUT OMX_VERSIONTYPE* componentVersion,
+ OMX_OUT OMX_VERSIONTYPE* specVersion,
+ OMX_OUT OMX_UUIDTYPE* componentUUID)
+{
+ if((hComp == NULL) || (componentName == NULL) ||
+ (specVersion == NULL) || (componentUUID == NULL))
+ {
+ componentVersion = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ componentVersion->nVersion = OMX_SPEC_VERSION;
+ specVersion->nVersion = OMX_SPEC_VERSION;
+ return OMX_ErrorNone;
+}
+/**
+ @brief member function handles command from IL client
+
+ This function simply queue up commands from IL client.
+ Commands will be processed in command server thread context later
+
+ @param hComp handle to component instance
+ @param cmd type of command
+ @param param1 parameters associated with the command type
+ @param cmdData
+ @return Error status
+*/
+OMX_ERRORTYPE omx_evrc_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ int portIndex = (int)param1;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateInvalid == m_state)
+ {
+ return OMX_ErrorInvalidState;
+ }
+ if ( (cmd == OMX_CommandFlush) && (portIndex > 1) )
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND);
+ DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n");
+ DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1);
+ sem_wait (&sem_States);
+ DEBUG_PRINT("send_command : recieved state after semwait\n");
+ return OMX_ErrorNone;
+}
+
+/**
+ @brief member function performs actual processing of commands excluding
+ empty buffer call
+
+ @param hComp handle to component
+ @param cmd command type
+ @param param1 parameter associated with the command
+ @param cmdData
+
+ @return error status
+*/
+OMX_ERRORTYPE omx_evrc_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ // Handle only IDLE and executing
+ OMX_STATETYPE eState = (OMX_STATETYPE) param1;
+ int bFlag = 1;
+ nState = eState;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_CommandStateSet == cmd)
+ {
+ /***************************/
+ /* Current State is Loaded */
+ /***************************/
+ if (OMX_StateLoaded == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+
+ if (allocate_done() ||
+ (m_inp_bEnabled == OMX_FALSE
+ && m_out_bEnabled == OMX_FALSE))
+ {
+ DEBUG_PRINT("SCP-->Allocate Done Complete\n");
+ }
+ else
+ {
+ DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ bFlag = 0;
+ }
+
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ }
+
+ else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n");
+ eRet = OMX_ErrorNone;
+ }
+
+ else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ m_state = OMX_StateInvalid;
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /***************************/
+ /* Current State is IDLE */
+ /***************************/
+ else if (OMX_StateIdle == m_state)
+ {
+ if (OMX_StateLoaded == eState)
+ {
+ if (release_done(-1))
+ {
+ if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("SCP:Idle->Loaded,\
+ ioctl stop failed %d\n", errno);
+ }
+
+ nTimestamp=0;
+
+ DEBUG_PRINT("SCP-->Idle to Loaded\n");
+ } else
+ {
+ DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING);
+ // Skip the event notification
+ bFlag = 0;
+ }
+ }
+ else if (OMX_StateExecuting == eState)
+ {
+
+ struct msm_audio_evrc_enc_config drv_evrc_enc_config;
+ struct msm_audio_stream_config drv_stream_config;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+
+ if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+ if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+
+ if(ioctl(m_drv_fd, AUDIO_GET_EVRC_ENC_CONFIG,
+ &drv_evrc_enc_config) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_EVRC_ENC_CONFIG failed,\
+ errno[%d]\n", errno);
+ }
+ drv_evrc_enc_config.min_bit_rate = m_evrc_param.nMinBitRate;
+ drv_evrc_enc_config.max_bit_rate = m_evrc_param.nMaxBitRate;
+ if(ioctl(m_drv_fd, AUDIO_SET_EVRC_ENC_CONFIG, &drv_evrc_enc_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_EVRC_ENC_CONFIG failed,\
+ errno[%d]\n", errno);
+ }
+ if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ buf_cfg.meta_info_enable = 1;
+ buf_cfg.frames_per_buf = NUMOFFRAMES;
+ if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ if(pcm_input)
+ {
+ if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ pcm_cfg.channel_count = m_pcm_param.nChannels;
+ pcm_cfg.sample_rate = m_pcm_param.nSamplingRate;
+ DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+
+ if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ }
+ if(ioctl(m_drv_fd, AUDIO_START, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n",
+ errno);
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+
+ }
+ DEBUG_PRINT("SCP-->Idle to Executing\n");
+ nState = eState;
+ } else if (eState == OMX_StateIdle)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n");
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /******************************/
+ /* Current State is Executing */
+ /******************************/
+ else if (OMX_StateExecuting == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+ DEBUG_PRINT("SCP-->Executing to Idle \n");
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+
+ } else if (OMX_StatePause == eState)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED PAUSE STATE\n");
+ DEBUG_DETAIL("*************************\n");
+ //ioctl(m_drv_fd, AUDIO_PAUSE, 0);
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n",
+ eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /***************************/
+ /* Current State is Pause */
+ /***************************/
+ else if (OMX_StatePause == m_state)
+ {
+ if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) )
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if(is_out_th_sleep)
+ {
+ DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n");
+ is_out_th_sleep = false;
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ }
+ if ( OMX_StateExecuting == eState )
+ {
+ nState = eState;
+ } else if ( OMX_StateIdle == eState )
+ {
+ DEBUG_PRINT("SCP-->Paused to Idle \n");
+ DEBUG_PRINT ("\n Internal flush issued");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+ } else if ( eState == OMX_StateLoaded )
+ {
+ DEBUG_PRINT("\n Pause --> loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n Pause --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("\n Pause --> Pause \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n Pause --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /**************************************/
+ /* Current State is WaitForResources */
+ /**************************************/
+ else if (m_state == OMX_StateWaitForResources)
+ {
+ if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n");
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: \
+ WaitForResources-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n",
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /****************************/
+ /* Current State is Invalid */
+ /****************************/
+ else if (m_state == OMX_StateInvalid)
+ {
+ if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState
+ || OMX_StateIdle == eState || OMX_StateExecuting == eState
+ || OMX_StatePause == eState || OMX_StateInvalid == eState)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing"
+ "/Pause/Invalid/WaitForResources\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else if (OMX_CommandFlush == cmd)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1);
+ DEBUG_DETAIL("*************************\n");
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX ||
+ param1 == OMX_CORE_OUTPUT_PORT_INDEX ||
+ (signed)param1 == -1 )
+ {
+ execute_omx_flush(param1);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError,
+ OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL );
+ }
+ } else if ( cmd == OMX_CommandPortDisable )
+ {
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL )
+ {
+ DEBUG_PRINT("SCP: Disabling Input port Indx\n");
+ m_inp_bEnabled = OMX_FALSE;
+ if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(0) )
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_inp_bEnabled = %d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+
+ else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\
+ " param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+
+ }
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+
+ DEBUG_PRINT("SCP: Disabling Output port Indx\n");
+ m_out_bEnabled = OMX_FALSE;
+ if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(1))
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_out_bEnabled = %d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\
+ "param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID");
+ }
+
+ } else if (cmd == OMX_CommandPortEnable)
+ {
+ bFlag = 0;
+ if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ m_inp_bEnabled = OMX_TRUE;
+ DEBUG_PRINT("SCP: Enabling Input port Indx\n");
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_inp_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+
+ } else
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ }
+
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ DEBUG_PRINT("SCP: Enabling Output port Indx\n");
+ m_out_bEnabled = OMX_TRUE;
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_out_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID");
+ }
+
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd);
+ eRet = OMX_ErrorNotImplemented;
+ }
+ DEBUG_PRINT("posting sem_States\n");
+ sem_post (&sem_States);
+ if (eRet == OMX_ErrorNone && bFlag)
+ {
+ post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT);
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] param1
+ [IN] cmd_cmpl
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_evrc_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl)
+{
+ bool bRet = true;
+
+ DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1);
+ struct timespec abs_timeout;
+ abs_timeout.tv_sec = 1;
+ abs_timeout.tv_nsec = 0;
+
+ if ((signed)param1 == -1)
+ {
+ bFlushinprogress = true;
+ DEBUG_PRINT("Execute flush for both I/p O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+
+ // Send Flush commands to input and output threads
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ // Send Flush to the kernel so that the in and out buffers are released
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+
+ DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\
+ param1,cmd_cmpl);
+
+ // If not going to idle state, Send FLUSH complete message
+ // to the Client, now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n");
+ }
+ bFlushinprogress = false;
+ }
+ else if (param1 == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("Execute FLUSH for I/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ //sleep till the FLUSH ACK are done by both the input and output threads
+ DEBUG_DETAIL("Executing FLUSH for I/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+ DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1);
+
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1)
+ {
+ DEBUG_PRINT("Executing FLUSH for O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ DEBUG_DETAIL("Executing FLUSH for O/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1)
+ DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ wait_for_event();
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ }
+ DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1);
+ } else
+ {
+ DEBUG_PRINT("Invalid Port ID[%lu]",param1);
+ }
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_input_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_evrc_aenc::execute_input_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on input port");
+
+ pthread_mutex_lock(&m_lock);
+ do
+ {
+ qsize = m_input_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += m_input_ctrl_ebd_q.m_size;
+
+ DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,qsize);
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_lock);
+ break;
+ }
+ if (qsize)
+ {
+ m_input_q.pop_entry(&p1, &p2, &ident);
+ if ((ident == OMX_COMPONENT_GENERATE_ETB) ||
+ (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf);
+ omx_buf->nFilledLen = 0;
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else if (m_input_ctrl_ebd_q.m_size)
+ {
+ m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident);
+ if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ omx_buf->nFilledLen = 0;
+ DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf);
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else
+ {
+ }
+ }while (tot_qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("IN-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_lock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_output_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_evrc_aenc::execute_output_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on output port");
+
+ pthread_mutex_lock(&m_outputlock);
+ do
+ {
+ qsize = m_output_q.m_size;
+ DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,qsize);
+ tot_qsize = qsize;
+ tot_qsize += m_output_ctrl_fbd_q.m_size;
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_outputlock);
+ break;
+ }
+ if (qsize)
+ {
+ m_output_q.pop_entry(&p1,&p2,&ident);
+ if ( (OMX_COMPONENT_GENERATE_FTB == ident) ||
+ (OMX_COMPONENT_GENERATE_FRAME_DONE == ident))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FBD FROM FLUSH");
+ }
+ } else if ((qsize = m_output_ctrl_fbd_q.m_size))
+ {
+ m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident);
+ if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH");
+ }
+ }
+ }while (qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("OUT-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_outputlock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_input
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_evrc_aenc::post_input(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+ pthread_mutex_lock(&m_lock);
+
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND))
+ {
+ // insert flush message and ebd
+ m_input_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id))
+ {
+ // insert ebd
+ m_input_ctrl_ebd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ // ETBS in this queue
+ m_input_q.insert_entry(p1,p2,id);
+ }
+
+ if (m_ipc_to_in_th)
+ {
+ bRet = true;
+ omx_evrc_post_msg(m_ipc_to_in_th, id);
+ }
+
+ DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\
+ m_state,
+ id,
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,
+ m_input_q.m_size);
+
+ pthread_mutex_unlock(&m_lock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_command
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_evrc_aenc::post_command(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_commandlock);
+
+ m_command_q.insert_entry(p1,p2,id);
+
+ if (m_ipc_to_cmd_th)
+ {
+ bRet = true;
+ omx_evrc_post_msg(m_ipc_to_cmd_th, id);
+ }
+
+ DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\
+ m_state,
+ id,
+ m_command_q.m_size,
+ m_flags >> 3);
+
+ pthread_mutex_unlock(&m_commandlock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_output
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_evrc_aenc::post_output(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_outputlock);
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)
+ || (id == OMX_COMPONENT_RESUME))
+ {
+ // insert flush message and fbd
+ m_output_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) )
+ {
+ // insert flush message and fbd
+ m_output_ctrl_fbd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ m_output_q.insert_entry(p1,p2,id);
+ }
+ if ( m_ipc_to_out_th )
+ {
+ bRet = true;
+ omx_evrc_post_msg(m_ipc_to_out_th, id);
+ }
+ DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ m_state,
+ id,
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,
+ m_output_q.m_size);
+
+ pthread_mutex_unlock(&m_outputlock);
+ return bRet;
+}
+/**
+ @brief member function that return parameters to IL client
+
+ @param hComp handle to component instance
+ @param paramIndex Parameter type
+ @param paramData pointer to memory space which would hold the
+ paramter
+ @return error status
+*/
+OMX_ERRORTYPE omx_evrc_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_INOUT OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Param in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("get_parameter: paramData is NULL\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ DEBUG_PRINT("OMX_IndexParamPortDefinition " \
+ "portDefn->nPortIndex = %lu\n",
+ portDefn->nPortIndex);
+
+ portDefn->nVersion.nVersion = OMX_SPEC_VERSION;
+ portDefn->nSize = sizeof(portDefn);
+ portDefn->eDomain = OMX_PortDomainAudio;
+
+ if (0 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirInput;
+ portDefn->bEnabled = m_inp_bEnabled;
+ portDefn->bPopulated = m_inp_bPopulated;
+ portDefn->nBufferCountActual = m_inp_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS;
+ portDefn->nBufferSize = input_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+ portDefn->format.audio.pNativeRender = 0;
+ } else if (1 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirOutput;
+ portDefn->bEnabled = m_out_bEnabled;
+ portDefn->bPopulated = m_out_bPopulated;
+ portDefn->nBufferCountActual = m_out_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS;
+ portDefn->nBufferSize = output_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingEVRC;
+ portDefn->format.audio.pNativeRender = 0;
+ } else
+ {
+ portDefn->eDir = OMX_DirMax;
+ DEBUG_PRINT_ERROR("Bad Port idx %d\n",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioInit\n");
+
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 2;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n");
+ portFormatType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portFormatType->nSize = sizeof(portFormatType);
+
+ if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex)
+ {
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\
+ "%lu\n", portFormatType->nIndex);
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingEVRC;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n",
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioEvrc:
+ {
+ OMX_AUDIO_PARAM_EVRCTYPE *evrcParam =
+ (OMX_AUDIO_PARAM_EVRCTYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioEvrc\n");
+ if (OMX_CORE_OUTPUT_PORT_INDEX== evrcParam->nPortIndex)
+ {
+ memcpy(evrcParam,&m_evrc_param,
+ sizeof(OMX_AUDIO_PARAM_EVRCTYPE));
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioEvrc "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)evrcParam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case QOMX_IndexParamAudioSessionId:
+ {
+ QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam =
+ (QOMX_AUDIO_STREAM_INFO_DATA *) paramData;
+ streaminfoparam->sessionId = m_session_id;
+ break;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(pcmparam,&m_pcm_param,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+ DEBUG_PRINT("get_parameter: Sampling rate %lu",\
+ pcmparam->nSamplingRate);
+ DEBUG_PRINT("get_parameter: Number of channels %lu",\
+ pcmparam->nChannels);
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamComponentSuspended:
+ {
+ OMX_PARAM_SUSPENSIONTYPE *suspend =
+ (OMX_PARAM_SUSPENSIONTYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n",
+ suspend);
+ break;
+ }
+ case OMX_IndexParamVideoInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ OMX_PRIORITYMGMTTYPE *priorityMgmtType =
+ (OMX_PRIORITYMGMTTYPE*)paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n");
+ priorityMgmtType->nSize = sizeof(priorityMgmtType);
+ priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION;
+ priorityMgmtType->nGroupID = m_priority_mgm.nGroupID;
+ priorityMgmtType->nGroupPriority =
+ m_priority_mgm.nGroupPriority;
+ break;
+ }
+ case OMX_IndexParamImageInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+
+ bufferSupplierType->nSize = sizeof(bufferSupplierType);
+ bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION;
+ if (OMX_CORE_INPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:"\
+ "OMX_IndexParamCompBufferSupplier eRet"\
+ "%08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ /*Component should support this port definition*/
+ case OMX_IndexParamOtherInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ componentRole->nSize = component_Role.nSize;
+ componentRole->nVersion = component_Role.nVersion;
+ strlcpy((char *)componentRole->cRole,
+ (const char*)component_Role.cRole,
+ sizeof(componentRole->cRole));
+ DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n",
+ component_Role.nSize,
+ component_Role.nVersion,
+ component_Role.cRole);
+ break;
+
+ }
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+
+}
+
+/**
+ @brief member function that set paramter from IL client
+
+ @param hComp handle to component instance
+ @param paramIndex parameter type
+ @param paramData pointer to memory space which holds the paramter
+ @return error status
+ */
+OMX_ERRORTYPE omx_evrc_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_IN OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("set_parameter is not in proper state\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("param data is NULL");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamAudioEvrc:
+ {
+ DEBUG_PRINT("OMX_IndexParamAudioEvrc");
+ OMX_AUDIO_PARAM_AMRTYPE *evrcparam
+ = (OMX_AUDIO_PARAM_AMRTYPE *) paramData;
+ memcpy(&m_evrc_param,evrcparam,
+ sizeof(OMX_AUDIO_PARAM_EVRCTYPE));
+ break;
+ }
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ if (((m_state == OMX_StateLoaded)&&
+ !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources &&
+ ((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == true)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == true)))
+ ||(((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == false)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == false)) &&
+ (m_state != OMX_StateWaitForResources)))
+ {
+ DEBUG_PRINT("Set Parameter called in valid state\n");
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex "
+ "= %lu\n",portDefn->nPortIndex);
+ if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_INPUT_BUFFERS )
+ {
+ m_inp_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS;
+ }
+ input_buffer_size = portDefn->nBufferSize;
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_OUTPUT_BUFFERS )
+ {
+ m_out_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS;
+ }
+ output_buffer_size = portDefn->nBufferSize;
+ } else
+ {
+ DEBUG_PRINT(" set_parameter: Bad Port idx %d",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n");
+
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ OMX_PRIORITYMGMTTYPE *priorityMgmtype
+ = (OMX_PRIORITYMGMTTYPE*) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n",
+ priorityMgmtype->nGroupID);
+
+ DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n",
+ priorityMgmtype->nGroupPriority);
+
+ m_priority_mgm.nGroupID = priorityMgmtype->nGroupID;
+ m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority;
+
+ break;
+ }
+ case OMX_IndexParamAudioPortFormat:
+ {
+
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n");
+
+ if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex)
+ {
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\
+ " %lu\n", portFormatType->nIndex);
+ portFormatType->eEncoding = OMX_AUDIO_CodingEVRC;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("set_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\
+ bufferSupplierType->eBufferSupplier);
+
+ if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX
+ || bufferSupplierType->nPortIndex ==
+ OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("set_parameter:\
+ OMX_IndexParamCompBufferSupplier\n");
+ m_buffer_supplier.eBufferSupplier =
+ bufferSupplierType->eBufferSupplier;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_param:\
+ IndexParamCompBufferSup %08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ break; }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n");
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam
+ = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(&m_pcm_param,pcmparam,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+ DEBUG_PRINT("set_pcm_parameter: %lu %lu",\
+ m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm "
+ "OMX_ErrorBadPortIndex %d\n",
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamSuspensionPolicy:
+ {
+ eRet = OMX_ErrorNotImplemented;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ component_Role.nSize = componentRole->nSize;
+ component_Role.nVersion = componentRole->nVersion;
+ strlcpy((char *)component_Role.cRole,
+ (const char*)componentRole->cRole,
+ sizeof(component_Role.cRole));
+ break;
+ }
+
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::GetConfig
+
+DESCRIPTION
+ OMX Get Config Method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_INOUT OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *volume =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex)
+ {
+ volume->nSize = sizeof(volume);
+ volume->nVersion.nVersion = OMX_SPEC_VERSION;
+ volume->bLinear = OMX_TRUE;
+ volume->sVolume.nValue = m_volume;
+ volume->sVolume.nMax = OMX_AENC_MAX;
+ volume->sVolume.nMin = OMX_AENC_MIN;
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute =
+ (OMX_AUDIO_CONFIG_MUTETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex)
+ {
+ mute->nSize = sizeof(mute);
+ mute->nVersion.nVersion = OMX_SPEC_VERSION;
+ mute->bMute = (BITMASK_PRESENT(&m_flags,
+ OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::SetConfig
+
+DESCRIPTION
+ OMX Set Config method implementation
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_IN OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Set Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if ( m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *vol =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData;
+ if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if ((vol->sVolume.nValue <= OMX_AENC_MAX) &&
+ (vol->sVolume.nValue >= OMX_AENC_MIN))
+ {
+ m_volume = vol->sVolume.nValue;
+ if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED))
+ {
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+
+ } else
+ {
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*)
+ configData;
+ if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if (mute->bMute == OMX_TRUE)
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */
+ } else
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::GetExtensionIndex
+
+DESCRIPTION
+ OMX GetExtensionIndex method implementaion. <TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::get_extension_index(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_STRING paramName,
+ OMX_OUT OMX_INDEXTYPE* indexType)
+{
+ if((hComp == NULL) || (paramName == NULL) || (indexType == NULL))
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId",
+ strlen("OMX.Qualcomm.index.audio.sessionId")) == 0)
+ {
+ *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId;
+ DEBUG_PRINT("Extension index type - %d\n", *indexType);
+
+ }
+ else
+ {
+ return OMX_ErrorBadParameter;
+
+ }
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::GetState
+
+DESCRIPTION
+ Returns the state information back to the caller.<TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STATETYPE* state)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ *state = m_state;
+ DEBUG_PRINT("Returning the state %d\n",*state);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::ComponentTunnelRequest
+
+DESCRIPTION
+ OMX Component Tunnel Request method implementation. <TBD>
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::component_tunnel_request
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_HANDLETYPE peerComponent,
+ OMX_IN OMX_U32 peerPort,
+ OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup)
+{
+ DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n");
+
+ if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL))
+ {
+ port = 0;
+ peerPort = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::AllocateInputBuffer
+
+DESCRIPTION
+ Helper function for allocate buffer in the input pin
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::allocate_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+ if(m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc((nBufSize + \
+ sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1);
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ free(buf_ptr);
+ return OMX_ErrorBadParameter;
+ }
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+
+ m_inp_current_buf_count++;
+ DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%u \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,
+ m_inp_current_buf_count, bytes);
+
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+OMX_ERRORTYPE omx_evrc_aenc::allocate_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+ buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) +
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+ DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d "\
+ "bytes=%lu",bufHdr, bufHdr->pBuffer,\
+ m_out_current_buf_count, bytes);
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+
+// AllocateBuffer -- API Call
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::AllocateBuffer
+
+DESCRIPTION
+ Returns zero if all the buffers released..
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::allocate_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type
+
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ // What if the client calls again.
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",
+ (int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("allocate_buffer: before allocate_done \n");
+ if (allocate_done())
+ {
+ DEBUG_PRINT("allocate_buffer: after allocate_done \n");
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("allocate_buffer: post idle transition event \n");
+ }
+ DEBUG_PRINT("allocate_buffer: complete \n");
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ m_out_bEnabled = OMX_TRUE;
+
+ DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("AB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ }
+ DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet);
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_buffer
+
+DESCRIPTION:
+ OMX Use Buffer method implementation.
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_evrc_aenc::use_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("Checking for Output Allocate buffer Done");
+ if (allocate_done())
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("UB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ }
+ }
+ DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet);
+ return eRet;
+}
+/*=============================================================================
+FUNCTION:
+ use_input_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the input pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_evrc_aenc::use_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if(bytes < input_buffer_size)
+ {
+ /* return if i\p buffer size provided by client
+ is less than min i\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+ if (m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ input_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+ m_inp_current_buf_count++;
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_output_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the output pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_evrc_aenc::use_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (bytes < output_buffer_size)
+ {
+ /* return if o\p buffer size provided by client
+ is less than min o\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+
+ DEBUG_PRINT("Inside omx_evrc_aenc::use_output_buffer");
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer);
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \
+ len=%lu\n", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ output_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_evrc_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_input_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_input_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_evrc_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_output_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_output_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+// Free Buffer - API call
+/**
+ @brief member function that handles free buffer command from IL client
+
+ This function is a block-call function that handles IL client request to
+ freeing the buffer
+
+ @param hComp handle to component instance
+ @param port id of port which holds the buffer
+ @param buffer buffer header
+ @return Error status
+*/
+OMX_ERRORTYPE omx_evrc_aenc::free_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("Free_Buffer buf %p\n", buffer);
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateIdle &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ DEBUG_PRINT(" free buffer while Component in Loading pending\n");
+ } else if ((m_inp_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_INPUT_PORT_INDEX)||
+ (m_out_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_OUTPUT_PORT_INDEX))
+ {
+ DEBUG_PRINT("Free Buffer while port %lu disabled\n", port);
+ } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause)
+ {
+ DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\
+ OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ return eRet;
+ } else
+ {
+ DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\
+ disabled:OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ if (m_inp_current_buf_count != 0)
+ {
+ m_inp_bPopulated = OMX_FALSE;
+ if (true == search_input_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer);
+ m_input_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_inp_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \
+ Invalid Input buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \
+ came out Invalid\n");
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING)
+ && release_done(0))
+ {
+ DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ if (m_out_current_buf_count != 0)
+ {
+ m_out_bPopulated = OMX_FALSE;
+ if (true == search_output_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer);
+ m_output_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_out_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT("Free_Buf:Error-->free_buffer , \
+ Invalid Output buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING)
+ && release_done(1))
+ {
+ DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if ((OMX_ErrorNone == eRet) &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ if (release_done(-1))
+ {
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0)
+ DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n");
+ else
+ DEBUG_PRINT("AUDIO STOP in free buffer passed\n");
+
+
+ DEBUG_PRINT("Free_Buf: Free buffer\n");
+
+
+ // Send the callback now
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING);
+ DEBUG_PRINT("Before OMX_StateLoaded \
+ OMX_COMPONENT_GENERATE_EVENT\n");
+ post_command(OMX_CommandStateSet,
+ OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n");
+
+ }
+ }
+ return eRet;
+}
+
+
+/**
+ @brief member function that that handles empty this buffer command
+
+ This function meremly queue up the command and data would be consumed
+ in command server thread context
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_evrc_aenc::empty_this_buffer(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \
+ buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf));
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("Empty this buffer in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (!m_inp_bEnabled)
+ {
+ DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\
+ "Port Status %d \n", m_inp_bEnabled);
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_evrc_aenc::etb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_evrc_aenc::etb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+
+ if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ if ((m_state != OMX_StateExecuting) &&
+ (m_state != OMX_StatePause))
+ {
+ DEBUG_PRINT_ERROR("Invalid state\n");
+ eRet = OMX_ErrorInvalidState;
+ }
+ if (OMX_ErrorNone == eRet)
+ {
+ if (search_input_bufhdr(buffer) == true)
+ {
+ post_input((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ pthread_mutex_lock(&in_buf_count_lock);
+ nNumInputBuf++;
+ m_evrc_pb_stats.etb_cnt++;
+ pthread_mutex_unlock(&in_buf_count_lock);
+ return eRet;
+}
+/**
+ @brief member function that writes data to kernel driver
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_evrc_aenc::empty_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ META_IN meta_in;
+ //Pointer to the starting location of the data to be transcoded
+ OMX_U8 *srcStart;
+ //The total length of the data to be transcoded
+ srcStart = buffer->pBuffer;
+ OMX_U8 *data = NULL;
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer);
+ memset(&meta_in,0,sizeof(meta_in));
+ if ( search_input_bufhdr(buffer) == false )
+ {
+ DEBUG_PRINT("ETBP: INVALID BUF HDR\n");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorBadParameter;
+ }
+ if (m_tmp_meta_buf)
+ {
+ data = m_tmp_meta_buf;
+
+ // copy the metadata info from the BufHdr and insert to payload
+ meta_in.offsetVal = sizeof(META_IN);
+ meta_in.nTimeStamp.LowPart =
+ ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF);
+ meta_in.nTimeStamp.HighPart =
+ (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF);
+ meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS;
+ if(buffer->nFlags & OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT("EOS OCCURED \n");
+ meta_in.nFlags |= OMX_BUFFERFLAG_EOS;
+ }
+ memcpy(data,&meta_in, meta_in.offsetVal);
+ DEBUG_PRINT("meta_in.nFlags = %d\n",meta_in.nFlags);
+ }
+
+ memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen);
+ write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN));
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (OMX_StateExecuting == state)
+ {
+ DEBUG_DETAIL("In Exe state, EBD CB");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ } else
+ {
+ /* Assume empty this buffer function has already checked
+ validity of buffer */
+ DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer);
+ post_input((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_BUFFER_DONE);
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE omx_evrc_aenc::fill_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ ENC_META_OUT *meta_out = NULL;
+ int nReadbytes = 0;
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (true == search_output_bufhdr(buffer))
+ {
+ DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd);
+ nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size );
+ DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\
+ buffer->nAllocLen,buffer->pBuffer,
+ nReadbytes,nNumOutputBuf);
+ if (nReadbytes <= 0) {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorNone;
+ } else
+ DEBUG_PRINT("Read bytes %d\n",nReadbytes);
+ // Buffer from Driver will have
+ // 1 byte => Nr of frame field
+ // (sizeof(ENC_META_OUT) * Nr of frame) bytes => meta_out->offset_to_frame
+ // Frame Size * Nr of frame =>
+
+ meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char));
+ buffer->nTimeStamp = (((OMX_TICKS) meta_out->msw_ts << 32)+
+ meta_out->lsw_ts);
+ buffer->nFlags |= meta_out->nflags;
+ buffer->nOffset = meta_out->offset_to_frame + sizeof(unsigned char);
+ buffer->nFilledLen = nReadbytes - buffer->nOffset;
+ nTimestamp = buffer->nTimeStamp;
+ DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \
+ timestamp %lld\n", meta_out->nflags,
+ meta_out->frame_size, meta_out->offset_to_frame,
+ buffer->nTimeStamp);
+
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n");
+ m_cb.EventHandler(&m_cmp,
+ m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+ }
+
+ return OMX_ErrorNone;
+ }
+ DEBUG_PRINT("nState %d \n",nState );
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (state == OMX_StatePause)
+ {
+ DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\
+ state);
+ post_output((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_FRAME_DONE);
+ }
+ else
+ {
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+
+ }
+
+ }
+ else
+ DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n");
+
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::FillThisBuffer
+
+DESCRIPTION
+ IL client uses this method to release the frame buffer
+ after displaying them.
+
+
+
+PARAMETERS
+
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::fill_this_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_evrc_aenc::ftb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_bEnabled == OMX_FALSE)
+ {
+ return OMX_ErrorIncorrectStateOperation;
+ }
+
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_evrc_aenc::ftb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+ if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf++;
+ m_evrc_pb_stats.ftb_cnt++;
+ DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf);
+ pthread_mutex_unlock(&out_buf_count_lock);
+ post_output((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB);
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::SetCallbacks
+
+DESCRIPTION
+ Set the callbacks.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::set_callbacks(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_CALLBACKTYPE* callbacks,
+ OMX_IN OMX_PTR appData)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ m_cb = *callbacks;
+ m_app_data = appData;
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::ComponentDeInit
+
+DESCRIPTION
+ Destroys the component and release memory allocated to the heap.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state)
+ {
+ DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n",
+ m_state);
+ }
+ deinit_encoder();
+
+DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::deinit_encoder
+
+DESCRIPTION
+ Closes all the threads and release memory allocated to the heap.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ None.
+
+========================================================================== */
+void omx_evrc_aenc::deinit_encoder()
+{
+ DEBUG_PRINT("Component-deinit being processed\n");
+ DEBUG_PRINT("********************************\n");
+ DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\
+ m_evrc_pb_stats.tot_in_buf_len,
+ m_evrc_pb_stats.tot_out_buf_len,
+ m_evrc_pb_stats.tot_pb_time);
+ DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\
+ m_evrc_pb_stats.fbd_cnt,m_evrc_pb_stats.ftb_cnt,
+ m_evrc_pb_stats.etb_cnt,
+ m_evrc_pb_stats.ebd_cnt);
+ memset(&m_evrc_pb_stats,0,sizeof(EVRC_PB_STATS));
+
+ if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state))
+ {
+ DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\
+ m_state);
+ // Get back any buffers from driver
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+ // force state change to loaded so that all threads can be exited
+ pthread_mutex_lock(&m_state_lock);
+ m_state = OMX_StateLoaded;
+ pthread_mutex_unlock(&m_state_lock);
+ DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\
+ m_inp_current_buf_count,
+ m_input_buf_hdrs.size());
+ m_input_buf_hdrs.eraseall();
+ DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\
+ m_out_current_buf_count,
+ m_output_buf_hdrs.size());
+ m_output_buf_hdrs.eraseall();
+
+ }
+ if(pcm_input)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ if(pcm_input)
+ {
+ if (m_ipc_to_in_th != NULL)
+ {
+ omx_evrc_thread_stop(m_ipc_to_in_th);
+ m_ipc_to_in_th = NULL;
+ }
+ }
+
+ if (m_ipc_to_cmd_th != NULL)
+ {
+ omx_evrc_thread_stop(m_ipc_to_cmd_th);
+ m_ipc_to_cmd_th = NULL;
+ }
+ if (m_ipc_to_out_th != NULL)
+ {
+ DEBUG_DETAIL("Inside omx_evrc_thread_stop\n");
+ omx_evrc_thread_stop(m_ipc_to_out_th);
+ m_ipc_to_out_th = NULL;
+ }
+
+
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0)
+ DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n");
+
+ if(pcm_input && m_tmp_meta_buf )
+ {
+ free(m_tmp_meta_buf);
+ }
+
+ if(m_tmp_out_meta_buf)
+ {
+ free(m_tmp_out_meta_buf);
+ }
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ bFlushinprogress = 0;
+
+ m_inp_current_buf_count=0;
+ m_out_current_buf_count=0;
+ m_out_act_buf_count = 0;
+ m_inp_act_buf_count = 0;
+ m_inp_bEnabled = OMX_FALSE;
+ m_out_bEnabled = OMX_FALSE;
+ m_inp_bPopulated = OMX_FALSE;
+ m_out_bPopulated = OMX_FALSE;
+
+ if ( m_drv_fd >= 0 )
+ {
+ if(close(m_drv_fd) < 0)
+ DEBUG_PRINT("De-init: Driver Close Failed \n");
+ m_drv_fd = -1;
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR(" EVRC device already closed\n");
+ }
+ m_comp_deinit=1;
+ m_is_out_th_sleep = 1;
+ m_is_in_th_sleep = 1;
+ DEBUG_PRINT("************************************\n");
+ DEBUG_PRINT(" DEINIT COMPLETED");
+ DEBUG_PRINT("************************************\n");
+
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::UseEGLImage
+
+DESCRIPTION
+ OMX Use EGL Image method implementation <TBD>.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Not Implemented error.
+
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::use_EGL_image
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN void* eglImage)
+{
+ DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n");
+
+ if((hComp == NULL) || (appData == NULL) || (eglImage == NULL))
+ {
+ bufferHdr = NULL;
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::ComponentRoleEnum
+
+DESCRIPTION
+ OMX Component Role Enum method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_evrc_aenc::component_role_enum(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_U8* role,
+ OMX_IN OMX_U32 index)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ const char *cmp_role = "audio_encoder.evrc";
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (index == 0 && role)
+ {
+ memcpy(role, cmp_role, sizeof(cmp_role));
+ *(((char *) role) + sizeof(cmp_role)) = '\0';
+ } else
+ {
+ eRet = OMX_ErrorNoMore;
+ }
+ return eRet;
+}
+
+
+
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::AllocateDone
+
+DESCRIPTION
+ Checks if entire buffer pool is allocated by IL Client or not.
+ Need this to move to IDLE state.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false.
+
+========================================================================== */
+bool omx_evrc_aenc::allocate_done(void)
+{
+ OMX_BOOL bRet = OMX_FALSE;
+ if (pcm_input==1)
+ {
+ if ((m_inp_act_buf_count == m_inp_current_buf_count)
+ &&(m_out_act_buf_count == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled )
+ {
+ m_inp_bPopulated = OMX_TRUE;
+ }
+
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+ } else if (pcm_input==0)
+ {
+ if (m_out_act_buf_count == m_out_current_buf_count)
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+
+ }
+ return bRet;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_evrc_aenc::ReleaseDone
+
+DESCRIPTION
+ Checks if IL client has released all the buffers.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+bool omx_evrc_aenc::release_done(OMX_U32 param1)
+{
+ DEBUG_PRINT("Inside omx_evrc_aenc::release_done");
+ OMX_BOOL bRet = OMX_FALSE;
+
+ if (param1 == OMX_ALL)
+ {
+ if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_INPUT_PORT_INDEX )
+ {
+ if ((0 == m_inp_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ if ((0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ }
+ return bRet;
+}
diff --git a/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c b/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c
new file mode 100644
index 0000000..e01759e
--- /dev/null
+++ b/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c
@@ -0,0 +1,1094 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include<unistd.h>
+#include<string.h>
+#include <pthread.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+
+
+#include <linux/ioctl.h>
+
+typedef unsigned char uint8;
+typedef unsigned char byte;
+typedef unsigned int uint32;
+typedef unsigned int uint16;
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+/* maximum ADTS frame header length */
+void Release_Encoder();
+
+#ifdef AUDIOV2
+unsigned short session_id;
+int device_id;
+int control = 0;
+const char *device="handset_tx";
+#define DIR_TX 2
+#endif
+
+uint32_t samplerate = 8000;
+uint32_t channels = 1;
+uint32_t min_bitrate = 0;
+uint32_t max_bitrate = 0;
+uint32_t cdmarate = 0;
+uint32_t rectime = -1;
+uint32_t recpath = -1;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t format = 1;
+#define DEBUG_PRINT printf
+unsigned to_idle_transition = 0;
+unsigned long total_pcm_bytes;
+
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define QCP_HEADER_SIZE sizeof(struct qcp_header)
+#define MIN_BITRATE 4 /* Bit rate 1 - 13.6 , 2 - 6.2 , 3 - 2.7 , 4 - 1.0 kbps*/
+#define MAX_BITRATE 4
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+pthread_mutex_t lock;
+pthread_cond_t cond;
+pthread_mutex_t elock;
+pthread_cond_t econd;
+pthread_cond_t fcond;
+pthread_mutex_t etb_lock;
+pthread_mutex_t etb_lock1;
+pthread_cond_t etb_cond;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+OMX_AUDIO_PARAM_EVRCTYPE evrcparam;
+OMX_AUDIO_PARAM_PCMMODETYPE pcmparam;
+OMX_PORT_PARAM_TYPE portParam;
+OMX_PORT_PARAM_TYPE portFmt;
+OMX_ERRORTYPE error;
+
+
+
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+struct enc_meta_out{
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+} __attribute__ ((packed));
+
+struct qcp_header {
+ /* RIFF Section */
+ char riff[4];
+ unsigned int s_riff;
+ char qlcm[4];
+
+ /* Format chunk */
+ char fmt[4];
+ unsigned int s_fmt;
+ char mjr;
+ char mnr;
+ unsigned int data1; /* UNIQUE ID of the codec */
+ unsigned short data2;
+ unsigned short data3;
+ char data4[8];
+ unsigned short ver; /* Codec Info */
+ char name[80];
+ unsigned short abps; /* average bits per sec of the codec */
+ unsigned short bytes_per_pkt;
+ unsigned short samp_per_block;
+ unsigned short samp_per_sec;
+ unsigned short bits_per_samp;
+ unsigned char vr_num_of_rates; /* Rate Header fmt info */
+ unsigned char rvd1[3];
+ unsigned short vr_bytes_per_pkt[8];
+ unsigned int rvd2[5];
+
+ /* Vrat chunk */
+ unsigned char vrat[4];
+ unsigned int s_vrat;
+ unsigned int v_rate;
+ unsigned int size_in_pkts;
+
+ /* Data chunk */
+ unsigned char data[4];
+ unsigned int s_data;
+} __attribute__ ((packed));
+
+ /* Common part */
+ static struct qcp_header append_header = {
+ {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'},
+ {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0},
+ {'v','r','a','t'},0, 0, 0,{'d','a','t','a'},0
+ };
+
+static unsigned totaldatalen = 0;
+static unsigned framecnt = 0;
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+volatile int etb_event_is_done = 0;
+int ebd_cnt;
+int bInputEosReached = 0;
+int bOutputEosReached = 0;
+int bInputEosReached_tunnel = 0;
+static int etb_done = 0;
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+const char *out_filename;
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* evrc_enc_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Encoder(char*);
+int Play_Encoder();
+OMX_STRING aud_comp;
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *evrc_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE parse_pcm_header();
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock1);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock1);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock1);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+static void create_qcp_header(int Datasize, int Frames)
+{
+ append_header.s_riff = Datasize + QCP_HEADER_SIZE - 8;
+ /* exclude riff id and size field */
+ append_header.data1 = 0xe689d48d;
+ append_header.data2 = 0x9076;
+ append_header.data3 = 0x46b5;
+ append_header.data4[0] = 0x91;
+ append_header.data4[1] = 0xef;
+ append_header.data4[2] = 0x73;
+ append_header.data4[3] = 0x6a;
+ append_header.data4[4] = 0x51;
+ append_header.data4[5] = 0x00;
+ append_header.data4[6] = 0xce;
+ append_header.data4[7] = 0xb4;
+ append_header.ver = 0x0001;
+ memcpy(append_header.name, "TIA IS-127 Enhanced Variable Rate Codec, Speech Service Option 3", 64);
+ append_header.abps = 9600;
+ append_header.bytes_per_pkt = 23;
+ append_header.vr_num_of_rates = 4;
+ append_header.vr_bytes_per_pkt[0] = 0x0416;
+ append_header.vr_bytes_per_pkt[1] = 0x030a;
+ append_header.vr_bytes_per_pkt[2] = 0x0200;
+ append_header.vr_bytes_per_pkt[3] = 0x0102;
+ append_header.s_vrat = 0x00000008;
+ append_header.v_rate = 0x00000001;
+ append_header.size_in_pkts = Frames;
+ append_header.s_data = Datasize;
+ return;
+}
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+ switch(eEvent) {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent,
+ nData1,nData2);
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("\n OMX_EventError \n");
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("\n OMX_EventBufferFlag \n");
+ bOutputEosReached = true;
+ event_complete();
+ break;
+ case OMX_EventPortSettingsChanged:
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ size_t bytes_writen = 0;
+ int total_bytes_writen = 0;
+ unsigned int len = 0;
+ struct enc_meta_out *meta = NULL;
+ OMX_U8 *src = pBuffer->pBuffer;
+ unsigned int num_of_frames = 1;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) {
+ DEBUG_PRINT("FBD::EOS on output port\n ");
+ bOutputEosReached = true;
+ return OMX_ErrorNone;
+ }
+ if(bInputEosReached_tunnel || bOutputEosReached)
+ {
+ DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n");
+ return OMX_ErrorNone;
+ }
+ if(num_of_frames != src[0]){
+
+ printf("Data corrupt\n");
+ return OMX_ErrorNone;
+ }
+ /* Skip the first bytes */
+
+
+
+ src += sizeof(unsigned char);
+ meta = (struct enc_meta_out *)src;
+ while (num_of_frames > 0) {
+ meta = (struct enc_meta_out *)src;
+ /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n",
+ meta->offset_to_frame,
+ meta->frame_size,
+ meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/
+ len = meta->frame_size;
+
+ bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile);
+ if(bytes_writen < len)
+ {
+ DEBUG_PRINT("error: invalid EVRC encoded data \n");
+ return OMX_ErrorNone;
+ }
+ src += sizeof(struct enc_meta_out);
+ num_of_frames--;
+ total_bytes_writen += len;
+ }
+ DEBUG_PRINT(" FillBufferDone size writen to file %d count %d\n",total_bytes_writen, framecnt);
+ totaldatalen += total_bytes_writen ;
+ framecnt++;
+
+ DEBUG_PRINT(" FBD calling FTB\n");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock);
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock);
+ }
+
+
+ if(bInputEosReached)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }else if (bFlushing == true) {
+ DEBUG_PRINT("omx_evrc13_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (used_ip_buf_cnt == 0) {
+ bFlushing = false;
+ } else {
+ DEBUG_PRINT("omx_evrc13_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ return OMX_ErrorNone;
+ }
+ }
+
+ if((readBytes = Read_Buffer(pBuffer)) > 0) {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else{
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ bInputEosReached = true;
+ pBuffer->nFilledLen = 0;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id) {
+
+ /* Flush */
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ } else if (sig_id == SIGUSR2) {
+ if (bPause == true) {
+ DEBUG_PRINT("%s resume record\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ } else {
+ DEBUG_PRINT("%s pause record\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+ (void) signal(SIGINT, Release_Encoder);
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+
+ if (argc >= 9) {
+ in_filename = argv[1];
+ out_filename = argv[2];
+ tunnel = atoi(argv[3]);
+ min_bitrate = atoi(argv[4]);
+ max_bitrate = atoi(argv[5]);
+ cdmarate = atoi(argv[6]);
+ recpath = atoi(argv[7]); // No configuration support yet..
+ rectime = atoi(argv[8]);
+
+ } else {
+ DEBUG_PRINT(" invalid format: \n");
+ DEBUG_PRINT("ex: ./mm-aenc-omxevrc-test INPUTFILE OUTPUTFILE Tunnel MINRATE MAXRATE CDMARATE RECORDPATH RECORDTIME\n");
+ DEBUG_PRINT("MINRATE MAXRATE and CDMARATE 1 to 4\n");
+ DEBUG_PRINT("RECORDPATH 0(TX),1(RX),2(BOTH),3(MIC)\n");
+ DEBUG_PRINT("RECORDTIME in seconds for AST Automation\n");
+ return 0;
+ }
+ if(recpath != 3) {
+ DEBUG_PRINT("For RECORDPATH Only MIC supported\n");
+ return 0;
+ }
+ if(tunnel == 0)
+ aud_comp = "OMX.qcom.audio.encoder.evrc";
+ else
+ aud_comp = "OMX.qcom.audio.encoder.tunneled.evrc";
+ if(Init_Encoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+
+ if(Play_Encoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+ if(rectime && tunnel)
+ {
+ sleep(rectime);
+ rectime = 0;
+ bInputEosReached_tunnel = 1;
+ DEBUG_PRINT("\EOS ON INPUT PORT\n");
+ }
+ else
+ {
+ wait_for_event();
+ }
+
+ if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel))
+ {
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+
+ DEBUG_PRINT("\nMoving the encoder to loaded state \n");
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+ sleep(1);
+ if (!tunnel)
+ {
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(evrc_enc_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ }
+
+ DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(evrc_enc_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+ wait_for_event();
+ create_qcp_header(totaldatalen, framecnt);
+ fseek(outputBufferFile, 0,SEEK_SET);
+ fwrite(&append_header,1,QCP_HEADER_SIZE,outputBufferFile);
+
+
+ result = OMX_FreeHandle(evrc_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+ if(tunnel)
+ {
+ #ifdef AUDIOV2
+ if (msm_route_stream(DIR_TX,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ #endif
+ }
+ OMX_Deinit();
+ ebd_cnt=0;
+ bOutputEosReached = false;
+ bInputEosReached_tunnel = false;
+ bInputEosReached = 0;
+ evrc_enc_handle = NULL;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ fclose(outputBufferFile);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...EVRC ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+ return 0;
+}
+
+void Release_Encoder()
+{
+ static int cnt=0;
+ OMX_ERRORTYPE result;
+
+ DEBUG_PRINT("END OF EVRC ENCODING: EXITING PLEASE WAIT\n");
+ bInputEosReached_tunnel = 1;
+ event_complete();
+ cnt++;
+ if(cnt > 1)
+ {
+ /* FORCE RESET */
+ evrc_enc_handle = NULL;
+ ebd_cnt=0;
+ bInputEosReached_tunnel = false;
+
+ result = OMX_FreeHandle(evrc_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+
+ OMX_Deinit();
+
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...EVRC ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ exit(0);
+ }
+}
+
+int Init_Encoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ typedef OMX_U8* OMX_U8_PTR;
+ char *role ="audio_encoder";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Evrc_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total);
+
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&evrc_enc_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component);
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(evrc_enc_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+
+ if(OMX_ErrorNone != omxresult)
+ {
+ DEBUG_PRINT("Set parameter failed");
+ }
+
+ return 0;
+}
+
+int Play_Encoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file()) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+
+ /* Query the encoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(evrc_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Input Port\n");
+ return -1;
+ }
+
+ pcmparam.nPortIndex = 0;
+ pcmparam.nChannels = channels;
+ pcmparam.nSamplingRate = samplerate;
+ OMX_SetParameter(evrc_enc_handle,OMX_IndexParamAudioPcm,&pcmparam);
+
+
+ /* Query the encoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(evrc_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Output Port\n");
+ return -1;
+ }
+
+
+ CONFIG_VERSION_SIZE(evrcparam);
+
+ evrcparam.nPortIndex = 1;
+ evrcparam.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/
+ evrcparam.nMinBitRate = min_bitrate;
+ evrcparam.nMaxBitRate = max_bitrate;
+ OMX_SetParameter(evrc_enc_handle,OMX_IndexParamAudioEvrc,&evrcparam);
+ OMX_GetExtensionIndex(evrc_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(evrc_enc_handle,index,&streaminfoparam);
+ if(tunnel) {
+ #ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+ if (msm_route_stream(DIR_TX,session_id,device_id, 1))
+ {
+ perror("could not set stream routing\n");
+ return -1;
+ }
+ #endif
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n");
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+ if (tunnel == 0)
+ {
+ input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(evrc_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pInputBufHdrs == NULL) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+ }
+ output_buf_cnt = outputportFmt.nBufferCountMin ;
+
+ /* Allocate buffer on encoder's O/Pp port */
+ error = Allocate_Buffer(evrc_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pOutputBufHdrs == NULL) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+
+ if (tunnel == 1)
+ {
+ DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n");
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandPortDisable,0,0); // disable input port
+ wait_for_event();
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n");
+ OMX_SendCommand(evrc_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(evrc_enc_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+if(tunnel == 0)
+{
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++) {
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ bInputEosReached = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ ret = OMX_EmptyThisBuffer(evrc_enc_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock);
+ if(etb_done)
+{
+ DEBUG_PRINT("Component is waiting for EBD to be released.\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock);
+}
+
+ return 0;
+}
+
+
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_enc_handle;
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(evrc_enc_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+
+
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+
+ int bytes_read=0;
+
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile);
+
+ pBufHdr->nFilledLen = bytes_read;
+ // Time stamp logic
+ ((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp = \
+
+ (unsigned long) ((total_pcm_bytes * 1000)/(samplerate * channels *2));
+
+ DEBUG_PRINT ("\n--time stamp -- %ld\n", (unsigned long)((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp);
+ if(bytes_read == 0)
+ {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+
+ total_pcm_bytes += bytes_read;
+ }
+
+ return bytes_read;;
+}
+
+
+
+//In Encoder this Should Open a PCM or WAV file for input.
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+
+ if (!tunnel)
+ {
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ }
+ if(parse_pcm_header() != 0x00)
+ {
+ DEBUG_PRINT("PCM parser failed \n");
+ return -1;
+ }
+ }
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename);
+ outputBufferFile = fopen (out_filename, "wb");
+ if (outputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ out_filename);
+ error_code = -1;
+ return error_code;
+ }
+ fseek(outputBufferFile, QCP_HEADER_SIZE, SEEK_SET);
+ return error_code;
+}
+
+static OMX_ERRORTYPE parse_pcm_header()
+{
+ struct wav_header hdr;
+
+ DEBUG_PRINT("\n***************************************************************\n");
+ if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr))
+ {
+ DEBUG_PRINT("Wav file cannot read header\n");
+ return -1;
+ }
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE)||
+ (hdr.fmt_id != ID_FMT))
+ {
+ DEBUG_PRINT("Wav file is not a riff/wave file\n");
+ return -1;
+ }
+
+ if (hdr.audio_format != FORMAT_PCM)
+ {
+ DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n",
+ hdr.audio_format, hdr.fmt_sz);
+ return -1;
+ }
+
+ DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate);
+ DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels);
+ DEBUG_PRINT("\n***************************************************************\n");
+
+ samplerate = hdr.sample_rate;
+ channels = hdr.num_channels;
+ total_pcm_bytes = 0;
+
+ return OMX_ErrorNone;
+}
diff --git a/mm-audio/aenc-qcelp13/Android.mk b/mm-audio/aenc-qcelp13/Android.mk
new file mode 100644
index 0000000..8f6985c
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/Android.mk
@@ -0,0 +1,26 @@
+ifeq ($(TARGET_ARCH),arm)
+
+
+AENC_QCELP13_PATH:= $(call my-dir)
+
+ifeq ($(call is-board-platform,msm8660),true)
+include $(AENC_QCELP13_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8960),true)
+include $(AENC_QCELP13_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8974),true)
+include $(AENC_QCELP13_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8226),true)
+include $(AENC_QCELP13_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,msm8610),true)
+include $(AENC_QCELP13_PATH)/qdsp6/Android.mk
+endif
+ifeq ($(call is-board-platform,apq8084),true)
+include $(AENC_QCELP13_PATH)/qdsp6/Android.mk
+endif
+
+
+endif
diff --git a/mm-audio/aenc-qcelp13/Makefile b/mm-audio/aenc-qcelp13/Makefile
new file mode 100644
index 0000000..83d822b
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/Makefile
@@ -0,0 +1,6 @@
+all:
+ @echo "invoking omxaudio make"
+ $(MAKE) -C qdsp6
+
+install:
+ $(MAKE) -C qdsp6 install
diff --git a/mm-audio/aenc-qcelp13/qdsp6/Android.mk b/mm-audio/aenc-qcelp13/qdsp6/Android.mk
new file mode 100644
index 0000000..5aaa3bf
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/Android.mk
@@ -0,0 +1,78 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# ---------------------------------------------------------------------------------
+# Common definitons
+# ---------------------------------------------------------------------------------
+
+libOmxQcelp13Enc-def := -g -O3
+libOmxQcelp13Enc-def += -DQC_MODIFIED
+libOmxQcelp13Enc-def += -D_ANDROID_
+libOmxQcelp13Enc-def += -D_ENABLE_QC_MSG_LOG_
+libOmxQcelp13Enc-def += -DVERBOSE
+libOmxQcelp13Enc-def += -D_DEBUG
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+libOmxQcelp13Enc-def += -DAUDIOV2
+endif
+
+# ---------------------------------------------------------------------------------
+# Make the Shared library (libOmxQcelp13Enc)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+libOmxQcelp13Enc-inc := $(LOCAL_PATH)/inc
+libOmxQcelp13Enc-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+
+LOCAL_MODULE := libOmxQcelp13Enc
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxQcelp13Enc-def)
+LOCAL_C_INCLUDES := $(libOmxQcelp13Enc-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libutils liblog
+
+LOCAL_SRC_FILES := src/aenc_svr.c
+LOCAL_SRC_FILES += src/omx_qcelp13_aenc.cpp
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+# ---------------------------------------------------------------------------------
+# Make the apps-test (mm-aenc-omxqcelp13-test)
+# ---------------------------------------------------------------------------------
+
+include $(CLEAR_VARS)
+
+mm-qcelp13-enc-test-inc := $(LOCAL_PATH)/inc
+mm-qcelp13-enc-test-inc += $(LOCAL_PATH)/test
+
+mm-qcelp13-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-core/omxcore
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+mm-qcelp13-enc-test-inc += $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+endif
+LOCAL_MODULE := mm-aenc-omxqcelp13-test
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(libOmxQcelp13Enc-def)
+LOCAL_C_INCLUDES := $(mm-qcelp13-enc-test-inc)
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := libmm-omxcore
+LOCAL_SHARED_LIBRARIES += libOmxQcelp13Enc
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
+LOCAL_SHARED_LIBRARIES += libaudioalsa
+endif
+LOCAL_SRC_FILES := test/omx_qcelp13_enc_test.c
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
+
diff --git a/mm-audio/aenc-qcelp13/qdsp6/Makefile b/mm-audio/aenc-qcelp13/qdsp6/Makefile
new file mode 100644
index 0000000..b14655b
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/Makefile
@@ -0,0 +1,81 @@
+# ---------------------------------------------------------------------------------
+# MM-AUDIO-OSS-8K-AENC-QCELP13
+# ---------------------------------------------------------------------------------
+
+# cross-compiler flags
+CFLAGS += -Wall
+CFLAGS += -Wundef
+CFLAGS += -Wstrict-prototypes
+CFLAGS += -Wno-trigraphs
+
+# cross-compile flags specific to shared objects
+CFLAGS_SO += -fpic
+
+# required pre-processor flags
+CPPFLAGS := -D__packed__=
+CPPFLAGS += -DIMAGE_APPS_PROC
+CPPFLAGS += -DFEATURE_Q_SINGLE_LINK
+CPPFLAGS += -DFEATURE_Q_NO_SELF_QPTR
+CPPFLAGS += -DFEATURE_LINUX
+CPPFLAGS += -DFEATURE_NATIVELINUX
+CPPFLAGS += -DFEATURE_DSM_DUP_ITEMS
+
+CPPFLAGS += -g
+CPPFALGS += -D_DEBUG
+CPPFLAGS += -Iinc
+
+# linker flags
+LDFLAGS += -L$(SYSROOT)/usr/lib
+
+# linker flags for shared objects
+LDFLAGS_SO := -shared
+
+# defintions
+LIBMAJOR := $(basename $(basename $(LIBVER)))
+LIBINSTALLDIR := $(DESTDIR)usr/lib
+INCINSTALLDIR := $(DESTDIR)usr/include
+BININSTALLDIR := $(DESTDIR)usr/bin
+
+# ---------------------------------------------------------------------------------
+# BUILD
+# ---------------------------------------------------------------------------------
+all: libOmxQcelp13Enc.so.$(LIBVER) mm-aenc-omxqcelp13-test
+
+install:
+ echo "intalling aenc-qcelp13 in $(DESTDIR)"
+ if [ ! -d $(LIBINSTALLDIR) ]; then mkdir -p $(LIBINSTALLDIR); fi
+ if [ ! -d $(INCINSTALLDIR) ]; then mkdir -p $(INCINSTALLDIR); fi
+ if [ ! -d $(BININSTALLDIR) ]; then mkdir -p $(BININSTALLDIR); fi
+ install -m 555 libOmxQcelp13Enc.so.$(LIBVER) $(LIBINSTALLDIR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxQcelp13Enc.so.$(LIBVER) libOmxQcelp13Enc.so.$(LIBMAJOR)
+ cd $(LIBINSTALLDIR) && ln -s libOmxQcelp13Enc.so.$(LIBMAJOR) libOmxQcelp13Enc.so
+ install -m 555 mm-aenc-omxqcelp13-test $(BININSTALLDIR)
+
+# ---------------------------------------------------------------------------------
+# COMPILE LIBRARY
+# ---------------------------------------------------------------------------------
+LDLIBS := -lpthread
+LDLIBS += -lstdc++
+LDLIBS += -lOmxCore
+
+SRCS := src/omx_qcelp13_aenc.cpp
+SRCS += src/aenc_svr.c
+
+libOmxQcelp13Enc.so.$(LIBVER): $(SRCS)
+ $(CC) $(CPPFLAGS) $(CFLAGS_SO) $(LDFLAGS_SO) -Wl,-soname,libOmxQcelp13Enc.so.$(LIBMAJOR) -o $@ $^ $(LDFLAGS) $(LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# COMPILE TEST APP
+# ---------------------------------------------------------------------------------
+TEST_LDLIBS := -lpthread
+TEST_LDLIBS += -ldl
+TEST_LDLIBS += -lOmxCore
+
+TEST_SRCS := test/omx_qcelp13_enc_test.c
+
+mm-aenc-omxqcelp13-test: libOmxQcelp13Enc.so.$(LIBVER) $(TEST_SRCS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(TEST_LDLIBS)
+
+# ---------------------------------------------------------------------------------
+# END
+# ---------------------------------------------------------------------------------
diff --git a/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h b/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h
new file mode 100644
index 0000000..aac96fd
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h
@@ -0,0 +1,244 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdio.h>
+using namespace std;
+
+template <typename T,typename T2>
+class Map
+{
+ struct node
+ {
+ T data;
+ T2 data2;
+ node* prev;
+ node* next;
+ node(T t, T2 t2,node* p, node* n) :
+ data(t), data2(t2), prev(p), next(n) {}
+ };
+ node* head;
+ node* tail;
+ node* tmp;
+ unsigned size_of_list;
+ static Map<T,T2> *m_self;
+public:
+ Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {}
+ bool empty() const { return ( !head || !tail ); }
+ operator bool() const { return !empty(); }
+ void insert(T,T2);
+ void show();
+ int size();
+ T2 find(T); // Return VALUE
+ T find_ele(T);// Check if the KEY is present or not
+ T2 begin(); //give the first ele
+ bool erase(T);
+ bool eraseall();
+ bool isempty();
+ ~Map()
+ {
+ while(head)
+ {
+ node* temp(head);
+ head=head->next;
+ size_of_list--;
+ delete temp;
+ }
+ }
+};
+
+template <typename T,typename T2>
+T2 Map<T,T2>::find(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data2;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T Map<T,T2>::find_ele(T d1)
+{
+ tmp = head;
+ while(tmp)
+ {
+ if(tmp->data == d1)
+ {
+ return tmp->data;
+ }
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+T2 Map<T,T2>::begin()
+{
+ tmp = head;
+ if(tmp)
+ {
+ return (tmp->data2);
+ }
+ return 0;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::show()
+{
+ tmp = head;
+ while(tmp)
+ {
+ printf("%d-->%d\n",tmp->data,tmp->data2);
+ tmp = tmp->next;
+ }
+}
+
+template <typename T,typename T2>
+int Map<T,T2>::size()
+{
+ int count =0;
+ tmp = head;
+ while(tmp)
+ {
+ tmp = tmp->next;
+ count++;
+ }
+ return count;
+}
+
+template <typename T,typename T2>
+void Map<T,T2>::insert(T data, T2 data2)
+{
+ tail = new node(data, data2,tail, NULL);
+ if( tail->prev )
+ tail->prev->next = tail;
+
+ if( empty() )
+ {
+ head = tail;
+ tmp=head;
+ }
+ tmp = head;
+ size_of_list++;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::erase(T d)
+{
+ bool found = false;
+ tmp = head;
+ node* prevnode = tmp;
+ node *tempnode;
+
+ while(tmp)
+ {
+ if((head == tail) && (head->data == d))
+ {
+ found = true;
+ tempnode = head;
+ head = tail = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp ==head) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ tmp = tmp->next;
+ tmp->prev = NULL;
+ head = tmp;
+ tempnode->next = NULL;
+ delete tempnode;
+ break;
+ }
+ if((tmp == tail) && (tmp->data ==d))
+ {
+ found = true;
+ tempnode = tmp;
+ prevnode->next = NULL;
+ tmp->prev = NULL;
+ tail = prevnode;
+ delete tempnode;
+ break;
+ }
+ if(tmp->data == d)
+ {
+ found = true;
+ prevnode->next = tmp->next;
+ tmp->next->prev = prevnode->next;
+ tempnode = tmp;
+ //tmp = tmp->next;
+ delete tempnode;
+ break;
+ }
+ prevnode = tmp;
+ tmp = tmp->next;
+ }
+ if(found)size_of_list--;
+ return found;
+}
+
+template <typename T,typename T2>
+bool Map<T,T2>::eraseall()
+{
+ // Be careful while using this method
+ // it not only removes the node but FREES(not delete) the allocated
+ // memory.
+ node *tempnode;
+ tmp = head;
+ while(head)
+ {
+ tempnode = head;
+ head = head->next;
+ tempnode->next = NULL;
+ if(tempnode->data)
+ free(tempnode->data);
+ if(tempnode->data2)
+ free(tempnode->data2);
+ delete tempnode;
+ }
+ tail = head = NULL;
+ return true;
+}
+
+
+template <typename T,typename T2>
+bool Map<T,T2>::isempty()
+{
+ if(!size_of_list) return true;
+ else return false;
+}
+
+#endif // _MAP_H_
diff --git a/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h b/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h
new file mode 100644
index 0000000..940d863
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h
@@ -0,0 +1,120 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef AENC_SVR_H
+#define AENC_SVR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <pthread.h>
+#include <sched.h>
+#include <utils/Log.h>
+
+#ifdef _ANDROID_
+#define LOG_TAG "QC_QCELP13ENC"
+#endif
+
+#ifndef LOGE
+#define LOGE ALOGE
+#endif
+
+#ifndef LOGW
+#define LOGW ALOGW
+#endif
+
+#ifndef LOGD
+#define LOGD ALOGD
+#endif
+
+#ifndef LOGV
+#define LOGV ALOGV
+#endif
+
+#ifndef LOGI
+#define LOGI ALOGI
+#endif
+
+#define DEBUG_PRINT_ERROR LOGE
+#define DEBUG_PRINT LOGI
+#define DEBUG_DETAIL LOGV
+
+typedef void (*message_func)(void* client_data, unsigned char id);
+
+/**
+ @brief audio encoder ipc info structure
+
+ */
+struct qcelp13_ipc_info
+{
+ pthread_t thr;
+ int pipe_in;
+ int pipe_out;
+ int dead;
+ message_func process_msg_cb;
+ void *client_data;
+ char thread_name[128];
+};
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to command server
+ */
+struct qcelp13_ipc_info *omx_qcelp13_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+
+struct qcelp13_ipc_info *omx_qcelp13_event_thread_create(message_func cb,
+ void* client_data,
+ char *th_name);
+/**
+ @brief This function stop command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_qcelp13_thread_stop(struct qcelp13_ipc_info *qcelp13_ipc);
+
+
+/**
+ @brief This function post message in the command server
+
+ @param svr handle to command server
+ @return none
+ */
+void omx_qcelp13_post_msg(struct qcelp13_ipc_info *qcelp13_ipc,
+ unsigned char id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AENC_SVR */
diff --git a/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h b/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h
new file mode 100644
index 0000000..c547809
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h
@@ -0,0 +1,539 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#ifndef _QCELP13_ENC_H_
+#define _QCELP13_ENC_H_
+/*============================================================================
+ Audio Encoder
+
+@file omx_qcelp13_aenc.h
+This module contains the class definition for openMAX encoder component.
+
+
+
+============================================================================*/
+
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+/* Uncomment out below line #define LOG_NDEBUG 0 if we want to see
+ * all DEBUG_PRINT or LOGV messaging */
+#include<stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#include "OMX_Core.h"
+#include "OMX_Audio.h"
+#include "aenc_svr.h"
+#include "qc_omx_component.h"
+#include "Map.h"
+#include <semaphore.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_qcp.h>
+extern "C" {
+ void * get_omx_component_factory_fn(void);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Module specific globals
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+#define OMX_SPEC_VERSION 0x00000101
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (x >= y?x:y)
+
+//////////////////////////////////////////////////////////////////////////////
+// Macros
+//////////////////////////////////////////////////////////////////////////////
+//
+
+
+#define PrintFrameHdr(i,bufHdr) \
+ DEBUG_PRINT("i=%d OMX bufHdr[%x]buf[%x]size[%d]TS[%lld]nFlags[0x%x]\n",\
+ i,\
+ (unsigned) bufHdr, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\
+ ((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp, \
+ (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFlags)
+
+
+// BitMask Management logic
+#define BITS_PER_BYTE 8
+#define BITMASK_SIZE(mIndex) \
+ (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE)
+#define BITMASK_OFFSET(mIndex)\
+ ((mIndex)/BITS_PER_BYTE)
+#define BITMASK_FLAG(mIndex) \
+ (1 << ((mIndex) % BITS_PER_BYTE))
+#define BITMASK_CLEAR(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] &= ~(BITMASK_FLAG(mIndex))
+#define BITMASK_SET(mArray,mIndex)\
+ (mArray)[BITMASK_OFFSET(mIndex)] |= BITMASK_FLAG(mIndex)
+#define BITMASK_PRESENT(mArray,mIndex)\
+ ((mArray)[BITMASK_OFFSET(mIndex)] & BITMASK_FLAG(mIndex))
+#define BITMASK_ABSENT(mArray,mIndex)\
+ (((mArray)[BITMASK_OFFSET(mIndex)] & \
+ BITMASK_FLAG(mIndex)) == 0x0)
+
+#define OMX_CORE_NUM_INPUT_BUFFERS 2
+#define OMX_CORE_NUM_OUTPUT_BUFFERS 16
+
+#define OMX_CORE_INPUT_BUFFER_SIZE 8160 // Multiple of 160
+#define OMX_CORE_CONTROL_CMDQ_SIZE 100
+#define OMX_AENC_VOLUME_STEP 0x147
+#define OMX_AENC_MIN 0
+#define OMX_AENC_MAX 100
+#define NON_TUNNEL 1
+#define TUNNEL 0
+#define IP_PORT_BITMASK 0x02
+#define OP_PORT_BITMASK 0x01
+#define IP_OP_PORT_BITMASK 0x03
+
+#define OMX_QCELP13_DEFAULT_SF 8000
+#define OMX_QCELP13_DEFAULT_CH_CFG 1
+#define OMX_QCELP13_DEFAULT_VOL 25
+// 14 bytes for input meta data
+#define OMX_AENC_SIZEOF_META_BUF (OMX_CORE_INPUT_BUFFER_SIZE+14)
+
+#define TRUE 1
+#define FALSE 0
+
+#define NUMOFFRAMES 1
+#define MAXFRAMELENGTH 35
+#define OMX_QCELP13_OUTPUT_BUFFER_SIZE ((NUMOFFRAMES * (sizeof(ENC_META_OUT) + MAXFRAMELENGTH) \
+ + 1))
+
+#define OMX_QCELP13_DEFAULT_MINRATE 4
+#define OMX_QCELP13_DEFAULT_MAXRATE 4
+
+class omx_qcelp13_aenc;
+
+// OMX mo3 audio encoder class
+class omx_qcelp13_aenc: public qc_omx_component
+{
+public:
+ omx_qcelp13_aenc(); // constructor
+ virtual ~omx_qcelp13_aenc(); // destructor
+
+ OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+
+ OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp);
+
+ OMX_ERRORTYPE component_init(OMX_STRING role);
+
+ OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE hComp,
+ OMX_U8 *role,
+ OMX_U32 index);
+
+ OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_HANDLETYPE peerComponent,
+ OMX_U32 peerPort,
+ OMX_TUNNELSETUPTYPE *tunnelSetup);
+
+ OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+
+ OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE hComp,
+ OMX_U32 port,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE hComp,
+ OMX_STRING componentName,
+ OMX_VERSIONTYPE *componentVersion,
+ OMX_VERSIONTYPE * specVersion,
+ OMX_UUIDTYPE *componentUUID);
+
+ OMX_ERRORTYPE get_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE hComp,
+ OMX_STRING paramName,
+ OMX_INDEXTYPE *indexType);
+
+ OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp,
+ OMX_STATETYPE *state);
+
+ static void process_in_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_out_port_msg(void *client_data,
+ unsigned char id);
+
+ static void process_command_msg(void *client_data,
+ unsigned char id);
+
+ static void process_event_cb(void *client_data,
+ unsigned char id);
+
+
+ OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp,
+ OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData);
+
+ OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE configIndex,
+ OMX_PTR configData);
+
+ OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp,
+ OMX_INDEXTYPE paramIndex,
+ OMX_PTR paramData);
+
+ OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes,
+ OMX_U8 *buffer);
+
+ OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ void * eglImage);
+
+ bool post_command(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ // Deferred callback identifiers
+ enum
+ {
+ //Event Callbacks from the component thread context
+ OMX_COMPONENT_GENERATE_EVENT = 0x1,
+ //Buffer Done callbacks from component thread context
+ OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2,
+ OMX_COMPONENT_GENERATE_ETB = 0x3,
+ //Command
+ OMX_COMPONENT_GENERATE_COMMAND = 0x4,
+ OMX_COMPONENT_GENERATE_FRAME_DONE = 0x05,
+ OMX_COMPONENT_GENERATE_FTB = 0x06,
+ OMX_COMPONENT_GENERATE_EOS = 0x07,
+ OMX_COMPONENT_PORTSETTINGS_CHANGED = 0x08,
+ OMX_COMPONENT_SUSPEND = 0x09,
+ OMX_COMPONENT_RESUME = 0x0a
+ };
+private:
+
+ ///////////////////////////////////////////////////////////
+ // Type definitions
+ ///////////////////////////////////////////////////////////
+ // Bit Positions
+ enum flags_bit_positions
+ {
+ // Defer transition to IDLE
+ OMX_COMPONENT_IDLE_PENDING =0x1,
+ // Defer transition to LOADING
+ OMX_COMPONENT_LOADING_PENDING =0x2,
+
+ OMX_COMPONENT_MUTED =0x3,
+
+ // Defer transition to Enable
+ OMX_COMPONENT_INPUT_ENABLE_PENDING =0x4,
+ // Defer transition to Enable
+ OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x5,
+ // Defer transition to Disable
+ OMX_COMPONENT_INPUT_DISABLE_PENDING =0x6,
+ // Defer transition to Disable
+ OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x7
+ };
+
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ input_buffer_map;
+
+ typedef Map<OMX_BUFFERHEADERTYPE*, OMX_BUFFERHEADERTYPE*>
+ output_buffer_map;
+
+ enum port_indexes
+ {
+ OMX_CORE_INPUT_PORT_INDEX =0,
+ OMX_CORE_OUTPUT_PORT_INDEX =1
+ };
+
+ struct omx_event
+ {
+ unsigned param1;
+ unsigned param2;
+ unsigned id;
+ };
+
+ struct omx_cmd_queue
+ {
+ omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE];
+ unsigned m_read;
+ unsigned m_write;
+ unsigned m_size;
+
+ omx_cmd_queue();
+ ~omx_cmd_queue();
+ bool insert_entry(unsigned p1, unsigned p2, unsigned id);
+ bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id);
+ bool get_msg_id(unsigned *id);
+ bool get_msg_with_id(unsigned *p1,unsigned *p2, unsigned id);
+ };
+
+ typedef struct TIMESTAMP
+ {
+ unsigned long LowPart;
+ unsigned long HighPart;
+ }__attribute__((packed)) TIMESTAMP;
+
+ typedef struct metadata_input
+ {
+ unsigned short offsetVal;
+ TIMESTAMP nTimeStamp;
+ unsigned int nFlags;
+ }__attribute__((packed)) META_IN;
+
+ typedef struct enc_meta_out
+ {
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+ } __attribute__ ((packed))ENC_META_OUT;
+
+ typedef struct
+ {
+ OMX_U32 tot_in_buf_len;
+ OMX_U32 tot_out_buf_len;
+ OMX_U32 tot_pb_time;
+ OMX_U32 fbd_cnt;
+ OMX_U32 ftb_cnt;
+ OMX_U32 etb_cnt;
+ OMX_U32 ebd_cnt;
+ }QCELP13_PB_STATS;
+
+ ///////////////////////////////////////////////////////////
+ // Member variables
+ ///////////////////////////////////////////////////////////
+ OMX_U8 *m_tmp_meta_buf;
+ OMX_U8 *m_tmp_out_meta_buf;
+ OMX_U8 m_flush_cnt ;
+ OMX_U8 m_comp_deinit;
+
+ // the below var doesnt hold good if combo of use and alloc bufs are used
+ OMX_S32 m_volume;//Unit to be determined
+ OMX_PTR m_app_data;// Application data
+ int nNumInputBuf;
+ int nNumOutputBuf;
+ int m_drv_fd; // Kernel device node file handle
+ bool bFlushinprogress;
+ bool is_in_th_sleep;
+ bool is_out_th_sleep;
+ unsigned int m_flags; //encapsulate the waiting states.
+ unsigned int nTimestamp;
+ unsigned int pcm_input; //tunnel or non-tunnel
+ unsigned int m_inp_act_buf_count; // Num of Input Buffers
+ unsigned int m_out_act_buf_count; // Numb of Output Buffers
+ unsigned int m_inp_current_buf_count; // Num of Input Buffers
+ unsigned int m_out_current_buf_count; // Numb of Output Buffers
+ unsigned int output_buffer_size;
+ unsigned int input_buffer_size;
+ unsigned short m_session_id;
+ // store I/P PORT state
+ OMX_BOOL m_inp_bEnabled;
+ // store O/P PORT state
+ OMX_BOOL m_out_bEnabled;
+ //Input port Populated
+ OMX_BOOL m_inp_bPopulated;
+ //Output port Populated
+ OMX_BOOL m_out_bPopulated;
+ sem_t sem_States;
+ sem_t sem_read_msg;
+ sem_t sem_write_msg;
+
+ volatile int m_is_event_done;
+ volatile int m_is_in_th_sleep;
+ volatile int m_is_out_th_sleep;
+ input_buffer_map m_input_buf_hdrs;
+ output_buffer_map m_output_buf_hdrs;
+ omx_cmd_queue m_input_q;
+ omx_cmd_queue m_input_ctrl_cmd_q;
+ omx_cmd_queue m_input_ctrl_ebd_q;
+ omx_cmd_queue m_command_q;
+ omx_cmd_queue m_output_q;
+ omx_cmd_queue m_output_ctrl_cmd_q;
+ omx_cmd_queue m_output_ctrl_fbd_q;
+ pthread_mutexattr_t m_outputlock_attr;
+ pthread_mutexattr_t m_commandlock_attr;
+ pthread_mutexattr_t m_lock_attr;
+ pthread_mutexattr_t m_state_attr;
+ pthread_mutexattr_t m_flush_attr;
+ pthread_mutexattr_t m_in_th_attr_1;
+ pthread_mutexattr_t m_out_th_attr_1;
+ pthread_mutexattr_t m_event_attr;
+ pthread_mutexattr_t m_in_th_attr;
+ pthread_mutexattr_t m_out_th_attr;
+ pthread_mutexattr_t out_buf_count_lock_attr;
+ pthread_mutexattr_t in_buf_count_lock_attr;
+ pthread_cond_t cond;
+ pthread_cond_t in_cond;
+ pthread_cond_t out_cond;
+ pthread_mutex_t m_lock;
+ pthread_mutex_t m_commandlock;
+ pthread_mutex_t m_outputlock;
+ // Mutexes for state change
+ pthread_mutex_t m_state_lock;
+ // Mutexes for flush acks from input and output threads
+ pthread_mutex_t m_flush_lock;
+ pthread_mutex_t m_event_lock;
+ pthread_mutex_t m_in_th_lock;
+ pthread_mutex_t m_out_th_lock;
+ pthread_mutex_t m_in_th_lock_1;
+ pthread_mutex_t m_out_th_lock_1;
+ pthread_mutex_t out_buf_count_lock;
+ pthread_mutex_t in_buf_count_lock;
+
+ OMX_STATETYPE m_state; // OMX State
+ OMX_STATETYPE nState;
+ OMX_CALLBACKTYPE m_cb; // Application callbacks
+ QCELP13_PB_STATS m_qcelp13_pb_stats;
+ struct qcelp13_ipc_info *m_ipc_to_in_th; // for input thread
+ struct qcelp13_ipc_info *m_ipc_to_out_th; // for output thread
+ struct qcelp13_ipc_info *m_ipc_to_cmd_th; // for command thread
+ struct qcelp13_ipc_info *m_ipc_to_event_th; //for txco event thread
+ OMX_PRIORITYMGMTTYPE m_priority_mgm ;
+ OMX_AUDIO_PARAM_QCELP13TYPE m_qcelp13_param; // Cache QCELP13 encoder parameter
+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_param; // Cache pcm parameter
+ OMX_PARAM_COMPONENTROLETYPE component_Role;
+ OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier;
+
+ ///////////////////////////////////////////////////////////
+ // Private methods
+ ///////////////////////////////////////////////////////////
+ OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE **bufferHdr,
+ OMX_U32 port,
+ OMX_PTR appData,
+ OMX_U32 bytes);
+
+ OMX_ERRORTYPE use_input_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE use_output_buffer(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **bufHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer);
+
+ OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param1,
+ OMX_PTR cmdData);
+
+ bool allocate_done(void);
+
+ bool release_done(OMX_U32 param1);
+
+ bool execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl=true);
+
+ bool execute_input_omx_flush(void);
+
+ bool execute_output_omx_flush(void);
+
+ bool search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer);
+
+ bool post_input(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ bool post_output(unsigned int p1, unsigned int p2,
+ unsigned int id);
+
+ void process_events(omx_qcelp13_aenc *client_data);
+
+ void buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr);
+
+ void wait_for_event();
+
+ void event_complete();
+
+ void in_th_goto_sleep();
+
+ void in_th_wakeup();
+
+ void out_th_goto_sleep();
+
+ void out_th_wakeup();
+
+ void flush_ack();
+ void deinit_encoder();
+
+};
+#endif
diff --git a/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c b/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c
new file mode 100644
index 0000000..b39f625
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c
@@ -0,0 +1,208 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <aenc_svr.h>
+
+/**
+ @brief This function processes posted messages
+
+ Once thread is being spawned, this function is run to
+ start processing commands posted by client
+
+ @param info pointer to context
+
+ */
+void *omx_qcelp13_msg(void *info)
+{
+ struct qcelp13_ipc_info *qcelp13_info = (struct qcelp13_ipc_info*)info;
+ unsigned char id;
+ int n;
+
+ DEBUG_DETAIL("\n%s: message thread start\n", __FUNCTION__);
+ while (!qcelp13_info->dead)
+ {
+ n = read(qcelp13_info->pipe_in, &id, 1);
+ if (0 == n) break;
+ if (1 == n)
+ {
+ DEBUG_DETAIL("\n%s-->pipe_in=%d pipe_out=%d\n",
+ qcelp13_info->thread_name,
+ qcelp13_info->pipe_in,
+ qcelp13_info->pipe_out);
+
+ qcelp13_info->process_msg_cb(qcelp13_info->client_data, id);
+ }
+ if ((n < 0) && (errno != EINTR)) break;
+ }
+ DEBUG_DETAIL("%s: message thread stop\n", __FUNCTION__);
+
+ return 0;
+}
+
+void *omx_qcelp13_events(void *info)
+{
+ struct qcelp13_ipc_info *qcelp13_info = (struct qcelp13_ipc_info*)info;
+ unsigned char id = 0;
+
+ DEBUG_DETAIL("%s: message thread start\n", qcelp13_info->thread_name);
+ qcelp13_info->process_msg_cb(qcelp13_info->client_data, id);
+ DEBUG_DETAIL("%s: message thread stop\n", qcelp13_info->thread_name);
+ return 0;
+}
+
+/**
+ @brief This function starts command server
+
+ @param cb pointer to callback function from the client
+ @param client_data reference client wants to get back
+ through callback
+ @return handle to msging thread
+ */
+struct qcelp13_ipc_info *omx_qcelp13_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct qcelp13_ipc_info *qcelp13_info;
+
+ qcelp13_info = calloc(1, sizeof(struct qcelp13_ipc_info));
+ if (!qcelp13_info)
+ {
+ return 0;
+ }
+
+ qcelp13_info->client_data = client_data;
+ qcelp13_info->process_msg_cb = cb;
+ strlcpy(qcelp13_info->thread_name, th_name,
+ sizeof(qcelp13_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT_ERROR("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ qcelp13_info->pipe_in = fds[0];
+ qcelp13_info->pipe_out = fds[1];
+
+ r = pthread_create(&qcelp13_info->thr, 0, omx_qcelp13_msg, qcelp13_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", qcelp13_info->thread_name);
+ return qcelp13_info;
+
+
+fail_thread:
+ close(qcelp13_info->pipe_in);
+ close(qcelp13_info->pipe_out);
+
+fail_pipe:
+ free(qcelp13_info);
+
+ return 0;
+}
+
+/**
+ * @brief This function starts command server
+ *
+ * @param cb pointer to callback function from the client
+ * @param client_data reference client wants to get back
+ * through callback
+ * @return handle to msging thread
+ * */
+struct qcelp13_ipc_info *omx_qcelp13_event_thread_create(
+ message_func cb,
+ void* client_data,
+ char* th_name)
+{
+ int r;
+ int fds[2];
+ struct qcelp13_ipc_info *qcelp13_info;
+
+ qcelp13_info = calloc(1, sizeof(struct qcelp13_ipc_info));
+ if (!qcelp13_info)
+ {
+ return 0;
+ }
+
+ qcelp13_info->client_data = client_data;
+ qcelp13_info->process_msg_cb = cb;
+ strlcpy(qcelp13_info->thread_name, th_name,
+ sizeof(qcelp13_info->thread_name));
+
+ if (pipe(fds))
+ {
+ DEBUG_PRINT("\n%s: pipe creation failed\n", __FUNCTION__);
+ goto fail_pipe;
+ }
+
+ qcelp13_info->pipe_in = fds[0];
+ qcelp13_info->pipe_out = fds[1];
+
+ r = pthread_create(&qcelp13_info->thr, 0, omx_qcelp13_events, qcelp13_info);
+ if (r < 0) goto fail_thread;
+
+ DEBUG_DETAIL("Created thread for %s \n", qcelp13_info->thread_name);
+ return qcelp13_info;
+
+
+fail_thread:
+ close(qcelp13_info->pipe_in);
+ close(qcelp13_info->pipe_out);
+
+fail_pipe:
+ free(qcelp13_info);
+
+ return 0;
+}
+
+void omx_qcelp13_thread_stop(struct qcelp13_ipc_info *qcelp13_info) {
+ DEBUG_DETAIL("%s stop server\n", __FUNCTION__);
+ close(qcelp13_info->pipe_in);
+ close(qcelp13_info->pipe_out);
+ pthread_join(qcelp13_info->thr,NULL);
+ qcelp13_info->pipe_out = -1;
+ qcelp13_info->pipe_in = -1;
+ DEBUG_DETAIL("%s: message thread close fds%d %d\n", qcelp13_info->thread_name,
+ qcelp13_info->pipe_in,qcelp13_info->pipe_out);
+ free(qcelp13_info);
+}
+
+void omx_qcelp13_post_msg(struct qcelp13_ipc_info *qcelp13_info, unsigned char id) {
+ DEBUG_DETAIL("\n%s id=%d\n", __FUNCTION__,id);
+
+ write(qcelp13_info->pipe_out, &id, 1);
+}
diff --git a/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp b/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp
new file mode 100644
index 0000000..f080e1f
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp
@@ -0,0 +1,4531 @@
+/*--------------------------------------------------------------------------
+Copyright (c) 2010, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+/*============================================================================
+@file omx_aenc_qcelp13.c
+ This module contains the implementation of the OpenMAX core & component.
+
+*//*========================================================================*/
+//////////////////////////////////////////////////////////////////////////////
+// Include Files
+//////////////////////////////////////////////////////////////////////////////
+
+
+#include<string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "omx_qcelp13_aenc.h"
+#include <errno.h>
+
+using namespace std;
+#define SLEEP_MS 100
+
+// omx_cmd_queue destructor
+omx_qcelp13_aenc::omx_cmd_queue::~omx_cmd_queue()
+{
+ // Nothing to do
+}
+
+// omx cmd queue constructor
+omx_qcelp13_aenc::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0)
+{
+ memset(m_q, 0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE);
+}
+
+// omx cmd queue insert
+bool omx_qcelp13_aenc::omx_cmd_queue::insert_entry(unsigned p1,
+ unsigned p2,
+ unsigned id)
+{
+ bool ret = true;
+ if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_q[m_write].id = id;
+ m_q[m_write].param1 = p1;
+ m_q[m_write].param2 = p2;
+ m_write++;
+ m_size ++;
+ if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_write = 0;
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full");
+ }
+ return ret;
+}
+
+bool omx_qcelp13_aenc::omx_cmd_queue::pop_entry(unsigned *p1,
+ unsigned *p2, unsigned *id)
+{
+ bool ret = true;
+ if (m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ *p1 = m_q[m_read].param1;
+ *p2 = m_q[m_read].param2;
+ // Move the read pointer ahead
+ ++m_read;
+ --m_size;
+ if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE)
+ {
+ m_read = 0;
+
+ }
+ } else
+ {
+ ret = false;
+ DEBUG_PRINT_ERROR("ERROR Delete!!! Command Queue Empty");
+ }
+ return ret;
+}
+
+// factory function executed by the core to create instances
+void *get_omx_component_factory_fn(void)
+{
+ return(new omx_qcelp13_aenc);
+}
+bool omx_qcelp13_aenc::omx_cmd_queue::get_msg_id(unsigned *id)
+{
+ if(m_size > 0)
+ {
+ *id = m_q[m_read].id;
+ DEBUG_PRINT("get_msg_id=%d\n",*id);
+ }
+ else{
+ return false;
+ }
+ return true;
+}
+/*=============================================================================
+FUNCTION:
+ wait_for_event
+
+DESCRIPTION:
+ waits for a particular event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_qcelp13_aenc::wait_for_event()
+{
+ int rc;
+ struct timespec ts;
+ pthread_mutex_lock(&m_event_lock);
+ while (0 == m_is_event_done)
+ {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += (SLEEP_MS/1000);
+ ts.tv_nsec += ((SLEEP_MS%1000) * 1000000);
+ rc = pthread_cond_timedwait(&cond, &m_event_lock, &ts);
+ if (rc == ETIMEDOUT && !m_is_event_done) {
+ DEBUG_PRINT("Timed out waiting for flush");
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ }
+ }
+ m_is_event_done = 0;
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+/*=============================================================================
+FUNCTION:
+ event_complete
+
+DESCRIPTION:
+ informs about the occurance of an event
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_qcelp13_aenc::event_complete()
+{
+ pthread_mutex_lock(&m_event_lock);
+ if (0 == m_is_event_done)
+ {
+ m_is_event_done = 1;
+ pthread_cond_signal(&cond);
+ }
+ pthread_mutex_unlock(&m_event_lock);
+}
+
+// All this non-sense because of a single qcelp13 object
+void omx_qcelp13_aenc::in_th_goto_sleep()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ while (0 == m_is_in_th_sleep)
+ {
+ pthread_cond_wait(&in_cond, &m_in_th_lock);
+ }
+ m_is_in_th_sleep = 0;
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_qcelp13_aenc::in_th_wakeup()
+{
+ pthread_mutex_lock(&m_in_th_lock);
+ if (0 == m_is_in_th_sleep)
+ {
+ m_is_in_th_sleep = 1;
+ pthread_cond_signal(&in_cond);
+ }
+ pthread_mutex_unlock(&m_in_th_lock);
+}
+
+void omx_qcelp13_aenc::out_th_goto_sleep()
+{
+
+ pthread_mutex_lock(&m_out_th_lock);
+ while (0 == m_is_out_th_sleep)
+ {
+ pthread_cond_wait(&out_cond, &m_out_th_lock);
+ }
+ m_is_out_th_sleep = 0;
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+
+void omx_qcelp13_aenc::out_th_wakeup()
+{
+ pthread_mutex_lock(&m_out_th_lock);
+ if (0 == m_is_out_th_sleep)
+ {
+ m_is_out_th_sleep = 1;
+ pthread_cond_signal(&out_cond);
+ }
+ pthread_mutex_unlock(&m_out_th_lock);
+}
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::omx_qcelp13_aenc
+
+DESCRIPTION
+ Constructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_qcelp13_aenc::omx_qcelp13_aenc(): m_tmp_meta_buf(NULL),
+ m_tmp_out_meta_buf(NULL),
+ m_flush_cnt(255),
+ m_comp_deinit(0),
+ m_app_data(NULL),
+ m_drv_fd(-1),
+ bFlushinprogress(0),
+ is_in_th_sleep(false),
+ is_out_th_sleep(false),
+ m_flags(0),
+ nTimestamp(0),
+ m_inp_act_buf_count (OMX_CORE_NUM_INPUT_BUFFERS),
+ m_out_act_buf_count (OMX_CORE_NUM_OUTPUT_BUFFERS),
+ m_inp_current_buf_count(0),
+ m_out_current_buf_count(0),
+ output_buffer_size(OMX_QCELP13_OUTPUT_BUFFER_SIZE),
+ input_buffer_size(OMX_CORE_INPUT_BUFFER_SIZE),
+ m_inp_bEnabled(OMX_TRUE),
+ m_out_bEnabled(OMX_TRUE),
+ m_inp_bPopulated(OMX_FALSE),
+ m_out_bPopulated(OMX_FALSE),
+ m_is_event_done(0),
+ m_state(OMX_StateInvalid),
+ m_ipc_to_in_th(NULL),
+ m_ipc_to_out_th(NULL),
+ m_ipc_to_cmd_th(NULL),
+ m_volume(25),
+ pcm_input(0),
+ nNumOutputBuf(0),
+ m_session_id(0),
+ m_ipc_to_event_th(NULL),
+ nNumInputBuf(0)
+{
+ int cond_ret = 0;
+ component_Role.nSize = 0;
+ memset(&m_cmp, 0, sizeof(m_cmp));
+ memset(&m_cb, 0, sizeof(m_cb));
+ memset(&m_qcelp13_pb_stats, 0, sizeof(m_qcelp13_pb_stats));
+ memset(&m_qcelp13_param, 0, sizeof(m_qcelp13_param));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+
+ pthread_mutexattr_init(&m_lock_attr);
+ pthread_mutex_init(&m_lock, &m_lock_attr);
+ pthread_mutexattr_init(&m_commandlock_attr);
+ pthread_mutex_init(&m_commandlock, &m_commandlock_attr);
+
+ pthread_mutexattr_init(&m_outputlock_attr);
+ pthread_mutex_init(&m_outputlock, &m_outputlock_attr);
+
+ pthread_mutexattr_init(&m_state_attr);
+ pthread_mutex_init(&m_state_lock, &m_state_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_flush_attr);
+ pthread_mutex_init(&m_flush_lock, &m_flush_attr);
+
+ pthread_mutexattr_init(&m_event_attr);
+ pthread_mutex_init(&m_event_lock, &m_event_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr);
+ pthread_mutex_init(&m_in_th_lock, &m_in_th_attr);
+
+ pthread_mutexattr_init(&m_out_th_attr);
+ pthread_mutex_init(&m_out_th_lock, &m_out_th_attr);
+
+ pthread_mutexattr_init(&m_in_th_attr_1);
+ pthread_mutex_init(&m_in_th_lock_1, &m_in_th_attr_1);
+
+ pthread_mutexattr_init(&m_out_th_attr_1);
+ pthread_mutex_init(&m_out_th_lock_1, &m_out_th_attr_1);
+
+ pthread_mutexattr_init(&out_buf_count_lock_attr);
+ pthread_mutex_init(&out_buf_count_lock, &out_buf_count_lock_attr);
+
+ pthread_mutexattr_init(&in_buf_count_lock_attr);
+ pthread_mutex_init(&in_buf_count_lock, &in_buf_count_lock_attr);
+ if ((cond_ret = pthread_cond_init (&cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&in_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for in_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+ if ((cond_ret = pthread_cond_init (&out_cond, NULL)) != 0)
+ {
+ DEBUG_PRINT_ERROR("pthread_cond_init returns non zero for out_cond\n");
+ if (cond_ret == EAGAIN)
+ DEBUG_PRINT_ERROR("The system lacked necessary \
+ resources(other than mem)\n");
+ else if (cond_ret == ENOMEM)
+ DEBUG_PRINT_ERROR("Insufficient memory to initialise \
+ condition variable\n");
+ }
+
+ sem_init(&sem_read_msg,0, 0);
+ sem_init(&sem_write_msg,0, 0);
+ sem_init(&sem_States,0, 0);
+ return;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::~omx_qcelp13_aenc
+
+DESCRIPTION
+ Destructor
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ None.
+========================================================================== */
+omx_qcelp13_aenc::~omx_qcelp13_aenc()
+{
+ DEBUG_PRINT_ERROR("QCELP13 Object getting destroyed comp-deinit=%d\n",
+ m_comp_deinit);
+ if ( !m_comp_deinit )
+ {
+ deinit_encoder();
+ }
+ pthread_mutexattr_destroy(&m_lock_attr);
+ pthread_mutex_destroy(&m_lock);
+
+ pthread_mutexattr_destroy(&m_commandlock_attr);
+ pthread_mutex_destroy(&m_commandlock);
+
+ pthread_mutexattr_destroy(&m_outputlock_attr);
+ pthread_mutex_destroy(&m_outputlock);
+
+ pthread_mutexattr_destroy(&m_state_attr);
+ pthread_mutex_destroy(&m_state_lock);
+
+ pthread_mutexattr_destroy(&m_event_attr);
+ pthread_mutex_destroy(&m_event_lock);
+
+ pthread_mutexattr_destroy(&m_flush_attr);
+ pthread_mutex_destroy(&m_flush_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr);
+ pthread_mutex_destroy(&m_in_th_lock);
+
+ pthread_mutexattr_destroy(&m_out_th_attr);
+ pthread_mutex_destroy(&m_out_th_lock);
+
+ pthread_mutexattr_destroy(&out_buf_count_lock_attr);
+ pthread_mutex_destroy(&out_buf_count_lock);
+
+ pthread_mutexattr_destroy(&in_buf_count_lock_attr);
+ pthread_mutex_destroy(&in_buf_count_lock);
+
+ pthread_mutexattr_destroy(&m_in_th_attr_1);
+ pthread_mutex_destroy(&m_in_th_lock_1);
+
+ pthread_mutexattr_destroy(&m_out_th_attr_1);
+ pthread_mutex_destroy(&m_out_th_lock_1);
+ pthread_cond_destroy(&cond);
+ pthread_cond_destroy(&in_cond);
+ pthread_cond_destroy(&out_cond);
+ sem_destroy (&sem_read_msg);
+ sem_destroy (&sem_write_msg);
+ sem_destroy (&sem_States);
+ DEBUG_PRINT_ERROR("OMX QCELP13 component destroyed\n");
+ return;
+}
+
+/**
+ @brief memory function for sending EmptyBufferDone event
+ back to IL client
+
+ @param bufHdr OMX buffer header to be passed back to IL client
+ @return none
+ */
+void omx_qcelp13_aenc::buffer_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.EmptyBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_BUFFER_DONE,bufHdr);
+ bufHdr->nFilledLen = 0;
+
+ m_cb.EmptyBufferDone(&m_cmp, m_app_data, bufHdr);
+ pthread_mutex_lock(&in_buf_count_lock);
+ m_qcelp13_pb_stats.ebd_cnt++;
+ nNumInputBuf--;
+ DEBUG_DETAIL("EBD CB:: in_buf_len=%d nNumInputBuf=%d\n",\
+ m_qcelp13_pb_stats.tot_in_buf_len,
+ nNumInputBuf, m_qcelp13_pb_stats.ebd_cnt);
+ pthread_mutex_unlock(&in_buf_count_lock);
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ flush_ack
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_qcelp13_aenc::flush_ack()
+{
+ // Decrement the FLUSH ACK count and notify the waiting recepients
+ pthread_mutex_lock(&m_flush_lock);
+ --m_flush_cnt;
+ if (0 == m_flush_cnt)
+ {
+ event_complete();
+ }
+ DEBUG_PRINT("Rxed FLUSH ACK cnt=%d\n",m_flush_cnt);
+ pthread_mutex_unlock(&m_flush_lock);
+}
+void omx_qcelp13_aenc::frame_done_cb(OMX_BUFFERHEADERTYPE *bufHdr)
+{
+ if (m_cb.FillBufferDone)
+ {
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_FRAME_DONE,bufHdr);
+ m_qcelp13_pb_stats.fbd_cnt++;
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf--;
+ DEBUG_PRINT("FBD CB:: nNumOutputBuf=%d out_buf_len=%lu fbd_cnt=%lu\n",\
+ nNumOutputBuf,
+ m_qcelp13_pb_stats.tot_out_buf_len,
+ m_qcelp13_pb_stats.fbd_cnt);
+ m_qcelp13_pb_stats.tot_out_buf_len += bufHdr->nFilledLen;
+ m_qcelp13_pb_stats.tot_pb_time = bufHdr->nTimeStamp;
+ DEBUG_PRINT("FBD:in_buf_len=%lu out_buf_len=%lu\n",
+ m_qcelp13_pb_stats.tot_in_buf_len,
+ m_qcelp13_pb_stats.tot_out_buf_len);
+
+ pthread_mutex_unlock(&out_buf_count_lock);
+ m_cb.FillBufferDone(&m_cmp, m_app_data, bufHdr);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_out_port_msg
+
+DESCRIPTION:
+ Function for handling all commands from IL client
+IL client commands are processed and callbacks are generated through
+this routine Audio Command Server provides the thread context for this routine
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_qcelp13_aenc::process_out_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0; // qsize
+ unsigned tot_qsize = 0;
+ omx_qcelp13_aenc *pThis = (omx_qcelp13_aenc *) client_data;
+ OMX_STATETYPE state;
+
+loopback_out:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" OUT: IN LOADED STATE RETURN\n");
+ return;
+ }
+ pthread_mutex_lock(&pThis->m_outputlock);
+
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_DETAIL("OUT-->BREAK FROM LOOP...%d\n",tot_qsize);
+ return;
+ }
+ if ( (state != OMX_StateExecuting) && !qsize )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ DEBUG_DETAIL("OUT:1.SLEEPING OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+
+ if ( ((!pThis->m_output_ctrl_cmd_q.m_size) && !pThis->m_out_bEnabled) )
+ {
+ // case where no port reconfig and nothing in the flush q
+ DEBUG_DETAIL("No flush/port reconfig qsize=%d tot_qsize=%d",\
+ qsize,tot_qsize);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ return;
+
+ if(pThis->m_output_ctrl_cmd_q.m_size || !(pThis->bFlushinprogress))
+ {
+ DEBUG_PRINT("OUT:2. SLEEPING OUT THREAD \n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pThis->out_th_goto_sleep();
+ }
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize = pThis->m_output_ctrl_cmd_q.m_size;
+ tot_qsize += pThis->m_output_ctrl_fbd_q.m_size;
+ tot_qsize += pThis->m_output_q.m_size;
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_DETAIL("OUT-->QSIZE-flush=%d,fbd=%d QSIZE=%d state=%d\n",\
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size,state);
+
+
+ if (qsize)
+ {
+ // process FLUSH message
+ pThis->m_output_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_ctrl_fbd_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_output_ctrl_fbd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_output_q.m_size) &&
+ (pThis->m_out_bEnabled) && (state == OMX_StateExecuting) )
+ {
+ // if no FLUSH and FBD's then process FTB's
+ pThis->m_output_q.pop_entry(&p1,&p2,&ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("OUT--> Empty Queue state=%d %d %d %d\n",state,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("OUT: SLEEPING AGAIN OUT THREAD\n");
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ pThis->is_out_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_outputlock);
+ pThis->out_th_goto_sleep();
+ goto loopback_out;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_outputlock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ ident = 0;
+ DEBUG_DETAIL("OUT->state[%d]ident[%d]flushq[%d]fbd[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_output_ctrl_cmd_q.m_size,
+ pThis->m_output_ctrl_fbd_q.m_size,
+ pThis->m_output_q.m_size);
+
+ if ( OMX_COMPONENT_GENERATE_FRAME_DONE == id )
+ {
+ pThis->frame_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_FTB == id )
+ {
+ pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_EOS == id )
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+
+ }
+ else if(id == OMX_COMPONENT_RESUME)
+ {
+ DEBUG_PRINT("RESUMED...\n");
+ }
+ else if(id == OMX_COMPONENT_GENERATE_COMMAND)
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL("Executing FLUSH command on Output port\n");
+ pThis->execute_output_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:OUT-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR: OUT--> Empty OUTPUTQ\n");
+ }
+
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_command_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_qcelp13_aenc::process_command_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ omx_qcelp13_aenc *pThis = (omx_qcelp13_aenc*)client_data;
+ pthread_mutex_lock(&pThis->m_commandlock);
+
+ qsize = pThis->m_command_q.m_size;
+ DEBUG_DETAIL("CMD-->QSIZE=%d state=%d\n",pThis->m_command_q.m_size,
+ pThis->m_state);
+
+ if (!qsize)
+ {
+ DEBUG_DETAIL("CMD-->BREAKING FROM LOOP\n");
+ pthread_mutex_unlock(&pThis->m_commandlock);
+ return;
+ } else
+ {
+ pThis->m_command_q.pop_entry(&p1,&p2,&ident);
+ }
+ pthread_mutex_unlock(&pThis->m_commandlock);
+
+ id = ident;
+ DEBUG_DETAIL("CMD->state[%d]id[%d]cmdq[%d]n",\
+ pThis->m_state,ident, \
+ pThis->m_command_q.m_size);
+
+ if (OMX_COMPONENT_GENERATE_EVENT == id)
+ {
+ if (pThis->m_cb.EventHandler)
+ {
+ if (OMX_CommandStateSet == p1)
+ {
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->m_state = (OMX_STATETYPE) p2;
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ DEBUG_PRINT("CMD:Process->state set to %d \n", \
+ pThis->m_state);
+
+ if (pThis->m_state == OMX_StateExecuting ||
+ pThis->m_state == OMX_StateLoaded)
+ {
+
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ if (pThis->is_in_th_sleep)
+ {
+ pThis->is_in_th_sleep = false;
+ DEBUG_DETAIL("CMD:WAKING UP IN THREADS\n");
+ pThis->in_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+
+ pthread_mutex_lock(&pThis->m_out_th_lock_1);
+ if (pThis->is_out_th_sleep)
+ {
+ DEBUG_DETAIL("CMD:WAKING UP OUT THREADS\n");
+ pThis->is_out_th_sleep = false;
+ pThis->out_th_wakeup();
+ }
+ pthread_mutex_unlock(&pThis->m_out_th_lock_1);
+ }
+ }
+ if (OMX_StateInvalid == pThis->m_state)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ } else if ((signed)p2 == OMX_ErrorPortUnpopulated)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventError,
+ p2,
+ NULL,
+ NULL );
+ } else
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventCmdComplete,
+ p1, p2, NULL );
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("ERROR:CMD-->EventHandler NULL \n");
+ }
+ } else if (OMX_COMPONENT_GENERATE_COMMAND == id)
+ {
+ pThis->send_command_proxy(&pThis->m_cmp,
+ (OMX_COMMANDTYPE)p1,
+ (OMX_U32)p2,(OMX_PTR)NULL);
+ } else if (OMX_COMPONENT_PORTSETTINGS_CHANGED == id)
+ {
+ DEBUG_DETAIL("CMD-->RXED PORTSETTINGS_CHANGED");
+ pThis->m_cb.EventHandler(&pThis->m_cmp,
+ pThis->m_app_data,
+ OMX_EventPortSettingsChanged,
+ 1, 1, NULL );
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("CMD->state[%d]id[%d]\n",pThis->m_state,ident);
+ }
+ return;
+}
+
+/*=============================================================================
+FUNCTION:
+ process_in_port_msg
+
+DESCRIPTION:
+
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] client_data
+ [IN] id
+
+RETURN VALUE:
+ None
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+void omx_qcelp13_aenc::process_in_port_msg(void *client_data, unsigned char id)
+{
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize = 0;
+ unsigned tot_qsize = 0;
+ omx_qcelp13_aenc *pThis = (omx_qcelp13_aenc *) client_data;
+ OMX_STATETYPE state;
+
+ if (!pThis)
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN--> Invalid Obj \n");
+ return;
+ }
+loopback_in:
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ if ( state == OMX_StateLoaded )
+ {
+ DEBUG_PRINT(" IN: IN LOADED STATE RETURN\n");
+ return;
+ }
+ // Protect the shared queue data structure
+ pthread_mutex_lock(&pThis->m_lock);
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ if ( 0 == tot_qsize )
+ {
+ DEBUG_DETAIL("IN-->BREAKING FROM IN LOOP");
+ pthread_mutex_unlock(&pThis->m_lock);
+ return;
+ }
+
+ if ( (state != OMX_StateExecuting) && ! (pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_DETAIL("SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ /* Get the updated state */
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ else if ((state == OMX_StatePause))
+ {
+ if(!(pThis->m_input_ctrl_cmd_q.m_size))
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ DEBUG_DETAIL("IN: SLEEPING IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pThis->in_th_goto_sleep();
+
+ pthread_mutex_lock(&pThis->m_state_lock);
+ pThis->get_state(&pThis->m_cmp, &state);
+ pthread_mutex_unlock(&pThis->m_state_lock);
+ }
+ }
+
+ qsize = pThis->m_input_ctrl_cmd_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += pThis->m_input_ctrl_ebd_q.m_size;
+ tot_qsize += pThis->m_input_q.m_size;
+
+ DEBUG_DETAIL("Input-->QSIZE-flush=%d,ebd=%d QSIZE=%d state=%d\n",\
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size, state);
+
+
+ if ( qsize )
+ {
+ // process FLUSH message
+ pThis->m_input_ctrl_cmd_q.pop_entry(&p1,&p2,&ident);
+ } else if ( (qsize = pThis->m_input_ctrl_ebd_q.m_size) &&
+ (state == OMX_StateExecuting) )
+ {
+ // then process EBD's
+ pThis->m_input_ctrl_ebd_q.pop_entry(&p1,&p2,&ident);
+ } else if ((qsize = pThis->m_input_q.m_size) &&
+ (state == OMX_StateExecuting))
+ {
+ // if no FLUSH and EBD's then process ETB's
+ pThis->m_input_q.pop_entry(&p1, &p2, &ident);
+ } else if ( state == OMX_StateLoaded )
+ {
+ pthread_mutex_unlock(&pThis->m_lock);
+ DEBUG_PRINT("IN: ***in OMX_StateLoaded so exiting\n");
+ return ;
+ } else
+ {
+ qsize = 0;
+ DEBUG_PRINT("IN-->state[%d]cmdq[%d]ebdq[%d]in[%d]\n",\
+ state,pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+
+ if(state == OMX_StatePause)
+ {
+ DEBUG_DETAIL("IN: SLEEPING AGAIN IN THREAD\n");
+ pthread_mutex_lock(&pThis->m_in_th_lock_1);
+ pThis->is_in_th_sleep = true;
+ pthread_mutex_unlock(&pThis->m_in_th_lock_1);
+ pthread_mutex_unlock(&pThis->m_lock);
+ pThis->in_th_goto_sleep();
+ goto loopback_in;
+ }
+ }
+ pthread_mutex_unlock(&pThis->m_lock);
+
+ if ( qsize > 0 )
+ {
+ id = ident;
+ DEBUG_DETAIL("Input->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ pThis->m_state,
+ ident,
+ pThis->m_input_ctrl_cmd_q.m_size,
+ pThis->m_input_ctrl_ebd_q.m_size,
+ pThis->m_input_q.m_size);
+ if ( OMX_COMPONENT_GENERATE_BUFFER_DONE == id )
+ {
+ pThis->buffer_done_cb((OMX_BUFFERHEADERTYPE *)p2);
+ }
+ else if(id == OMX_COMPONENT_GENERATE_EOS)
+ {
+ pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
+ OMX_EventBufferFlag, 0, 1, NULL );
+ } else if ( OMX_COMPONENT_GENERATE_ETB == id )
+ {
+ pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,
+ (OMX_BUFFERHEADERTYPE *)p2);
+ } else if ( OMX_COMPONENT_GENERATE_COMMAND == id )
+ {
+ // Execute FLUSH command
+ if ( OMX_CommandFlush == p1 )
+ {
+ DEBUG_DETAIL(" Executing FLUSH command on Input port\n");
+ pThis->execute_input_omx_flush();
+ } else
+ {
+ DEBUG_DETAIL("Invalid command[%d]\n",p1);
+ }
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR("ERROR:IN-->Invalid Id[%d]\n",id);
+ }
+ } else
+ {
+ DEBUG_DETAIL("ERROR:IN-->Empty INPUT Q\n");
+ }
+ return;
+}
+
+/**
+ @brief member function for performing component initialization
+
+ @param role C string mandating role of this component
+ @return Error status
+ */
+OMX_ERRORTYPE omx_qcelp13_aenc::component_init(OMX_STRING role)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ m_state = OMX_StateLoaded;
+
+ /* DSP does not give information about the bitstream
+ randomly assign the value right now. Query will result in
+ incorrect param */
+ memset(&m_qcelp13_param, 0, sizeof(m_qcelp13_param));
+ m_qcelp13_param.nSize = sizeof(m_qcelp13_param);
+ m_qcelp13_param.nChannels = OMX_QCELP13_DEFAULT_CH_CFG;
+ //Current DSP does not have config
+ m_qcelp13_param.eCDMARate = OMX_AUDIO_CDMARateFull;
+ m_qcelp13_param.nMinBitRate = OMX_QCELP13_DEFAULT_MINRATE;
+ m_qcelp13_param.nMaxBitRate = OMX_QCELP13_DEFAULT_MAXRATE;
+ m_volume = OMX_QCELP13_DEFAULT_VOL; /* Close to unity gain */
+ memset(&m_qcelp13_pb_stats,0,sizeof(QCELP13_PB_STATS));
+ memset(&m_pcm_param, 0, sizeof(m_pcm_param));
+ m_pcm_param.nSize = sizeof(m_pcm_param);
+ m_pcm_param.nChannels = OMX_QCELP13_DEFAULT_CH_CFG;
+ m_pcm_param.nSamplingRate = OMX_QCELP13_DEFAULT_SF;
+ nTimestamp = 0;
+
+
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ m_ipc_to_in_th = NULL; // Command server instance
+ m_ipc_to_out_th = NULL; // Client server instance
+ m_ipc_to_cmd_th = NULL; // command instance
+ m_is_out_th_sleep = 0;
+ m_is_in_th_sleep = 0;
+ is_out_th_sleep= false;
+
+ is_in_th_sleep=false;
+
+ memset(&m_priority_mgm, 0, sizeof(m_priority_mgm));
+ m_priority_mgm.nGroupID =0;
+ m_priority_mgm.nGroupPriority=0;
+
+ memset(&m_buffer_supplier, 0, sizeof(m_buffer_supplier));
+ m_buffer_supplier.nPortIndex=OMX_BufferSupplyUnspecified;
+
+ DEBUG_PRINT_ERROR(" component init: role = %s\n",role);
+
+ DEBUG_PRINT(" component init: role = %s\n",role);
+ component_Role.nVersion.nVersion = OMX_SPEC_VERSION;
+ if (!strcmp(role,"OMX.qcom.audio.encoder.qcelp13"))
+ {
+ pcm_input = 1;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole, (const char*)role,
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else if (!strcmp(role,"OMX.qcom.audio.encoder.tunneled.qcelp13"))
+ {
+ pcm_input = 0;
+ component_Role.nSize = sizeof(role);
+ strlcpy((char *)component_Role.cRole, (const char*)role,
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED \n", role);
+ } else
+ {
+ component_Role.nSize = sizeof("\0");
+ strlcpy((char *)component_Role.cRole, (const char*)"\0",
+ sizeof(component_Role.cRole));
+ DEBUG_PRINT("\ncomponent_init: Component %s LOADED is invalid\n", role);
+ }
+ if(pcm_input)
+ {
+
+
+ m_tmp_meta_buf = (OMX_U8*) malloc(sizeof(OMX_U8) *
+ (OMX_CORE_INPUT_BUFFER_SIZE + sizeof(META_IN)));
+
+ if (m_tmp_meta_buf == NULL){
+ DEBUG_PRINT_ERROR("Mem alloc failed for in meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ m_tmp_out_meta_buf =
+ (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_QCELP13_OUTPUT_BUFFER_SIZE);
+ if ( m_tmp_out_meta_buf == NULL ) {
+ DEBUG_PRINT_ERROR("Mem alloc failed for out meta buf\n");
+ return OMX_ErrorInsufficientResources;
+ }
+
+ if(0 == pcm_input)
+ {
+ m_drv_fd = open("/dev/msm_qcelp_in",O_RDONLY);
+ DEBUG_PRINT("Driver in Tunnel mode open\n");
+ }
+ else
+ {
+ m_drv_fd = open("/dev/msm_qcelp_in",O_RDWR);
+ DEBUG_PRINT("Driver in Non Tunnel mode open\n");
+ }
+ if (m_drv_fd < 0)
+ {
+ DEBUG_PRINT_ERROR("Component_init Open Failed[%d] errno[%d]",\
+ m_drv_fd,errno);
+
+ return OMX_ErrorInsufficientResources;
+ }
+ if(ioctl(m_drv_fd, AUDIO_GET_SESSION_ID,&m_session_id) == -1)
+ {
+ DEBUG_PRINT_ERROR("AUDIO_GET_SESSION_ID FAILED\n");
+ }
+ if(pcm_input)
+ {
+ if (!m_ipc_to_in_th)
+ {
+ m_ipc_to_in_th = omx_qcelp13_thread_create(process_in_port_msg,
+ this, (char *)"INPUT_THREAD");
+ if (!m_ipc_to_in_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start \
+ Input port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ }
+
+ if (!m_ipc_to_cmd_th)
+ {
+ m_ipc_to_cmd_th = omx_qcelp13_thread_create(process_command_msg,
+ this, (char *)"CMD_THREAD");
+ if (!m_ipc_to_cmd_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!!Failed to start "
+ "command message thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+
+ if (!m_ipc_to_out_th)
+ {
+ m_ipc_to_out_th = omx_qcelp13_thread_create(process_out_port_msg,
+ this, (char *)"OUTPUT_THREAD");
+ if (!m_ipc_to_out_th)
+ {
+ DEBUG_PRINT_ERROR("ERROR!!! Failed to start output "
+ "port thread\n");
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ return eRet;
+}
+
+/**
+
+ @brief member function to retrieve version of component
+
+
+
+ @param hComp handle to this component instance
+ @param componentName name of component
+ @param componentVersion pointer to memory space which stores the
+ version number
+ @param specVersion pointer to memory sapce which stores version of
+ openMax specification
+ @param componentUUID
+ @return Error status
+ */
+OMX_ERRORTYPE omx_qcelp13_aenc::get_component_version
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STRING componentName,
+ OMX_OUT OMX_VERSIONTYPE* componentVersion,
+ OMX_OUT OMX_VERSIONTYPE* specVersion,
+ OMX_OUT OMX_UUIDTYPE* componentUUID)
+{
+ if((hComp == NULL) || (componentName == NULL) ||
+ (specVersion == NULL) || (componentUUID == NULL))
+ {
+ componentVersion = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ componentVersion->nVersion = OMX_SPEC_VERSION;
+ specVersion->nVersion = OMX_SPEC_VERSION;
+ return OMX_ErrorNone;
+}
+/**
+ @brief member function handles command from IL client
+
+ This function simply queue up commands from IL client.
+ Commands will be processed in command server thread context later
+
+ @param hComp handle to component instance
+ @param cmd type of command
+ @param param1 parameters associated with the command type
+ @param cmdData
+ @return Error status
+*/
+OMX_ERRORTYPE omx_qcelp13_aenc::send_command(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ int portIndex = (int)param1;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateInvalid == m_state)
+ {
+ return OMX_ErrorInvalidState;
+ }
+ if ( (cmd == OMX_CommandFlush) && (portIndex > 1) )
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ post_command((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND);
+ DEBUG_PRINT("Send Command : returns with OMX_ErrorNone \n");
+ DEBUG_PRINT("send_command : recieved state before semwait= %lu\n",param1);
+ sem_wait (&sem_States);
+ DEBUG_PRINT("send_command : recieved state after semwait\n");
+ return OMX_ErrorNone;
+}
+
+/**
+ @brief member function performs actual processing of commands excluding
+ empty buffer call
+
+ @param hComp handle to component
+ @param cmd command type
+ @param param1 parameter associated with the command
+ @param cmdData
+
+ @return error status
+*/
+OMX_ERRORTYPE omx_qcelp13_aenc::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_COMMANDTYPE cmd,
+ OMX_IN OMX_U32 param1,
+ OMX_IN OMX_PTR cmdData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ // Handle only IDLE and executing
+ OMX_STATETYPE eState = (OMX_STATETYPE) param1;
+ int bFlag = 1;
+ nState = eState;
+
+ if(hComp == NULL)
+ {
+ cmdData = NULL;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_CommandStateSet == cmd)
+ {
+ /***************************/
+ /* Current State is Loaded */
+ /***************************/
+ if (OMX_StateLoaded == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+
+ if (allocate_done() ||
+ (m_inp_bEnabled == OMX_FALSE
+ && m_out_bEnabled == OMX_FALSE))
+ {
+ DEBUG_PRINT("SCP-->Allocate Done Complete\n");
+ }
+ else
+ {
+ DEBUG_PRINT("SCP-->Loaded to Idle-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ bFlag = 0;
+ }
+
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Loaded\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ }
+
+ else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->WaitForResources\n");
+ eRet = OMX_ErrorNone;
+ }
+
+ else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Executing\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Pause\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Loaded-->Invalid\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ m_state = OMX_StateInvalid;
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->Loaded to Invalid(%d))\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /***************************/
+ /* Current State is IDLE */
+ /***************************/
+ else if (OMX_StateIdle == m_state)
+ {
+ if (OMX_StateLoaded == eState)
+ {
+ if (release_done(-1))
+ {
+ if (ioctl(m_drv_fd, AUDIO_STOP, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("SCP:Idle->Loaded,\
+ ioctl stop failed %d\n", errno);
+ }
+
+ nTimestamp=0;
+
+ DEBUG_PRINT("SCP-->Idle to Loaded\n");
+ } else
+ {
+ DEBUG_PRINT("SCP--> Idle to Loaded-Pending\n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING);
+ // Skip the event notification
+ bFlag = 0;
+ }
+ }
+ else if (OMX_StateExecuting == eState)
+ {
+
+ struct msm_audio_qcelp_enc_config drv_qcelp13_enc_config;
+ struct msm_audio_stream_config drv_stream_config;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+
+ if(ioctl(m_drv_fd, AUDIO_GET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+ if(ioctl(m_drv_fd, AUDIO_SET_STREAM_CONFIG, &drv_stream_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_STREAM_CONFIG failed, \
+ errno[%d]\n", errno);
+ }
+
+ if(ioctl(m_drv_fd, AUDIO_GET_QCELP_ENC_CONFIG,
+ &drv_qcelp13_enc_config) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_QCELP_ENC_CONFIG failed,\
+ errno[%d]\n", errno);
+ }
+ drv_qcelp13_enc_config.min_bit_rate = m_qcelp13_param.nMinBitRate;
+ drv_qcelp13_enc_config.max_bit_rate = m_qcelp13_param.nMaxBitRate;
+ if(ioctl(m_drv_fd, AUDIO_SET_QCELP_ENC_CONFIG, &drv_qcelp13_enc_config)
+ == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_QCELP_ENC_CONFIG \
+ failed, errno[%d]\n", errno);
+ }
+ if (ioctl(m_drv_fd, AUDIO_GET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ buf_cfg.meta_info_enable = 1;
+ buf_cfg.frames_per_buf = NUMOFFRAMES;
+ if (ioctl(m_drv_fd, AUDIO_SET_BUF_CFG, &buf_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_BUF_CFG, errno[%d]\n",
+ errno);
+ }
+ if(pcm_input)
+ {
+ if (ioctl(m_drv_fd, AUDIO_GET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_GET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ pcm_cfg.channel_count = m_pcm_param.nChannels;
+ pcm_cfg.sample_rate = m_pcm_param.nSamplingRate;
+ DEBUG_PRINT("pcm config %lu %lu\n",m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+
+ if (ioctl(m_drv_fd, AUDIO_SET_CONFIG, &pcm_cfg) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_SET_CONFIG, errno[%d]\n",
+ errno);
+ }
+ }
+ if(ioctl(m_drv_fd, AUDIO_START, 0) == -1)
+ {
+ DEBUG_PRINT_ERROR("ioctl AUDIO_START failed, errno[%d]\n",
+ errno);
+ }
+ DEBUG_PRINT("SCP-->Idle to Executing\n");
+ nState = eState;
+ } else if (eState == OMX_StateIdle)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Idle\n");
+ m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ }
+
+ else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Pause\n");
+ }
+
+ else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Idle-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp,
+ this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Idle to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+
+ /******************************/
+ /* Current State is Executing */
+ /******************************/
+ else if (OMX_StateExecuting == m_state)
+ {
+ if (OMX_StateIdle == eState)
+ {
+ DEBUG_PRINT("SCP-->Executing to Idle \n");
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+
+ } else if (OMX_StatePause == eState)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED PAUSE STATE\n");
+ DEBUG_DETAIL("*************************\n");
+ //ioctl(m_drv_fd, AUDIO_PAUSE, 0);
+ } else if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Executing \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n OMXCORE-SM: Executing --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> Executing to %d Not Handled\n",
+ eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /***************************/
+ /* Current State is Pause */
+ /***************************/
+ else if (OMX_StatePause == m_state)
+ {
+ if( (eState == OMX_StateExecuting || eState == OMX_StateIdle) )
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if(is_out_th_sleep)
+ {
+ DEBUG_DETAIL("PE: WAKING UP OUT THREAD\n");
+ is_out_th_sleep = false;
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ }
+ if ( OMX_StateExecuting == eState )
+ {
+ nState = eState;
+ } else if ( OMX_StateIdle == eState )
+ {
+ DEBUG_PRINT("SCP-->Paused to Idle \n");
+ DEBUG_PRINT ("\n Internal flush issued");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+
+ } else if ( eState == OMX_StateLoaded )
+ {
+ DEBUG_PRINT("\n Pause --> loaded \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("\n Pause --> WaitForResources \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("\n Pause --> Pause \n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("\n Pause --> Invalid \n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT("SCP-->Paused to %d Not Handled\n",eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /**************************************/
+ /* Current State is WaitForResources */
+ /**************************************/
+ else if (m_state == OMX_StateWaitForResources)
+ {
+ if (eState == OMX_StateLoaded)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Loaded\n");
+ } else if (eState == OMX_StateWaitForResources)
+ {
+ DEBUG_PRINT("OMXCORE-SM: \
+ WaitForResources-->WaitForResources\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorSameState,
+ 0, NULL );
+ eRet = OMX_ErrorSameState;
+ } else if (eState == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Executing\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StatePause)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Pause\n");
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorIncorrectStateTransition,
+ 0, NULL );
+ eRet = OMX_ErrorIncorrectStateTransition;
+ } else if (eState == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("OMXCORE-SM: WaitForResources-->Invalid\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError,
+ OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP--> %d to %d(Not Handled)\n",
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ /****************************/
+ /* Current State is Invalid */
+ /****************************/
+ else if (m_state == OMX_StateInvalid)
+ {
+ if (OMX_StateLoaded == eState || OMX_StateWaitForResources == eState
+ || OMX_StateIdle == eState || OMX_StateExecuting == eState
+ || OMX_StatePause == eState || OMX_StateInvalid == eState)
+ {
+ DEBUG_PRINT("OMXCORE-SM: Invalid-->Loaded/Idle/Executing"
+ "/Pause/Invalid/WaitForResources\n");
+ m_state = OMX_StateInvalid;
+ this->m_cb.EventHandler(&this->m_cmp, this->m_app_data,
+ OMX_EventError, OMX_ErrorInvalidState,
+ 0, NULL );
+ eRet = OMX_ErrorInvalidState;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMXCORE-SM: %d --> %d(Not Handled)\n",\
+ m_state,eState);
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else if (OMX_CommandFlush == cmd)
+ {
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_PRINT("SCP-->RXED FLUSH COMMAND port=%lu\n",param1);
+ DEBUG_DETAIL("*************************\n");
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX ||
+ param1 == OMX_CORE_OUTPUT_PORT_INDEX ||
+ (signed)param1 == -1 )
+ {
+ execute_omx_flush(param1);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventError,
+ OMX_CommandFlush, OMX_ErrorBadPortIndex, NULL );
+ }
+ } else if ( cmd == OMX_CommandPortDisable )
+ {
+ bFlag = 0;
+ if ( param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL )
+ {
+ DEBUG_PRINT("SCP: Disabling Input port Indx\n");
+ m_inp_bEnabled = OMX_FALSE;
+ if ( (m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(0) )
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_inp_bEnabled=%d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+
+ else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable in "\
+ " param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_INPUT_PORT_INDEX \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+
+ }
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+
+ DEBUG_PRINT("SCP: Disabling Output port Indx\n");
+ m_out_bEnabled = OMX_FALSE;
+ if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
+ && release_done(1))
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortDisable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ DEBUG_PRINT("************* OMX_CommandPortDisable:\
+ m_out_bEnabled=%d********\n",m_inp_bEnabled);
+
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT("SCP: execute_omx_flush in Disable out "\
+ "param1=%lu m_state=%d \n",param1, m_state);
+ execute_omx_flush(param1);
+ }
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ // Skip the event notification
+
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortDisable: disable wrong port ID");
+ }
+
+ } else if (cmd == OMX_CommandPortEnable)
+ {
+ bFlag = 0;
+ if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ m_inp_bEnabled = OMX_TRUE;
+ DEBUG_PRINT("SCP: Enabling Input port Indx\n");
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_inp_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+
+ } else
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ }
+
+ if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL)
+ {
+ DEBUG_PRINT("SCP: Enabling Output port Indx\n");
+ m_out_bEnabled = OMX_TRUE;
+ if ((m_state == OMX_StateLoaded
+ && !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources)
+ || (m_out_bPopulated == OMX_TRUE))
+ {
+ post_command(OMX_CommandPortEnable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ } else
+ {
+ DEBUG_PRINT("send_command_proxy:OMX_CommandPortEnable:\
+ OMX_CORE_OUTPUT_PORT_INDEX:release_done \n");
+ BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ // Skip the event notification
+
+ }
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_PRINT("SCP:WAKING OUT THR, OMX_CommandPortEnable\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ } else
+ {
+ DEBUG_PRINT_ERROR("OMX_CommandPortEnable: disable wrong port ID");
+ }
+
+ } else
+ {
+ DEBUG_PRINT_ERROR("SCP-->ERROR: Invali Command [%d]\n",cmd);
+ eRet = OMX_ErrorNotImplemented;
+ }
+ DEBUG_PRINT("posting sem_States\n");
+ sem_post (&sem_States);
+ if (eRet == OMX_ErrorNone && bFlag)
+ {
+ post_command(cmd,eState,OMX_COMPONENT_GENERATE_EVENT);
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] param1
+ [IN] cmd_cmpl
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_qcelp13_aenc::execute_omx_flush(OMX_IN OMX_U32 param1, bool cmd_cmpl)
+{
+ bool bRet = true;
+
+ DEBUG_PRINT("Execute_omx_flush Port[%lu]", param1);
+ struct timespec abs_timeout;
+ abs_timeout.tv_sec = 1;
+ abs_timeout.tv_nsec = 0;
+
+ if ((signed)param1 == -1)
+ {
+ bFlushinprogress = true;
+ DEBUG_PRINT("Execute flush for both I/p O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 2;
+ pthread_mutex_unlock(&m_flush_lock);
+
+ // Send Flush commands to input and output threads
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ // Send Flush to the kernel so that the in and out buffers are released
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("FLush:ioctl flush failed errno=%d\n",errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+
+ DEBUG_PRINT("RECIEVED BOTH FLUSH ACK's param1=%lu cmd_cmpl=%d",\
+ param1,cmd_cmpl);
+
+ // If not going to idle state, Send FLUSH complete message
+ // to the Client, now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ DEBUG_PRINT("Inside FLUSH.. sending FLUSH CMPL\n");
+ }
+ bFlushinprogress = false;
+ }
+ else if (param1 == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("Execute FLUSH for I/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ post_input(OMX_CommandFlush,
+ OMX_CORE_INPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) == -1)
+ DEBUG_PRINT_ERROR("Flush:Input port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ //sleep till the FLUSH ACK are done by both the input and output threads
+ DEBUG_DETAIL("Executing FLUSH for I/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ wait_for_event();
+ DEBUG_DETAIL(" RECIEVED FLUSH ACK FOR I/P PORT param1=%d",param1);
+
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_INPUT_PORT_INDEX,
+ NULL );
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == param1)
+ {
+ DEBUG_PRINT("Executing FLUSH for O/p port\n");
+ pthread_mutex_lock(&m_flush_lock);
+ m_flush_cnt = 1;
+ pthread_mutex_unlock(&m_flush_lock);
+ DEBUG_DETAIL("Executing FLUSH for O/p port\n");
+ DEBUG_DETAIL("WAITING FOR FLUSH ACK's param1=%d",param1);
+ post_output(OMX_CommandFlush,
+ OMX_CORE_OUTPUT_PORT_INDEX,OMX_COMPONENT_GENERATE_COMMAND);
+ if (ioctl( m_drv_fd, AUDIO_FLUSH, 0) ==-1)
+ DEBUG_PRINT_ERROR("Flush:Output port, ioctl flush failed %d\n",
+ errno);
+ DEBUG_DETAIL("****************************************");
+ DEBUG_DETAIL("is_in_th_sleep=%d is_out_th_sleep=%d\n",\
+ is_in_th_sleep,is_out_th_sleep);
+ DEBUG_DETAIL("****************************************");
+ if (is_in_th_sleep)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ is_in_th_sleep = false;
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+
+ if (is_out_th_sleep)
+ {
+ pthread_mutex_lock(&m_out_th_lock_1);
+ is_out_th_sleep = false;
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ DEBUG_DETAIL("For FLUSH-->WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+
+ // sleep till the FLUSH ACK are done by both the input and
+ // output threads
+ wait_for_event();
+ // Send FLUSH complete message to the Client,
+ // now that FLUSH ACK's have been recieved.
+ if (cmd_cmpl)
+ {
+ m_cb.EventHandler(&m_cmp, m_app_data, OMX_EventCmdComplete,
+ OMX_CommandFlush, OMX_CORE_OUTPUT_PORT_INDEX,
+ NULL );
+ }
+ DEBUG_DETAIL("RECIEVED FLUSH ACK FOR O/P PORT param1=%d",param1);
+ } else
+ {
+ DEBUG_PRINT("Invalid Port ID[%lu]",param1);
+ }
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_input_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_qcelp13_aenc::execute_input_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on input port");
+
+ pthread_mutex_lock(&m_lock);
+ do
+ {
+ qsize = m_input_q.m_size;
+ tot_qsize = qsize;
+ tot_qsize += m_input_ctrl_ebd_q.m_size;
+
+ DEBUG_DETAIL("Input FLUSH-->flushq[%d] ebd[%d]dataq[%d]",\
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,qsize);
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("Input-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_lock);
+ break;
+ }
+ if (qsize)
+ {
+ m_input_q.pop_entry(&p1, &p2, &ident);
+ if ((ident == OMX_COMPONENT_GENERATE_ETB) ||
+ (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Flush:Input dataq=0x%x \n", omx_buf);
+ omx_buf->nFilledLen = 0;
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else if (m_input_ctrl_ebd_q.m_size)
+ {
+ m_input_ctrl_ebd_q.pop_entry(&p1, &p2, &ident);
+ if (ident == OMX_COMPONENT_GENERATE_BUFFER_DONE)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ omx_buf->nFilledLen = 0;
+ DEBUG_DETAIL("Flush:ctrl dataq=0x%x \n", omx_buf);
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ }
+ } else
+ {
+ }
+ }while (tot_qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("IN-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_lock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ execute_output_omx_flush
+
+DESCRIPTION:
+ Function that flushes buffers that are pending to be written to driver
+
+INPUT/OUTPUT PARAMETERS:
+ None
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_qcelp13_aenc::execute_output_omx_flush()
+{
+ OMX_BUFFERHEADERTYPE *omx_buf;
+ unsigned p1; // Parameter - 1
+ unsigned p2; // Parameter - 2
+ unsigned ident;
+ unsigned qsize=0; // qsize
+ unsigned tot_qsize=0; // qsize
+
+ DEBUG_PRINT("Execute_omx_flush on output port");
+
+ pthread_mutex_lock(&m_outputlock);
+ do
+ {
+ qsize = m_output_q.m_size;
+ DEBUG_DETAIL("OUT FLUSH-->flushq[%d] fbd[%d]dataq[%d]",\
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,qsize);
+ tot_qsize = qsize;
+ tot_qsize += m_output_ctrl_fbd_q.m_size;
+ if (!tot_qsize)
+ {
+ DEBUG_DETAIL("OUT-->BREAKING FROM execute_input_flush LOOP");
+ pthread_mutex_unlock(&m_outputlock);
+ break;
+ }
+ if (qsize)
+ {
+ m_output_q.pop_entry(&p1,&p2,&ident);
+ if ( (OMX_COMPONENT_GENERATE_FTB == ident) ||
+ (OMX_COMPONENT_GENERATE_FRAME_DONE == ident))
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n",\
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FBD FROM FLUSH");
+ }
+ } else if ((qsize = m_output_ctrl_fbd_q.m_size))
+ {
+ m_output_ctrl_fbd_q.pop_entry(&p1, &p2, &ident);
+ if (OMX_COMPONENT_GENERATE_FRAME_DONE == ident)
+ {
+ omx_buf = (OMX_BUFFERHEADERTYPE *) p2;
+ DEBUG_DETAIL("Ouput Buf_Addr=%x TS[0x%x] \n", \
+ omx_buf,nTimestamp);
+ omx_buf->nTimeStamp = nTimestamp;
+ omx_buf->nFilledLen = 0;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)omx_buf);
+ DEBUG_DETAIL("CALLING FROM CTRL-FBDQ FROM FLUSH");
+ }
+ }
+ }while (qsize>0);
+ DEBUG_DETAIL("*************************\n");
+ DEBUG_DETAIL("OUT-->FLUSHING DONE\n");
+ DEBUG_DETAIL("*************************\n");
+ flush_ack();
+ pthread_mutex_unlock(&m_outputlock);
+ return true;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_input
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_qcelp13_aenc::post_input(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+ pthread_mutex_lock(&m_lock);
+
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND))
+ {
+ // insert flush message and ebd
+ m_input_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ((OMX_COMPONENT_GENERATE_BUFFER_DONE == id))
+ {
+ // insert ebd
+ m_input_ctrl_ebd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ // ETBS in this queue
+ m_input_q.insert_entry(p1,p2,id);
+ }
+
+ if (m_ipc_to_in_th)
+ {
+ bRet = true;
+ omx_qcelp13_post_msg(m_ipc_to_in_th, id);
+ }
+
+ DEBUG_DETAIL("PostInput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d] \n",\
+ m_state,
+ id,
+ m_input_ctrl_cmd_q.m_size,
+ m_input_ctrl_ebd_q.m_size,
+ m_input_q.m_size);
+
+ pthread_mutex_unlock(&m_lock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_command
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_qcelp13_aenc::post_command(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_commandlock);
+
+ m_command_q.insert_entry(p1,p2,id);
+
+ if (m_ipc_to_cmd_th)
+ {
+ bRet = true;
+ omx_qcelp13_post_msg(m_ipc_to_cmd_th, id);
+ }
+
+ DEBUG_DETAIL("PostCmd-->state[%d]id[%d]cmdq[%d]flags[%x]\n",\
+ m_state,
+ id,
+ m_command_q.m_size,
+ m_flags >> 3);
+
+ pthread_mutex_unlock(&m_commandlock);
+ return bRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ post_output
+
+DESCRIPTION:
+ Function that posts command in the command queue
+
+INPUT/OUTPUT PARAMETERS:
+ [IN] p1
+ [IN] p2
+ [IN] id - command ID
+ [IN] lock - self-locking mode
+
+RETURN VALUE:
+ true
+ false
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+bool omx_qcelp13_aenc::post_output(unsigned int p1,
+ unsigned int p2,
+ unsigned int id)
+{
+ bool bRet = false;
+
+ pthread_mutex_lock(&m_outputlock);
+ if((OMX_COMPONENT_GENERATE_COMMAND == id) || (id == OMX_COMPONENT_SUSPEND)
+ || (id == OMX_COMPONENT_RESUME))
+ {
+ // insert flush message and fbd
+ m_output_ctrl_cmd_q.insert_entry(p1,p2,id);
+ } else if ( (OMX_COMPONENT_GENERATE_FRAME_DONE == id) )
+ {
+ // insert flush message and fbd
+ m_output_ctrl_fbd_q.insert_entry(p1,p2,id);
+ } else
+ {
+ m_output_q.insert_entry(p1,p2,id);
+ }
+ if ( m_ipc_to_out_th )
+ {
+ bRet = true;
+ omx_qcelp13_post_msg(m_ipc_to_out_th, id);
+ }
+ DEBUG_DETAIL("PostOutput-->state[%d]id[%d]flushq[%d]ebdq[%d]dataq[%d]\n",\
+ m_state,
+ id,
+ m_output_ctrl_cmd_q.m_size,
+ m_output_ctrl_fbd_q.m_size,
+ m_output_q.m_size);
+
+ pthread_mutex_unlock(&m_outputlock);
+ return bRet;
+}
+/**
+ @brief member function that return parameters to IL client
+
+ @param hComp handle to component instance
+ @param paramIndex Parameter type
+ @param paramData pointer to memory space which would hold the
+ paramter
+ @return error status
+*/
+OMX_ERRORTYPE omx_qcelp13_aenc::get_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_INOUT OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Param in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("get_parameter: paramData is NULL\n");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ DEBUG_PRINT("OMX_IndexParamPortDefinition " \
+ "portDefn->nPortIndex = %lu\n",
+ portDefn->nPortIndex);
+
+ portDefn->nVersion.nVersion = OMX_SPEC_VERSION;
+ portDefn->nSize = sizeof(portDefn);
+ portDefn->eDomain = OMX_PortDomainAudio;
+
+ if (0 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirInput;
+ portDefn->bEnabled = m_inp_bEnabled;
+ portDefn->bPopulated = m_inp_bPopulated;
+ portDefn->nBufferCountActual = m_inp_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_INPUT_BUFFERS;
+ portDefn->nBufferSize = input_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+ portDefn->format.audio.pNativeRender = 0;
+ } else if (1 == portDefn->nPortIndex)
+ {
+ portDefn->eDir = OMX_DirOutput;
+ portDefn->bEnabled = m_out_bEnabled;
+ portDefn->bPopulated = m_out_bPopulated;
+ portDefn->nBufferCountActual = m_out_act_buf_count;
+ portDefn->nBufferCountMin = OMX_CORE_NUM_OUTPUT_BUFFERS;
+ portDefn->nBufferSize = output_buffer_size;
+ portDefn->format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDefn->format.audio.eEncoding = OMX_AUDIO_CodingQCELP13;
+ portDefn->format.audio.pNativeRender = 0;
+ } else
+ {
+ portDefn->eDir = OMX_DirMax;
+ DEBUG_PRINT_ERROR("Bad Port idx %d\n",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioInit\n");
+
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 2;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioPortFormat\n");
+ portFormatType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portFormatType->nSize = sizeof(portFormatType);
+
+ if (OMX_CORE_INPUT_PORT_INDEX == portFormatType->nPortIndex)
+ {
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("get_parameter: OMX_IndexParamAudioFormat: "\
+ "%lu\n", portFormatType->nIndex);
+
+ portFormatType->eEncoding = OMX_AUDIO_CodingQCELP13;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n",
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ case OMX_IndexParamAudioQcelp13:
+ {
+ OMX_AUDIO_PARAM_QCELP13TYPE *qcelp13Param =
+ (OMX_AUDIO_PARAM_QCELP13TYPE *) paramData;
+ DEBUG_PRINT("OMX_IndexParamAudioQcelp13\n");
+ if (OMX_CORE_OUTPUT_PORT_INDEX== qcelp13Param->nPortIndex)
+ {
+ memcpy(qcelp13Param,&m_qcelp13_param,
+ sizeof(OMX_AUDIO_PARAM_QCELP13TYPE));
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:\
+ OMX_IndexParamAudioQcelp13 \
+ OMX_ErrorBadPortIndex %d\n", \
+ (int)qcelp13Param->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case QOMX_IndexParamAudioSessionId:
+ {
+ QOMX_AUDIO_STREAM_INFO_DATA *streaminfoparam =
+ (QOMX_AUDIO_STREAM_INFO_DATA *) paramData;
+ streaminfoparam->sessionId = m_session_id;
+ break;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(pcmparam,&m_pcm_param,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+ DEBUG_PRINT("get_parameter: Sampling rate %lu",\
+ pcmparam->nSamplingRate);
+ DEBUG_PRINT("get_parameter: Number of channels %lu",\
+ pcmparam->nChannels);
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:OMX_IndexParamAudioPcm "\
+ "OMX_ErrorBadPortIndex %d\n", \
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamComponentSuspended:
+ {
+ OMX_PARAM_SUSPENSIONTYPE *suspend =
+ (OMX_PARAM_SUSPENSIONTYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamComponentSuspended %p\n",
+ suspend);
+ break;
+ }
+ case OMX_IndexParamVideoInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamVideoInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ OMX_PRIORITYMGMTTYPE *priorityMgmtType =
+ (OMX_PRIORITYMGMTTYPE*)paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamPriorityMgmt\n");
+ priorityMgmtType->nSize = sizeof(priorityMgmtType);
+ priorityMgmtType->nVersion.nVersion = OMX_SPEC_VERSION;
+ priorityMgmtType->nGroupID = m_priority_mgm.nGroupID;
+ priorityMgmtType->nGroupPriority =
+ m_priority_mgm.nGroupPriority;
+ break;
+ }
+ case OMX_IndexParamImageInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamImageInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("get_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+
+ bufferSupplierType->nSize = sizeof(bufferSupplierType);
+ bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION;
+ if (OMX_CORE_INPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ bufferSupplierType->nPortIndex)
+ {
+ bufferSupplierType->nPortIndex =
+ OMX_BufferSupplyUnspecified;
+ } else
+ {
+ DEBUG_PRINT_ERROR("get_parameter:"\
+ "OMX_IndexParamCompBufferSupplier eRet"\
+ "%08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+ /*Component should support this port definition*/
+ case OMX_IndexParamOtherInit:
+ {
+ OMX_PORT_PARAM_TYPE *portParamType =
+ (OMX_PORT_PARAM_TYPE *) paramData;
+ DEBUG_PRINT("get_parameter: OMX_IndexParamOtherInit\n");
+ portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
+ portParamType->nSize = sizeof(portParamType);
+ portParamType->nPorts = 0;
+ portParamType->nStartPortNumber = 0;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ componentRole->nSize = component_Role.nSize;
+ componentRole->nVersion = component_Role.nVersion;
+ strlcpy((char *)componentRole->cRole,
+ (const char*)component_Role.cRole,
+ sizeof(componentRole->cRole));
+ DEBUG_PRINT_ERROR("nSize = %d , nVersion = %d, cRole = %s\n",
+ component_Role.nSize,
+ component_Role.nVersion,
+ component_Role.cRole);
+ break;
+
+ }
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %08x\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+
+}
+
+/**
+ @brief member function that set paramter from IL client
+
+ @param hComp handle to component instance
+ @param paramIndex parameter type
+ @param paramData pointer to memory space which holds the paramter
+ @return error status
+ */
+OMX_ERRORTYPE omx_qcelp13_aenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE paramIndex,
+ OMX_IN OMX_PTR paramData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("set_parameter is not in proper state\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (paramData == NULL)
+ {
+ DEBUG_PRINT("param data is NULL");
+ return OMX_ErrorBadParameter;
+ }
+
+ switch (paramIndex)
+ {
+ case OMX_IndexParamAudioQcelp13:
+ {
+ DEBUG_PRINT("OMX_IndexParamAudioQcelp13");
+ OMX_AUDIO_PARAM_QCELP13TYPE *qcelp13param
+ = (OMX_AUDIO_PARAM_QCELP13TYPE *) paramData;
+ memcpy(&m_qcelp13_param,qcelp13param,
+ sizeof(OMX_AUDIO_PARAM_QCELP13TYPE));
+ break;
+ }
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
+ portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
+
+ if (((m_state == OMX_StateLoaded)&&
+ !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ || (m_state == OMX_StateWaitForResources &&
+ ((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == true)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == true)))
+ ||(((OMX_DirInput == portDefn->eDir &&
+ m_inp_bEnabled == false)||
+ (OMX_DirInput == portDefn->eDir &&
+ m_out_bEnabled == false)) &&
+ (m_state != OMX_StateWaitForResources)))
+ {
+ DEBUG_PRINT("Set Parameter called in valid state\n");
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ DEBUG_PRINT("OMX_IndexParamPortDefinition portDefn->nPortIndex "
+ "= %lu\n",portDefn->nPortIndex);
+ if (OMX_CORE_INPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_INPUT_BUFFERS )
+ {
+ m_inp_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_inp_act_buf_count =OMX_CORE_NUM_INPUT_BUFFERS;
+ }
+ input_buffer_size = portDefn->nBufferSize;
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == portDefn->nPortIndex)
+ {
+ if ( portDefn->nBufferCountActual >
+ OMX_CORE_NUM_OUTPUT_BUFFERS )
+ {
+ m_out_act_buf_count = portDefn->nBufferCountActual;
+ } else
+ {
+ m_out_act_buf_count =OMX_CORE_NUM_OUTPUT_BUFFERS;
+ }
+ output_buffer_size = portDefn->nBufferSize;
+ } else
+ {
+ DEBUG_PRINT(" set_parameter: Bad Port idx %d",\
+ (int)portDefn->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamPriorityMgmt:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt\n");
+
+ if (m_state != OMX_StateLoaded)
+ {
+ DEBUG_PRINT_ERROR("Set Parameter called in \
+ Invalid State\n");
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ OMX_PRIORITYMGMTTYPE *priorityMgmtype
+ = (OMX_PRIORITYMGMTTYPE*) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamPriorityMgmt %lu\n",
+ priorityMgmtype->nGroupID);
+
+ DEBUG_PRINT("set_parameter: priorityMgmtype %lu\n",
+ priorityMgmtype->nGroupPriority);
+
+ m_priority_mgm.nGroupID = priorityMgmtype->nGroupID;
+ m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority;
+
+ break;
+ }
+ case OMX_IndexParamAudioPortFormat:
+ {
+
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *portFormatType =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *) paramData;
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPortFormat\n");
+
+ if (OMX_CORE_INPUT_PORT_INDEX== portFormatType->nPortIndex)
+ {
+ portFormatType->eEncoding = OMX_AUDIO_CodingPCM;
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX ==
+ portFormatType->nPortIndex)
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioFormat:"\
+ " %lu\n", portFormatType->nIndex);
+ portFormatType->eEncoding = OMX_AUDIO_CodingQCELP13;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_parameter: Bad port index %d\n", \
+ (int)portFormatType->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+
+
+ case OMX_IndexParamCompBufferSupplier:
+ {
+ DEBUG_PRINT("set_parameter: \
+ OMX_IndexParamCompBufferSupplier\n");
+ OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType
+ = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
+ DEBUG_PRINT("set_param: OMX_IndexParamCompBufferSupplier %d",\
+ bufferSupplierType->eBufferSupplier);
+
+ if (bufferSupplierType->nPortIndex == OMX_CORE_INPUT_PORT_INDEX
+ || bufferSupplierType->nPortIndex ==
+ OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ DEBUG_PRINT("set_parameter:\
+ OMX_IndexParamCompBufferSupplier\n");
+ m_buffer_supplier.eBufferSupplier =
+ bufferSupplierType->eBufferSupplier;
+ } else
+ {
+ DEBUG_PRINT_ERROR("set_param:\
+ IndexParamCompBufferSup %08x\n", eRet);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ break; }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ DEBUG_PRINT("set_parameter: OMX_IndexParamAudioPcm\n");
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmparam
+ = (OMX_AUDIO_PARAM_PCMMODETYPE *) paramData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX== pcmparam->nPortIndex)
+ {
+ memcpy(&m_pcm_param,pcmparam,\
+ sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+ DEBUG_PRINT("set_pcm_parameter: %lu %lu",\
+ m_pcm_param.nChannels,
+ m_pcm_param.nSamplingRate);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Set_parameter:OMX_IndexParamAudioPcm "
+ "OMX_ErrorBadPortIndex %d\n",
+ (int)pcmparam->nPortIndex);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ break;
+ }
+ case OMX_IndexParamSuspensionPolicy:
+ {
+ eRet = OMX_ErrorNotImplemented;
+ break;
+ }
+ case OMX_IndexParamStandardComponentRole:
+ {
+ OMX_PARAM_COMPONENTROLETYPE *componentRole;
+ componentRole = (OMX_PARAM_COMPONENTROLETYPE*)paramData;
+ component_Role.nSize = componentRole->nSize;
+ component_Role.nVersion = componentRole->nVersion;
+ strlcpy((char *)component_Role.cRole,
+ (const char*)componentRole->cRole,
+ sizeof(component_Role.cRole));
+ break;
+ }
+
+ default:
+ {
+ DEBUG_PRINT_ERROR("unknown param %d\n", paramIndex);
+ eRet = OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::GetConfig
+
+DESCRIPTION
+ OMX Get Config Method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::get_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_INOUT OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *volume =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == volume->nPortIndex)
+ {
+ volume->nSize = sizeof(volume);
+ volume->nVersion.nVersion = OMX_SPEC_VERSION;
+ volume->bLinear = OMX_TRUE;
+ volume->sVolume.nValue = m_volume;
+ volume->sVolume.nMax = OMX_AENC_MAX;
+ volume->sVolume.nMin = OMX_AENC_MIN;
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute =
+ (OMX_AUDIO_CONFIG_MUTETYPE*) configData;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == mute->nPortIndex)
+ {
+ mute->nSize = sizeof(mute);
+ mute->nVersion.nVersion = OMX_SPEC_VERSION;
+ mute->bMute = (BITMASK_PRESENT(&m_flags,
+ OMX_COMPONENT_MUTED)?OMX_TRUE:OMX_FALSE);
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::SetConfig
+
+DESCRIPTION
+ OMX Set Config method implementation
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if successful.
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::set_config(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_INDEXTYPE configIndex,
+ OMX_IN OMX_PTR configData)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Set Config in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if ( m_state == OMX_StateExecuting)
+ {
+ DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n");
+ return OMX_ErrorInvalidState;
+ }
+
+ switch (configIndex)
+ {
+ case OMX_IndexConfigAudioVolume:
+ {
+ OMX_AUDIO_CONFIG_VOLUMETYPE *vol =
+ (OMX_AUDIO_CONFIG_VOLUMETYPE*)configData;
+ if (vol->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if ((vol->sVolume.nValue <= OMX_AENC_MAX) &&
+ (vol->sVolume.nValue >= OMX_AENC_MIN))
+ {
+ m_volume = vol->sVolume.nValue;
+ if (BITMASK_ABSENT(&m_flags, OMX_COMPONENT_MUTED))
+ {
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+
+ } else
+ {
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ case OMX_IndexConfigAudioMute:
+ {
+ OMX_AUDIO_CONFIG_MUTETYPE *mute = (OMX_AUDIO_CONFIG_MUTETYPE*)
+ configData;
+ if (mute->nPortIndex == OMX_CORE_INPUT_PORT_INDEX)
+ {
+ if (mute->bMute == OMX_TRUE)
+ {
+ BITMASK_SET(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME, 0); */
+ } else
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_MUTED);
+ /* ioctl(m_drv_fd, AUDIO_VOLUME,
+ m_volume * OMX_AENC_VOLUME_STEP); */
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ }
+ break;
+
+ default:
+ eRet = OMX_ErrorUnsupportedIndex;
+ break;
+ }
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::GetExtensionIndex
+
+DESCRIPTION
+ OMX GetExtensionIndex method implementaion. <TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::get_extension_index(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_STRING paramName,
+ OMX_OUT OMX_INDEXTYPE* indexType)
+{
+ if((hComp == NULL) || (paramName == NULL) || (indexType == NULL))
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if(strncmp(paramName,"OMX.Qualcomm.index.audio.sessionId",
+ strlen("OMX.Qualcomm.index.audio.sessionId")) == 0)
+ {
+ *indexType =(OMX_INDEXTYPE)QOMX_IndexParamAudioSessionId;
+ DEBUG_PRINT("Extension index type - %d\n", *indexType);
+
+ }
+ else
+ {
+ return OMX_ErrorBadParameter;
+
+ }
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::GetState
+
+DESCRIPTION
+ Returns the state information back to the caller.<TBD>
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::get_state(OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_STATETYPE* state)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ *state = m_state;
+ DEBUG_PRINT("Returning the state %d\n",*state);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::ComponentTunnelRequest
+
+DESCRIPTION
+ OMX Component Tunnel Request method implementation. <TBD>
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::component_tunnel_request
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_HANDLETYPE peerComponent,
+ OMX_IN OMX_U32 peerPort,
+ OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup)
+{
+ DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n");
+
+ if((hComp == NULL) || (peerComponent == NULL) || (tunnelSetup == NULL))
+ {
+ port = 0;
+ peerPort = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::AllocateInputBuffer
+
+DESCRIPTION
+ Helper function for allocate buffer in the input pin
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::allocate_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+ if(m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc((nBufSize + \
+ sizeof(OMX_BUFFERHEADERTYPE)+sizeof(META_IN)) , 1);
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ free(buf_ptr);
+ return OMX_ErrorBadParameter;
+ }
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) + sizeof(META_IN)+
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+
+ m_inp_current_buf_count++;
+ DEBUG_PRINT("AIB:bufHdr %p bufHdr->pBuffer %p m_inp_buf_cnt=%d \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,m_inp_current_buf_count,
+ bytes);
+
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ }
+ else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+OMX_ERRORTYPE omx_qcelp13_aenc::allocate_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+ buf_ptr = (char *) calloc( (nBufSize + sizeof(OMX_BUFFERHEADERTYPE)),1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)((buf_ptr) +
+ sizeof(OMX_BUFFERHEADERTYPE));
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+ DEBUG_PRINT("AOB::bufHdr %p bufHdr->pBuffer %p m_out_buf_cnt=%d "\
+ "bytes=%lu",bufHdr, bufHdr->pBuffer,\
+ m_out_current_buf_count, bytes);
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+
+// AllocateBuffer -- API Call
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::AllocateBuffer
+
+DESCRIPTION
+ Returns zero if all the buffers released..
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::allocate_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes)
+{
+
+ OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type
+
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ // What if the client calls again.
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",
+ (int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("allocate_buffer: before allocate_done \n");
+ if (allocate_done())
+ {
+ DEBUG_PRINT("allocate_buffer: after allocate_done \n");
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("allocate_buffer: post idle transition event \n");
+ }
+ DEBUG_PRINT("allocate_buffer: complete \n");
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ m_out_bEnabled = OMX_TRUE;
+
+ DEBUG_PRINT("AllocBuf-->is_out_th_sleep=%d\n",is_out_th_sleep);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("AllocBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("AB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ }
+ DEBUG_PRINT("Allocate Buffer exit with ret Code %d\n", eRet);
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_buffer
+
+DESCRIPTION:
+ OMX Use Buffer method implementation.
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_qcelp13_aenc::use_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port);
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (eRet == OMX_ErrorNone)
+ {
+ DEBUG_PRINT("Checking for Output Allocate buffer Done");
+ if (allocate_done())
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
+ {
+ BITMASK_CLEAR(&m_flags, OMX_COMPONENT_IDLE_PENDING);
+ post_command(OMX_CommandStateSet,OMX_StateIdle,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ }
+ if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ }
+ if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
+ {
+ if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
+ {
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
+ post_command(OMX_CommandPortEnable, OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("UseBuf:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if(is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("UB:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ }
+ }
+ DEBUG_PRINT("Use Buffer for port[%lu] eRet[%d]\n", port,eRet);
+ return eRet;
+}
+/*=============================================================================
+FUNCTION:
+ use_input_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the input pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_qcelp13_aenc::use_input_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes, input_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if(bytes < input_buffer_size)
+ {
+ /* return if i\p buffer size provided by client
+ is less than min i\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+ if (m_inp_current_buf_count < m_inp_act_buf_count)
+ {
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_input_buffer:bufHdr %p bufHdr->pBuffer %p \
+ bytes=%lu", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ input_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_input_buf_hdrs.insert(bufHdr, NULL);
+ m_inp_current_buf_count++;
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed 1 \n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Input buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+
+/*=============================================================================
+FUNCTION:
+ use_output_buffer
+
+DESCRIPTION:
+ Helper function for Use buffer in the output pin
+
+INPUT/OUTPUT PARAMETERS:
+ [INOUT] bufferHdr
+ [IN] hComp
+ [IN] port
+ [IN] appData
+ [IN] bytes
+ [IN] buffer
+
+RETURN VALUE:
+ OMX_ERRORTYPE
+
+Dependency:
+ None
+
+SIDE EFFECTS:
+ None
+=============================================================================*/
+OMX_ERRORTYPE omx_qcelp13_aenc::use_output_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN OMX_U32 bytes,
+ OMX_IN OMX_U8* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ OMX_BUFFERHEADERTYPE *bufHdr;
+ unsigned nBufSize = MAX(bytes,output_buffer_size);
+ char *buf_ptr;
+
+ if(hComp == NULL)
+ {
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (bytes < output_buffer_size)
+ {
+ /* return if o\p buffer size provided by client
+ is less than min o\p buffer size supported by omx component*/
+ return OMX_ErrorInsufficientResources;
+ }
+
+ DEBUG_PRINT("Inside omx_qcelp13_aenc::use_output_buffer");
+ if (m_out_current_buf_count < m_out_act_buf_count)
+ {
+
+ buf_ptr = (char *) calloc(sizeof(OMX_BUFFERHEADERTYPE), 1);
+
+ if (buf_ptr != NULL)
+ {
+ bufHdr = (OMX_BUFFERHEADERTYPE *) buf_ptr;
+ DEBUG_PRINT("BufHdr=%p buffer=%p\n",bufHdr,buffer);
+ *bufferHdr = bufHdr;
+ memset(bufHdr,0,sizeof(OMX_BUFFERHEADERTYPE));
+
+ bufHdr->pBuffer = (OMX_U8 *)(buffer);
+ DEBUG_PRINT("use_output_buffer:bufHdr %p bufHdr->pBuffer %p \
+ len=%lu\n", bufHdr, bufHdr->pBuffer,bytes);
+ bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
+ bufHdr->nAllocLen = nBufSize;
+ output_buffer_size = nBufSize;
+ bufHdr->pAppPrivate = appData;
+ bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
+ bufHdr->nOffset = 0;
+ m_output_buf_hdrs.insert(bufHdr, NULL);
+ m_out_current_buf_count++;
+
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ } else
+ {
+ DEBUG_PRINT("Output buffer memory allocation failed 2\n");
+ eRet = OMX_ErrorInsufficientResources;
+ }
+ return eRet;
+}
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_qcelp13_aenc::search_input_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_input_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_input_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+/**
+ @brief member function that searches for caller buffer
+
+ @param buffer pointer to buffer header
+ @return bool value indicating whether buffer is found
+ */
+bool omx_qcelp13_aenc::search_output_bufhdr(OMX_BUFFERHEADERTYPE *buffer)
+{
+
+ bool eRet = false;
+ OMX_BUFFERHEADERTYPE *temp = NULL;
+
+ //access only in IL client context
+ temp = m_output_buf_hdrs.find_ele(buffer);
+ if (buffer && temp)
+ {
+ DEBUG_DETAIL("search_output_bufhdr %x \n", buffer);
+ eRet = true;
+ }
+ return eRet;
+}
+
+// Free Buffer - API call
+/**
+ @brief member function that handles free buffer command from IL client
+
+ This function is a block-call function that handles IL client request to
+ freeing the buffer
+
+ @param hComp handle to component instance
+ @param port id of port which holds the buffer
+ @param buffer buffer header
+ @return Error status
+*/
+OMX_ERRORTYPE omx_qcelp13_aenc::free_buffer(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("Free_Buffer buf %p\n", buffer);
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_state == OMX_StateIdle &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ DEBUG_PRINT(" free buffer while Component in Loading pending\n");
+ } else if ((m_inp_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_INPUT_PORT_INDEX)||
+ (m_out_bEnabled == OMX_FALSE &&
+ port == OMX_CORE_OUTPUT_PORT_INDEX))
+ {
+ DEBUG_PRINT("Free Buffer while port %lu disabled\n", port);
+ } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause)
+ {
+ DEBUG_PRINT("Invalid state to free buffer,ports need to be disabled:\
+ OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ return eRet;
+ } else
+ {
+ DEBUG_PRINT("free_buffer: Invalid state to free buffer,ports need to be\
+ disabled:OMX_ErrorPortUnpopulated\n");
+ post_command(OMX_EventError,
+ OMX_ErrorPortUnpopulated,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ if (OMX_CORE_INPUT_PORT_INDEX == port)
+ {
+ if (m_inp_current_buf_count != 0)
+ {
+ m_inp_bPopulated = OMX_FALSE;
+ if (true == search_input_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:in_buffer[%p]\n",buffer);
+ m_input_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_inp_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT_ERROR("Free_Buf:Error-->free_buffer, \
+ Invalid Input buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ DEBUG_PRINT_ERROR("Error: free_buffer,Port Index calculation \
+ came out Invalid\n");
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING)
+ && release_done(0))
+ {
+ DEBUG_PRINT("INPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_INPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+ }
+ } else if (OMX_CORE_OUTPUT_PORT_INDEX == port)
+ {
+ if (m_out_current_buf_count != 0)
+ {
+ m_out_bPopulated = OMX_FALSE;
+ if (true == search_output_bufhdr(buffer))
+ {
+ /* Buffer exist */
+ //access only in IL client context
+ DEBUG_PRINT("Free_Buf:out_buffer[%p]\n",buffer);
+ m_output_buf_hdrs.erase(buffer);
+ free(buffer);
+ m_out_current_buf_count--;
+ } else
+ {
+ DEBUG_PRINT("Free_Buf:Error-->free_buffer , \
+ Invalid Output buffer header\n");
+ eRet = OMX_ErrorBadParameter;
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+
+ if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING)
+ && release_done(1))
+ {
+ DEBUG_PRINT("OUTPUT PORT MOVING TO DISABLED STATE \n");
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
+ post_command(OMX_CommandPortDisable,
+ OMX_CORE_OUTPUT_PORT_INDEX,
+ OMX_COMPONENT_GENERATE_EVENT);
+
+ }
+ } else
+ {
+ eRet = OMX_ErrorBadPortIndex;
+ }
+ if ((OMX_ErrorNone == eRet) &&
+ (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
+ {
+ if (release_done(-1))
+ {
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) < 0)
+ DEBUG_PRINT_ERROR("AUDIO STOP in free buffer failed\n");
+ else
+ DEBUG_PRINT("AUDIO STOP in free buffer passed\n");
+
+
+ DEBUG_PRINT("Free_Buf: Free buffer\n");
+
+
+ // Send the callback now
+ BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING);
+ DEBUG_PRINT("Before OMX_StateLoaded \
+ OMX_COMPONENT_GENERATE_EVENT\n");
+ post_command(OMX_CommandStateSet,
+ OMX_StateLoaded,OMX_COMPONENT_GENERATE_EVENT);
+ DEBUG_PRINT("After OMX_StateLoaded OMX_COMPONENT_GENERATE_EVENT\n");
+
+ }
+ }
+ return eRet;
+}
+
+
+/**
+ @brief member function that that handles empty this buffer command
+
+ This function meremly queue up the command and data would be consumed
+ in command server thread context
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_qcelp13_aenc::empty_this_buffer(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+
+ DEBUG_PRINT("ETB:Buf:%p Len %lu TS %lld numInBuf=%d\n", \
+ buffer, buffer->nFilledLen, buffer->nTimeStamp, (nNumInputBuf));
+ if (m_state == OMX_StateInvalid)
+ {
+ DEBUG_PRINT("Empty this buffer in Invalid State\n");
+ return OMX_ErrorInvalidState;
+ }
+ if (!m_inp_bEnabled)
+ {
+ DEBUG_PRINT("empty_this_buffer OMX_ErrorIncorrectStateOperation "\
+ "Port Status %d \n", m_inp_bEnabled);
+ return OMX_ErrorIncorrectStateOperation;
+ }
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_qcelp13_aenc::etb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_qcelp13_aenc::etb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+
+ if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ if ((m_state != OMX_StateExecuting) &&
+ (m_state != OMX_StatePause))
+ {
+ DEBUG_PRINT_ERROR("Invalid state\n");
+ eRet = OMX_ErrorInvalidState;
+ }
+ if (OMX_ErrorNone == eRet)
+ {
+ if (search_input_bufhdr(buffer) == true)
+ {
+ post_input((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_ETB);
+ } else
+ {
+ DEBUG_PRINT_ERROR("Bad header %x \n", (int)buffer);
+ eRet = OMX_ErrorBadParameter;
+ }
+ }
+ pthread_mutex_lock(&in_buf_count_lock);
+ nNumInputBuf++;
+ m_qcelp13_pb_stats.etb_cnt++;
+ pthread_mutex_unlock(&in_buf_count_lock);
+ return eRet;
+}
+/**
+ @brief member function that writes data to kernel driver
+
+ @param hComp handle to component instance
+ @param buffer pointer to buffer header
+ @return error status
+ */
+OMX_ERRORTYPE omx_qcelp13_aenc::empty_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ META_IN meta_in;
+ //Pointer to the starting location of the data to be transcoded
+ OMX_U8 *srcStart;
+ //The total length of the data to be transcoded
+ srcStart = buffer->pBuffer;
+ OMX_U8 *data = NULL;
+ PrintFrameHdr(OMX_COMPONENT_GENERATE_ETB,buffer);
+ memset(&meta_in,0,sizeof(meta_in));
+ if ( search_input_bufhdr(buffer) == false )
+ {
+ DEBUG_PRINT("ETBP: INVALID BUF HDR\n");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorBadParameter;
+ }
+ if (m_tmp_meta_buf)
+ {
+ data = m_tmp_meta_buf;
+
+ // copy the metadata info from the BufHdr and insert to payload
+ meta_in.offsetVal = sizeof(META_IN);
+ meta_in.nTimeStamp.LowPart =
+ ((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp)& 0xFFFFFFFF);
+ meta_in.nTimeStamp.HighPart =
+ (((((OMX_BUFFERHEADERTYPE*)buffer)->nTimeStamp) >> 32) & 0xFFFFFFFF);
+ meta_in.nFlags &= ~OMX_BUFFERFLAG_EOS;
+ if(buffer->nFlags & OMX_BUFFERFLAG_EOS)
+ {
+ DEBUG_PRINT("EOS OCCURED \n");
+ meta_in.nFlags |= OMX_BUFFERFLAG_EOS;
+ }
+ memcpy(data,&meta_in, meta_in.offsetVal);
+ DEBUG_PRINT("meta_in.nFlags = 0x%8x\n",meta_in.nFlags);
+ }
+
+ memcpy(&data[sizeof(META_IN)],buffer->pBuffer,buffer->nFilledLen);
+ write(m_drv_fd, data, buffer->nFilledLen+sizeof(META_IN));
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (OMX_StateExecuting == state)
+ {
+ DEBUG_DETAIL("In Exe state, EBD CB");
+ buffer_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ } else
+ {
+ /* Assume empty this buffer function has already checked
+ validity of buffer */
+ DEBUG_PRINT("Empty buffer %p to kernel driver\n", buffer);
+ post_input((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_BUFFER_DONE);
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE omx_qcelp13_aenc::fill_this_buffer_proxy
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_STATETYPE state;
+ ENC_META_OUT *meta_out = NULL;
+ int nReadbytes = 0;
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (true == search_output_bufhdr(buffer))
+ {
+ DEBUG_PRINT("\nBefore Read..m_drv_fd = %d,\n",m_drv_fd);
+ nReadbytes = read(m_drv_fd,buffer->pBuffer,output_buffer_size );
+ DEBUG_DETAIL("FTBP->Al_len[%d]buf[%p]size[%d]numOutBuf[%d]\n",\
+ buffer->nAllocLen,buffer->pBuffer,
+ nReadbytes,nNumOutputBuf);
+ if (nReadbytes <= 0) {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ return OMX_ErrorNone;
+ } else
+ DEBUG_PRINT("Read bytes %d\n",nReadbytes);
+
+ // Buffer from Driver will have
+ // 1 byte => Nr of frame field
+ // (sizeof(ENC_META_OUT) * Nr of frame) bytes => meta_out->offset_to_frame
+ // Frame Size * Nr of frame =>
+
+ meta_out = (ENC_META_OUT *)(buffer->pBuffer + sizeof(unsigned char));
+ buffer->nTimeStamp = (((OMX_TICKS)meta_out->msw_ts << 32)+
+ meta_out->lsw_ts);
+ buffer->nFlags |= meta_out->nflags;
+ buffer->nOffset = meta_out->offset_to_frame + sizeof(unsigned char);
+ buffer->nFilledLen = nReadbytes - buffer->nOffset;
+ nTimestamp = buffer->nTimeStamp;
+ DEBUG_PRINT("nflags %d frame_size %d offset_to_frame %d \
+ timestamp %lld\n", meta_out->nflags,
+ meta_out->frame_size, meta_out->offset_to_frame,
+ buffer->nTimeStamp);
+
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->nTimeStamp = nTimestamp;
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+ if ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS )
+ {
+ DEBUG_PRINT("FTBP: Now, Send EOS flag to Client \n");
+ m_cb.EventHandler(&m_cmp,
+ m_app_data,
+ OMX_EventBufferFlag,
+ 1, 1, NULL );
+ }
+
+ return OMX_ErrorNone;
+ }
+ DEBUG_PRINT("nState %d \n",nState );
+
+ pthread_mutex_lock(&m_state_lock);
+ get_state(&m_cmp, &state);
+ pthread_mutex_unlock(&m_state_lock);
+
+ if (state == OMX_StatePause)
+ {
+ DEBUG_PRINT("FTBP:Post the FBD to event thread currstate=%d\n",\
+ state);
+ post_output((unsigned) & hComp,(unsigned) buffer,
+ OMX_COMPONENT_GENERATE_FRAME_DONE);
+ }
+ else
+ {
+ frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+
+ }
+
+ }
+ else
+ DEBUG_PRINT("\n FTBP-->Invalid buffer in FTB \n");
+
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::FillThisBuffer
+
+DESCRIPTION
+ IL client uses this method to release the frame buffer
+ after displaying them.
+
+
+
+PARAMETERS
+
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::fill_this_buffer
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_BUFFERHEADERTYPE* buffer)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ if (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+ {
+ DEBUG_PRINT("omx_qcelp13_aenc::ftb--> Buffer Size Invalid\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (m_out_bEnabled == OMX_FALSE)
+ {
+ return OMX_ErrorIncorrectStateOperation;
+ }
+
+ if (buffer->nVersion.nVersion != OMX_SPEC_VERSION)
+ {
+ DEBUG_PRINT("omx_qcelp13_aenc::ftb--> OMX Version Invalid\n");
+ return OMX_ErrorVersionMismatch;
+ }
+ if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ return OMX_ErrorBadPortIndex;
+ }
+ pthread_mutex_lock(&out_buf_count_lock);
+ nNumOutputBuf++;
+ m_qcelp13_pb_stats.ftb_cnt++;
+ DEBUG_DETAIL("FTB:nNumOutputBuf is %d", nNumOutputBuf);
+ pthread_mutex_unlock(&out_buf_count_lock);
+ post_output((unsigned)hComp,
+ (unsigned) buffer,OMX_COMPONENT_GENERATE_FTB);
+ return eRet;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::SetCallbacks
+
+DESCRIPTION
+ Set the callbacks.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::set_callbacks(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_IN OMX_CALLBACKTYPE* callbacks,
+ OMX_IN OMX_PTR appData)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ m_cb = *callbacks;
+ m_app_data = appData;
+
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::ComponentDeInit
+
+DESCRIPTION
+ Destroys the component and release memory allocated to the heap.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything successful.
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp)
+{
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (OMX_StateLoaded != m_state && OMX_StateInvalid != m_state)
+ {
+ DEBUG_PRINT_ERROR("Warning: Rxed DeInit when not in LOADED state %d\n",
+ m_state);
+ }
+ deinit_encoder();
+
+DEBUG_PRINT_ERROR("%s:COMPONENT DEINIT...\n", __FUNCTION__);
+ return OMX_ErrorNone;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::deinit_encoder
+
+DESCRIPTION
+ Closes all the threads and release memory allocated to the heap.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ None.
+
+========================================================================== */
+void omx_qcelp13_aenc::deinit_encoder()
+{
+ DEBUG_PRINT("Component-deinit being processed\n");
+ DEBUG_PRINT("********************************\n");
+ DEBUG_PRINT("STATS: in-buf-len[%lu]out-buf-len[%lu] tot-pb-time[%ld]",\
+ m_qcelp13_pb_stats.tot_in_buf_len,
+ m_qcelp13_pb_stats.tot_out_buf_len,
+ m_qcelp13_pb_stats.tot_pb_time);
+ DEBUG_PRINT("STATS: fbd-cnt[%lu]ftb-cnt[%lu]etb-cnt[%lu]ebd-cnt[%lu]",\
+ m_qcelp13_pb_stats.fbd_cnt,m_qcelp13_pb_stats.ftb_cnt,
+ m_qcelp13_pb_stats.etb_cnt,
+ m_qcelp13_pb_stats.ebd_cnt);
+ memset(&m_qcelp13_pb_stats,0,sizeof(QCELP13_PB_STATS));
+
+ if((OMX_StateLoaded != m_state) && (OMX_StateInvalid != m_state))
+ {
+ DEBUG_PRINT_ERROR("%s,Deinit called in state[%d]\n",__FUNCTION__,\
+ m_state);
+ // Get back any buffers from driver
+ if(pcm_input)
+ execute_omx_flush(-1,false);
+ else
+ execute_omx_flush(1,false);
+ // force state change to loaded so that all threads can be exited
+ pthread_mutex_lock(&m_state_lock);
+ m_state = OMX_StateLoaded;
+ pthread_mutex_unlock(&m_state_lock);
+ DEBUG_PRINT_ERROR("Freeing Buf:inp_current_buf_count[%d][%d]\n",\
+ m_inp_current_buf_count,
+ m_input_buf_hdrs.size());
+ m_input_buf_hdrs.eraseall();
+ DEBUG_PRINT_ERROR("Freeing Buf:out_current_buf_count[%d][%d]\n",\
+ m_out_current_buf_count,
+ m_output_buf_hdrs.size());
+ m_output_buf_hdrs.eraseall();
+
+ }
+ if(pcm_input)
+ {
+ pthread_mutex_lock(&m_in_th_lock_1);
+ if (is_in_th_sleep)
+ {
+ is_in_th_sleep = false;
+ DEBUG_DETAIL("Deinit:WAKING UP IN THREADS\n");
+ in_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_in_th_lock_1);
+ }
+ pthread_mutex_lock(&m_out_th_lock_1);
+ if (is_out_th_sleep)
+ {
+ is_out_th_sleep = false;
+ DEBUG_DETAIL("SCP:WAKING UP OUT THREADS\n");
+ out_th_wakeup();
+ }
+ pthread_mutex_unlock(&m_out_th_lock_1);
+ if(pcm_input)
+ {
+ if (m_ipc_to_in_th != NULL)
+ {
+ omx_qcelp13_thread_stop(m_ipc_to_in_th);
+ m_ipc_to_in_th = NULL;
+ }
+ }
+
+ if (m_ipc_to_cmd_th != NULL)
+ {
+ omx_qcelp13_thread_stop(m_ipc_to_cmd_th);
+ m_ipc_to_cmd_th = NULL;
+ }
+ if (m_ipc_to_out_th != NULL)
+ {
+ DEBUG_DETAIL("Inside omx_qcelp13_thread_stop\n");
+ omx_qcelp13_thread_stop(m_ipc_to_out_th);
+ m_ipc_to_out_th = NULL;
+ }
+
+
+ if(ioctl(m_drv_fd, AUDIO_STOP, 0) <0)
+ DEBUG_PRINT_ERROR("De-init: AUDIO_STOP FAILED\n");
+
+ if(pcm_input && m_tmp_meta_buf )
+ {
+ free(m_tmp_meta_buf);
+ }
+
+ if(m_tmp_out_meta_buf)
+ {
+ free(m_tmp_out_meta_buf);
+ }
+ nNumInputBuf = 0;
+ nNumOutputBuf = 0;
+ bFlushinprogress = 0;
+
+ m_inp_current_buf_count=0;
+ m_out_current_buf_count=0;
+ m_out_act_buf_count = 0;
+ m_inp_act_buf_count = 0;
+ m_inp_bEnabled = OMX_FALSE;
+ m_out_bEnabled = OMX_FALSE;
+ m_inp_bPopulated = OMX_FALSE;
+ m_out_bPopulated = OMX_FALSE;
+
+ if ( m_drv_fd >= 0 )
+ {
+ if(close(m_drv_fd) < 0)
+ DEBUG_PRINT("De-init: Driver Close Failed \n");
+ m_drv_fd = -1;
+ }
+ else
+ {
+ DEBUG_PRINT_ERROR(" QCELP13 device already closed\n");
+ }
+ m_comp_deinit=1;
+ m_is_out_th_sleep = 1;
+ m_is_in_th_sleep = 1;
+ DEBUG_PRINT("************************************\n");
+ DEBUG_PRINT(" DEINIT COMPLETED");
+ DEBUG_PRINT("************************************\n");
+
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::UseEGLImage
+
+DESCRIPTION
+ OMX Use EGL Image method implementation <TBD>.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ Not Implemented error.
+
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::use_EGL_image
+(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
+ OMX_IN OMX_U32 port,
+ OMX_IN OMX_PTR appData,
+ OMX_IN void* eglImage)
+{
+ DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n");
+
+ if((hComp == NULL) || (appData == NULL) || (eglImage == NULL))
+ {
+ bufferHdr = NULL;
+ port = 0;
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ return OMX_ErrorNotImplemented;
+}
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::ComponentRoleEnum
+
+DESCRIPTION
+ OMX Component Role Enum method implementation.
+
+PARAMETERS
+ <TBD>.
+
+RETURN VALUE
+ OMX Error None if everything is successful.
+========================================================================== */
+OMX_ERRORTYPE omx_qcelp13_aenc::component_role_enum(
+ OMX_IN OMX_HANDLETYPE hComp,
+ OMX_OUT OMX_U8* role,
+ OMX_IN OMX_U32 index)
+{
+ OMX_ERRORTYPE eRet = OMX_ErrorNone;
+ const char *cmp_role = "audio_encoder.qcelp13";
+
+ if(hComp == NULL)
+ {
+ DEBUG_PRINT_ERROR("Returning OMX_ErrorBadParameter\n");
+ return OMX_ErrorBadParameter;
+ }
+ if (index == 0 && role)
+ {
+ memcpy(role, cmp_role, sizeof(cmp_role));
+ *(((char *) role) + sizeof(cmp_role)) = '\0';
+ } else
+ {
+ eRet = OMX_ErrorNoMore;
+ }
+ return eRet;
+}
+
+
+
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::AllocateDone
+
+DESCRIPTION
+ Checks if entire buffer pool is allocated by IL Client or not.
+ Need this to move to IDLE state.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false.
+
+========================================================================== */
+bool omx_qcelp13_aenc::allocate_done(void)
+{
+ OMX_BOOL bRet = OMX_FALSE;
+ if (pcm_input==1)
+ {
+ if ((m_inp_act_buf_count == m_inp_current_buf_count)
+ &&(m_out_act_buf_count == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_inp_act_buf_count == m_inp_current_buf_count) && m_inp_bEnabled )
+ {
+ m_inp_bPopulated = OMX_TRUE;
+ }
+
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+ } else if (pcm_input==0)
+ {
+ if (m_out_act_buf_count == m_out_current_buf_count)
+ {
+ bRet=OMX_TRUE;
+
+ }
+ if ((m_out_act_buf_count == m_out_current_buf_count) && m_out_bEnabled )
+ {
+ m_out_bPopulated = OMX_TRUE;
+ }
+
+ }
+ return bRet;
+}
+
+
+/* ======================================================================
+FUNCTION
+ omx_qcelp13_aenc::ReleaseDone
+
+DESCRIPTION
+ Checks if IL client has released all the buffers.
+
+PARAMETERS
+ None.
+
+RETURN VALUE
+ true/false
+
+========================================================================== */
+bool omx_qcelp13_aenc::release_done(OMX_U32 param1)
+{
+ DEBUG_PRINT("Inside omx_qcelp13_aenc::release_done");
+ OMX_BOOL bRet = OMX_FALSE;
+
+ if (param1 == OMX_ALL)
+ {
+ if ((0 == m_inp_current_buf_count)&&(0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_INPUT_PORT_INDEX )
+ {
+ if ((0 == m_inp_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ } else if (param1 == OMX_CORE_OUTPUT_PORT_INDEX)
+ {
+ if ((0 == m_out_current_buf_count))
+ {
+ bRet=OMX_TRUE;
+ }
+ }
+ return bRet;
+}
diff --git a/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c b/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c
new file mode 100644
index 0000000..5c59349
--- /dev/null
+++ b/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c
@@ -0,0 +1,1097 @@
+
+/*--------------------------------------------------------------------------
+Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of The Linux Foundation nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--------------------------------------------------------------------------*/
+
+
+/*
+ An Open max test application ....
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "OMX_Core.h"
+#include "OMX_Component.h"
+#include "pthread.h"
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include<unistd.h>
+#include<string.h>
+#include <pthread.h>
+#include "QOMX_AudioExtensions.h"
+#include "QOMX_AudioIndexExtensions.h"
+#ifdef AUDIOV2
+#include "control.h"
+#endif
+
+
+#include <linux/ioctl.h>
+
+typedef unsigned char uint8;
+typedef unsigned char byte;
+typedef unsigned int uint32;
+typedef unsigned int uint16;
+QOMX_AUDIO_STREAM_INFO_DATA streaminfoparam;
+/* maximum ADTS frame header length */
+void Release_Encoder();
+
+#ifdef AUDIOV2
+unsigned short session_id;
+int device_id;
+int control = 0;
+const char *device="handset_tx";
+#define DIR_TX 2
+#endif
+
+uint32_t samplerate = 8000;
+uint32_t channels = 1;
+uint32_t min_bitrate = 0;
+uint32_t max_bitrate = 0;
+uint32_t cdmarate = 0;
+uint32_t rectime = -1;
+uint32_t recpath = -1;
+uint32_t pcmplayback = 0;
+uint32_t tunnel = 0;
+uint32_t format = 1;
+#define DEBUG_PRINT printf
+unsigned to_idle_transition = 0;
+unsigned long total_pcm_bytes;
+
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+/************************************************************************/
+/* #DEFINES */
+/************************************************************************/
+#define false 0
+#define true 1
+
+#define CONFIG_VERSION_SIZE(param) \
+ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\
+ param.nSize = sizeof(param);
+
+#define QCP_HEADER_SIZE sizeof(struct qcp_header)
+#define MIN_BITRATE 4 /* Bit rate 1 - 13.6 , 2 - 6.2 , 3 - 2.7 , 4 - 1.0 kbps*/
+#define MAX_BITRATE 4
+
+#define FAILED(result) (result != OMX_ErrorNone)
+
+#define SUCCEEDED(result) (result == OMX_ErrorNone)
+
+/************************************************************************/
+/* GLOBAL DECLARATIONS */
+/************************************************************************/
+
+pthread_mutex_t lock;
+pthread_cond_t cond;
+pthread_mutex_t elock;
+pthread_cond_t econd;
+pthread_cond_t fcond;
+pthread_mutex_t etb_lock;
+pthread_mutex_t etb_lock1;
+pthread_cond_t etb_cond;
+FILE * inputBufferFile;
+FILE * outputBufferFile;
+OMX_PARAM_PORTDEFINITIONTYPE inputportFmt;
+OMX_PARAM_PORTDEFINITIONTYPE outputportFmt;
+OMX_AUDIO_PARAM_QCELP13TYPE qcelp13param;
+OMX_AUDIO_PARAM_PCMMODETYPE pcmparam;
+OMX_PORT_PARAM_TYPE portParam;
+OMX_PORT_PARAM_TYPE portFmt;
+OMX_ERRORTYPE error;
+
+
+
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+struct enc_meta_out{
+ unsigned int offset_to_frame;
+ unsigned int frame_size;
+ unsigned int encoded_pcm_samples;
+ unsigned int msw_ts;
+ unsigned int lsw_ts;
+ unsigned int nflags;
+} __attribute__ ((packed));
+
+struct qcp_header {
+ /* RIFF Section */
+ char riff[4];
+ unsigned int s_riff;
+ char qlcm[4];
+
+ /* Format chunk */
+ char fmt[4];
+ unsigned int s_fmt;
+ char mjr;
+ char mnr;
+ unsigned int data1; /* UNIQUE ID of the codec */
+ unsigned short data2;
+ unsigned short data3;
+ char data4[8];
+ unsigned short ver; /* Codec Info */
+ char name[80];
+ unsigned short abps; /* average bits per sec of the codec */
+ unsigned short bytes_per_pkt;
+ unsigned short samp_per_block;
+ unsigned short samp_per_sec;
+ unsigned short bits_per_samp;
+ unsigned char vr_num_of_rates; /* Rate Header fmt info */
+ unsigned char rvd1[3];
+ unsigned short vr_bytes_per_pkt[8];
+ unsigned int rvd2[5];
+
+ /* Vrat chunk */
+ unsigned char vrat[4];
+ unsigned int s_vrat;
+ unsigned int v_rate;
+ unsigned int size_in_pkts;
+
+ /* Data chunk */
+ unsigned char data[4];
+ unsigned int s_data;
+} __attribute__ ((packed));
+
+ /* Common part */
+ static struct qcp_header append_header = {
+ {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'},
+ {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0},
+ {'v','r','a','t'},0, 0, 0,{'d','a','t','a'},0
+ };
+
+static unsigned totaldatalen = 0;
+static unsigned framecnt = 0;
+/************************************************************************/
+/* GLOBAL INIT */
+/************************************************************************/
+
+int input_buf_cnt = 0;
+int output_buf_cnt = 0;
+int used_ip_buf_cnt = 0;
+volatile int event_is_done = 0;
+volatile int ebd_event_is_done = 0;
+volatile int fbd_event_is_done = 0;
+volatile int etb_event_is_done = 0;
+int ebd_cnt;
+int bInputEosReached = 0;
+int bOutputEosReached = 0;
+int bInputEosReached_tunnel = 0;
+static int etb_done = 0;
+int bFlushing = false;
+int bPause = false;
+const char *in_filename;
+const char *out_filename;
+
+int timeStampLfile = 0;
+int timestampInterval = 100;
+
+//* OMX Spec Version supported by the wrappers. Version = 1.1 */
+const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101;
+OMX_COMPONENTTYPE* qcelp13_enc_handle = 0;
+
+OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL;
+OMX_BUFFERHEADERTYPE **pOutputBufHdrs = NULL;
+
+/************************************************************************/
+/* GLOBAL FUNC DECL */
+/************************************************************************/
+int Init_Encoder(char*);
+int Play_Encoder();
+OMX_STRING aud_comp;
+/**************************************************************************/
+/* STATIC DECLARATIONS */
+/**************************************************************************/
+
+static int open_audio_file ();
+static int Read_Buffer(OMX_BUFFERHEADERTYPE *pBufHdr );
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *qcelp13_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize);
+
+
+static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+static OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE parse_pcm_header();
+void wait_for_event(void)
+{
+ pthread_mutex_lock(&lock);
+ DEBUG_PRINT("%s: event_is_done=%d", __FUNCTION__, event_is_done);
+ while (event_is_done == 0) {
+ pthread_cond_wait(&cond, &lock);
+ }
+ event_is_done = 0;
+ pthread_mutex_unlock(&lock);
+}
+
+void event_complete(void )
+{
+ pthread_mutex_lock(&lock);
+ if (event_is_done == 0) {
+ event_is_done = 1;
+ pthread_cond_broadcast(&cond);
+ }
+ pthread_mutex_unlock(&lock);
+}
+
+void etb_wait_for_event(void)
+{
+ pthread_mutex_lock(&etb_lock1);
+ DEBUG_PRINT("%s: etb_event_is_done=%d", __FUNCTION__, etb_event_is_done);
+ while (etb_event_is_done == 0) {
+ pthread_cond_wait(&etb_cond, &etb_lock1);
+ }
+ etb_event_is_done = 0;
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+void etb_event_complete(void )
+{
+ pthread_mutex_lock(&etb_lock1);
+ if (etb_event_is_done == 0) {
+ etb_event_is_done = 1;
+ pthread_cond_broadcast(&etb_cond);
+ }
+ pthread_mutex_unlock(&etb_lock1);
+}
+
+static void create_qcp_header(int Datasize, int Frames)
+{
+ append_header.s_riff = Datasize + QCP_HEADER_SIZE - 8;
+ /* exclude riff id and size field */
+ append_header.data1 = 0x5E7F6D41;
+ append_header.data2 = 0xB115;
+ append_header.data3 = 0x11D0;
+ append_header.data4[0] = 0xBA;
+ append_header.data4[1] = 0x91;
+ append_header.data4[2] = 0x00;
+ append_header.data4[3] = 0x80;
+ append_header.data4[4] = 0x5F;
+ append_header.data4[5] = 0xB4;
+ append_header.data4[6] = 0xB9;
+ append_header.data4[7] = 0x7E;
+ append_header.ver = 0x0002;
+ memcpy(append_header.name, "Qcelp 13K", 9);
+ append_header.abps = 13000;
+ append_header.bytes_per_pkt = 35;
+ append_header.vr_num_of_rates = 5;
+ append_header.vr_bytes_per_pkt[0] = 0x0422;
+ append_header.vr_bytes_per_pkt[1] = 0x0310;
+ append_header.vr_bytes_per_pkt[2] = 0x0207;
+ append_header.vr_bytes_per_pkt[3] = 0x0103;
+ append_header.s_vrat = 0x00000008;
+ append_header.v_rate = 0x00000001;
+ append_header.size_in_pkts = Frames;
+ append_header.s_data = Datasize;
+ return;
+}
+
+OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData)
+{
+ DEBUG_PRINT("Function %s \n", __FUNCTION__);
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)hComponent;
+ (void)pAppData;
+ (void)pEventData;
+
+ switch(eEvent) {
+ case OMX_EventCmdComplete:
+ DEBUG_PRINT("\n OMX_EventCmdComplete event=%d data1=%lu data2=%lu\n",(OMX_EVENTTYPE)eEvent,
+ nData1,nData2);
+ event_complete();
+ break;
+ case OMX_EventError:
+ DEBUG_PRINT("\n OMX_EventError \n");
+ break;
+ case OMX_EventBufferFlag:
+ DEBUG_PRINT("\n OMX_EventBufferFlag \n");
+ bOutputEosReached = true;
+ event_complete();
+ break;
+ case OMX_EventPortSettingsChanged:
+ DEBUG_PRINT("\n OMX_EventPortSettingsChanged \n");
+ break;
+ default:
+ DEBUG_PRINT("\n Unknown Event \n");
+ break;
+ }
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE FillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ size_t bytes_writen = 0;
+ int total_bytes_writen = 0;
+ unsigned int len = 0;
+ struct enc_meta_out *meta = NULL;
+ OMX_U8 *src = pBuffer->pBuffer;
+ unsigned int num_of_frames = 1;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ if(((pBuffer->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS)) {
+ DEBUG_PRINT("FBD::EOS on output port\n ");
+ bOutputEosReached = true;
+ return OMX_ErrorNone;
+ }
+ if(bInputEosReached_tunnel || bOutputEosReached)
+ {
+ DEBUG_PRINT("EOS REACHED NO MORE PROCESSING OF BUFFERS\n");
+ return OMX_ErrorNone;
+ }
+ if(num_of_frames != src[0]){
+
+ printf("Data corrupt\n");
+ return OMX_ErrorNone;
+ }
+ /* Skip the first bytes */
+
+
+
+ src += sizeof(unsigned char);
+ meta = (struct enc_meta_out *)src;
+ while (num_of_frames > 0) {
+ meta = (struct enc_meta_out *)src;
+ /*printf("offset=%d framesize=%d encoded_pcm[%d] msw_ts[%d]lsw_ts[%d] nflags[%d]\n",
+ meta->offset_to_frame,
+ meta->frame_size,
+ meta->encoded_pcm_samples, meta->msw_ts, meta->lsw_ts, meta->nflags);*/
+ len = meta->frame_size;
+
+ bytes_writen = fwrite(pBuffer->pBuffer + sizeof(unsigned char) + meta->offset_to_frame,1,len,outputBufferFile);
+ if(bytes_writen < len)
+ {
+ DEBUG_PRINT("error: invalid QCELP13 encoded data \n");
+ return OMX_ErrorNone;
+ }
+ src += sizeof(struct enc_meta_out);
+ num_of_frames--;
+ total_bytes_writen += len;
+ }
+ DEBUG_PRINT(" FillBufferDone size writen to file %d count %d\n",total_bytes_writen, framecnt);
+ totaldatalen += total_bytes_writen ;
+ framecnt++;
+
+ DEBUG_PRINT(" FBD calling FTB\n");
+ OMX_FillThisBuffer(hComponent,pBuffer);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ int readBytes =0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)pAppData;
+
+ ebd_cnt++;
+ used_ip_buf_cnt--;
+ pthread_mutex_lock(&etb_lock);
+ if(!etb_done)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT("Wait till first set of buffers are given to component\n");
+ DEBUG_PRINT("\n*********************************************\n");
+ etb_done++;
+ pthread_mutex_unlock(&etb_lock);
+ etb_wait_for_event();
+ }
+ else
+ {
+ pthread_mutex_unlock(&etb_lock);
+ }
+
+
+ if(bInputEosReached)
+ {
+ DEBUG_PRINT("\n*********************************************\n");
+ DEBUG_PRINT(" EBD::EOS on input port\n ");
+ DEBUG_PRINT("*********************************************\n");
+ return OMX_ErrorNone;
+ }else if (bFlushing == true) {
+ DEBUG_PRINT("omx_qcelp13_adec_test: bFlushing is set to TRUE used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ if (used_ip_buf_cnt == 0) {
+ bFlushing = false;
+ } else {
+ DEBUG_PRINT("omx_qcelp13_adec_test: more buffer to come back used_ip_buf_cnt=%d\n",used_ip_buf_cnt);
+ return OMX_ErrorNone;
+ }
+ }
+
+ if((readBytes = Read_Buffer(pBuffer)) > 0) {
+ pBuffer->nFilledLen = readBytes;
+ used_ip_buf_cnt++;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ }
+ else{
+ pBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
+ used_ip_buf_cnt++;
+ bInputEosReached = true;
+ pBuffer->nFilledLen = 0;
+ OMX_EmptyThisBuffer(hComponent,pBuffer);
+ DEBUG_PRINT("EBD..Either EOS or Some Error while reading file\n");
+ }
+ return OMX_ErrorNone;
+}
+
+void signal_handler(int sig_id) {
+
+ /* Flush */
+ if (sig_id == SIGUSR1) {
+ DEBUG_PRINT("%s Initiate flushing\n", __FUNCTION__);
+ bFlushing = true;
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandFlush, OMX_ALL, NULL);
+ } else if (sig_id == SIGUSR2) {
+ if (bPause == true) {
+ DEBUG_PRINT("%s resume record\n", __FUNCTION__);
+ bPause = false;
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+ } else {
+ DEBUG_PRINT("%s pause record\n", __FUNCTION__);
+ bPause = true;
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StatePause, NULL);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int bufCnt=0;
+ OMX_ERRORTYPE result;
+
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &signal_handler;
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGUSR2, &sa, NULL);
+
+ (void) signal(SIGINT, Release_Encoder);
+
+ pthread_cond_init(&cond, 0);
+ pthread_mutex_init(&lock, 0);
+ pthread_cond_init(&etb_cond, 0);
+ pthread_mutex_init(&etb_lock, 0);
+ pthread_mutex_init(&etb_lock1, 0);
+
+ if (argc >= 9) {
+ in_filename = argv[1];
+ out_filename = argv[2];
+ tunnel = atoi(argv[3]);
+ min_bitrate = atoi(argv[4]);
+ max_bitrate = atoi(argv[5]);
+ cdmarate = atoi(argv[6]);
+ recpath = atoi(argv[7]); // No configuration support yet..
+ rectime = atoi(argv[8]);
+
+ } else {
+ DEBUG_PRINT(" invalid format: \n");
+ DEBUG_PRINT("ex: ./mm-aenc-omxqcelp13-test INPUTFILE OUTPUTFILE Tunnel MINRATE MAXRATE CDMARATE RECORDPATH RECORDTIME\n");
+ DEBUG_PRINT("MINRATE, MAXRATE and CDMARATE 1 to 4\n");
+ DEBUG_PRINT("RECORDPATH 0(TX),1(RX),2(BOTH),3(MIC)\n");
+ DEBUG_PRINT("RECORDTIME in seconds for AST Automation\n");
+ return 0;
+ }
+ if(recpath != 3) {
+ DEBUG_PRINT("For RECORDPATH Only MIC supported\n");
+ return 0;
+ }
+
+ if(tunnel == 0)
+ aud_comp = "OMX.qcom.audio.encoder.qcelp13";
+ else
+ aud_comp = "OMX.qcom.audio.encoder.tunneled.qcelp13";
+ if(Init_Encoder(aud_comp)!= 0x00)
+ {
+ DEBUG_PRINT("Decoder Init failed\n");
+ return -1;
+ }
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+
+ if(Play_Encoder() != 0x00)
+ {
+ DEBUG_PRINT("Play_Decoder failed\n");
+ return -1;
+ }
+
+ // Wait till EOS is reached...
+ if(rectime && tunnel)
+ {
+ sleep(rectime);
+ rectime = 0;
+ bInputEosReached_tunnel = 1;
+ DEBUG_PRINT("\EOS ON INPUT PORT\n");
+ }
+ else
+ {
+ wait_for_event();
+ }
+
+ if((bInputEosReached_tunnel) || ((bOutputEosReached) && !tunnel))
+ {
+
+ DEBUG_PRINT("\nMoving the decoder to idle state \n");
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ wait_for_event();
+
+ DEBUG_PRINT("\nMoving the encoder to loaded state \n");
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateLoaded,0);
+ sleep(1);
+ if (!tunnel)
+ {
+ DEBUG_PRINT("\nFillBufferDone: Deallocating i/p buffers \n");
+ for(bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(qcelp13_enc_handle, 0, pInputBufHdrs[bufCnt]);
+ }
+ }
+
+ DEBUG_PRINT ("\nFillBufferDone: Deallocating o/p buffers \n");
+ for(bufCnt=0; bufCnt < output_buf_cnt; ++bufCnt) {
+ OMX_FreeBuffer(qcelp13_enc_handle, 1, pOutputBufHdrs[bufCnt]);
+ }
+ wait_for_event();
+ create_qcp_header(totaldatalen, framecnt);
+ fseek(outputBufferFile, 0,SEEK_SET);
+ fwrite(&append_header,1,QCP_HEADER_SIZE,outputBufferFile);
+
+
+ result = OMX_FreeHandle(qcelp13_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+ if(tunnel)
+ {
+ #ifdef AUDIOV2
+ if (msm_route_stream(DIR_TX,session_id,device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not set stream routing\n");
+ return -1;
+ }
+ if (msm_en_device(device_id, 0))
+ {
+ DEBUG_PRINT("\ncould not enable device\n");
+ return -1;
+ }
+ msm_mixer_close();
+ #endif
+ }
+ OMX_Deinit();
+ ebd_cnt=0;
+ bOutputEosReached = false;
+ bInputEosReached_tunnel = false;
+ bInputEosReached = 0;
+ qcelp13_enc_handle = NULL;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ fclose(outputBufferFile);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...QCELP13 ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ }
+ return 0;
+}
+
+void Release_Encoder()
+{
+ static int cnt=0;
+ OMX_ERRORTYPE result;
+
+ DEBUG_PRINT("END OF QCELP13 ENCODING: EXITING PLEASE WAIT\n");
+ bInputEosReached_tunnel = 1;
+ event_complete();
+ cnt++;
+ if(cnt > 1)
+ {
+ /* FORCE RESET */
+ qcelp13_enc_handle = NULL;
+ ebd_cnt=0;
+ bInputEosReached_tunnel = false;
+
+ result = OMX_FreeHandle(qcelp13_enc_handle);
+ if (result != OMX_ErrorNone) {
+ DEBUG_PRINT ("\nOMX_FreeHandle error. Error code: %d\n", result);
+ }
+
+ /* Deinit OpenMAX */
+
+ OMX_Deinit();
+
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&lock);
+ DEBUG_PRINT("*****************************************\n");
+ DEBUG_PRINT("******...QCELP13 ENC TEST COMPLETED...***************\n");
+ DEBUG_PRINT("*****************************************\n");
+ exit(0);
+ }
+}
+
+int Init_Encoder(OMX_STRING audio_component)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE omxresult;
+ OMX_U32 total = 0;
+ typedef OMX_U8* OMX_U8_PTR;
+ char *role ="audio_encoder";
+
+ static OMX_CALLBACKTYPE call_back = {
+ &EventHandler,&EmptyBufferDone,&FillBufferDone
+ };
+
+ /* Init. the OpenMAX Core */
+ DEBUG_PRINT("\nInitializing OpenMAX Core....\n");
+ omxresult = OMX_Init();
+
+ if(OMX_ErrorNone != omxresult) {
+ DEBUG_PRINT("\n Failed to Init OpenMAX core");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT("\nOpenMAX Core Init Done\n");
+ }
+
+ /* Query for audio decoders*/
+ DEBUG_PRINT("Qcelp13_test: Before entering OMX_GetComponentOfRole");
+ OMX_GetComponentsOfRole(role, &total, 0);
+ DEBUG_PRINT ("\nTotal components of role=%s :%lu", role, total);
+
+
+ omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&qcelp13_enc_handle),
+ (OMX_STRING)audio_component, NULL, &call_back);
+ if (FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to Load the component:%s\n", audio_component);
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nComponent %s is in LOADED state\n", audio_component);
+ }
+
+ /* Get the port information */
+ CONFIG_VERSION_SIZE(portParam);
+ omxresult = OMX_GetParameter(qcelp13_enc_handle, OMX_IndexParamAudioInit,
+ (OMX_PTR)&portParam);
+
+ if(FAILED(omxresult)) {
+ DEBUG_PRINT("\nFailed to get Port Param\n");
+ return -1;
+ }
+ else
+ {
+ DEBUG_PRINT("\nportParam.nPorts:%lu\n", portParam.nPorts);
+ DEBUG_PRINT("\nportParam.nStartPortNumber:%lu\n",
+ portParam.nStartPortNumber);
+ }
+
+ if(OMX_ErrorNone != omxresult)
+ {
+ DEBUG_PRINT("Set parameter failed");
+ }
+
+ return 0;
+}
+
+int Play_Encoder()
+{
+ int i;
+ int Size=0;
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE ret;
+ OMX_INDEXTYPE index;
+ DEBUG_PRINT("sizeof[%d]\n", sizeof(OMX_BUFFERHEADERTYPE));
+
+ /* open the i/p and o/p files based on the video file format passed */
+ if(open_audio_file()) {
+ DEBUG_PRINT("\n Returning -1");
+ return -1;
+ }
+
+ /* Query the encoder input min buf requirements */
+ CONFIG_VERSION_SIZE(inputportFmt);
+
+ /* Port for which the Client needs to obtain info */
+ inputportFmt.nPortIndex = portParam.nStartPortNumber;
+
+ OMX_GetParameter(qcelp13_enc_handle,OMX_IndexParamPortDefinition,&inputportFmt);
+ DEBUG_PRINT ("\nEnc Input Buffer Count %lu\n", inputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Input Buffer Size %lu\n", inputportFmt.nBufferSize);
+
+ if(OMX_DirInput != inputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Input Port\n");
+ return -1;
+ }
+
+ pcmparam.nPortIndex = 0;
+ pcmparam.nChannels = channels;
+ pcmparam.nSamplingRate = samplerate;
+ OMX_SetParameter(qcelp13_enc_handle,OMX_IndexParamAudioPcm,&pcmparam);
+
+
+ /* Query the encoder outport's min buf requirements */
+ CONFIG_VERSION_SIZE(outputportFmt);
+ /* Port for which the Client needs to obtain info */
+ outputportFmt.nPortIndex = portParam.nStartPortNumber + 1;
+
+ OMX_GetParameter(qcelp13_enc_handle,OMX_IndexParamPortDefinition,&outputportFmt);
+ DEBUG_PRINT ("\nEnc: Output Buffer Count %lu\n", outputportFmt.nBufferCountMin);
+ DEBUG_PRINT ("\nEnc: Output Buffer Size %lu\n", outputportFmt.nBufferSize);
+
+ if(OMX_DirOutput != outputportFmt.eDir) {
+ DEBUG_PRINT ("\nEnc: Expect Output Port\n");
+ return -1;
+ }
+
+
+ CONFIG_VERSION_SIZE(qcelp13param);
+
+ qcelp13param.nPortIndex = 1;
+ qcelp13param.nChannels = channels; //2 ; /* 1-> mono 2-> stereo*/
+ qcelp13param.nMinBitRate = min_bitrate;
+ qcelp13param.nMaxBitRate = max_bitrate;
+ OMX_SetParameter(qcelp13_enc_handle,OMX_IndexParamAudioQcelp13,&qcelp13param);
+ OMX_GetExtensionIndex(qcelp13_enc_handle,"OMX.Qualcomm.index.audio.sessionId",&index);
+ OMX_GetParameter(qcelp13_enc_handle,index,&streaminfoparam);
+ if(tunnel) {
+ #ifdef AUDIOV2
+ session_id = streaminfoparam.sessionId;
+ control = msm_mixer_open("/dev/snd/controlC0", 0);
+ if(control < 0)
+ printf("ERROR opening the device\n");
+ device_id = msm_get_device(device);
+ DEBUG_PRINT ("\ndevice_id = %d\n",device_id);
+ DEBUG_PRINT("\nsession_id = %d\n",session_id);
+ if (msm_en_device(device_id, 1))
+ {
+ perror("could not enable device\n");
+ return -1;
+ }
+ if (msm_route_stream(DIR_TX,session_id,device_id, 1))
+ {
+ perror("could not set stream routing\n");
+ return -1;
+ }
+ #endif
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand Encoder -> IDLE\n");
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateIdle,0);
+ /* wait_for_event(); should not wait here event complete status will
+ not come until enough buffer are allocated */
+ if (tunnel == 0)
+ {
+ input_buf_cnt = inputportFmt.nBufferCountActual; // inputportFmt.nBufferCountMin + 5;
+ DEBUG_PRINT("Transition to Idle State succesful...\n");
+ /* Allocate buffer on decoder's i/p port */
+ error = Allocate_Buffer(qcelp13_enc_handle, &pInputBufHdrs, inputportFmt.nPortIndex,
+ input_buf_cnt, inputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pInputBufHdrs == NULL) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Input buffer success\n");
+ }
+ }
+ output_buf_cnt = outputportFmt.nBufferCountMin ;
+
+ /* Allocate buffer on encoder's O/Pp port */
+ error = Allocate_Buffer(qcelp13_enc_handle, &pOutputBufHdrs, outputportFmt.nPortIndex,
+ output_buf_cnt, outputportFmt.nBufferSize);
+ if (error != OMX_ErrorNone || pOutputBufHdrs == NULL ) {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer error\n");
+ return -1;
+ }
+ else {
+ DEBUG_PRINT ("\nOMX_AllocateBuffer Output buffer success\n");
+ }
+
+ wait_for_event();
+
+
+ if (tunnel == 1)
+ {
+ DEBUG_PRINT ("\nOMX_SendCommand to enable TUNNEL MODE during IDLE\n");
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandPortDisable,0,0); // disable input port
+ wait_for_event();
+ }
+
+ DEBUG_PRINT ("\nOMX_SendCommand encoder -> Executing\n");
+ OMX_SendCommand(qcelp13_enc_handle, OMX_CommandStateSet, OMX_StateExecuting,0);
+ wait_for_event();
+
+ DEBUG_PRINT(" Start sending OMX_FILLthisbuffer\n");
+
+ for(i=0; i < output_buf_cnt; i++) {
+ DEBUG_PRINT ("\nOMX_FillThisBuffer on output buf no.%d\n",i);
+ pOutputBufHdrs[i]->nOutputPortIndex = 1;
+ pOutputBufHdrs[i]->nFlags &= ~OMX_BUFFERFLAG_EOS;
+ ret = OMX_FillThisBuffer(qcelp13_enc_handle, pOutputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_FillThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_FillThisBuffer success!\n");
+ }
+ }
+
+if(tunnel == 0)
+{
+ DEBUG_PRINT(" Start sending OMX_emptythisbuffer\n");
+ for (i = 0;i < input_buf_cnt;i++) {
+ DEBUG_PRINT ("\nOMX_EmptyThisBuffer on Input buf no.%d\n",i);
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ Size = Read_Buffer(pInputBufHdrs[i]);
+ if(Size <=0 ){
+ DEBUG_PRINT("NO DATA READ\n");
+ bInputEosReached = true;
+ pInputBufHdrs[i]->nFlags= OMX_BUFFERFLAG_EOS;
+ }
+ pInputBufHdrs[i]->nFilledLen = Size;
+ pInputBufHdrs[i]->nInputPortIndex = 0;
+ used_ip_buf_cnt++;
+ ret = OMX_EmptyThisBuffer(qcelp13_enc_handle, pInputBufHdrs[i]);
+ if (OMX_ErrorNone != ret) {
+ DEBUG_PRINT("OMX_EmptyThisBuffer failed with result %d\n", ret);
+ }
+ else {
+ DEBUG_PRINT("OMX_EmptyThisBuffer success!\n");
+ }
+ if(Size <=0 ){
+ break;//eos reached
+ }
+ }
+ pthread_mutex_lock(&etb_lock);
+ if(etb_done)
+{
+ DEBUG_PRINT("Component is waiting for EBD to be released.\n");
+ etb_event_complete();
+ }
+ else
+ {
+ DEBUG_PRINT("\n****************************\n");
+ DEBUG_PRINT("EBD not yet happened ...\n");
+ DEBUG_PRINT("\n****************************\n");
+ etb_done++;
+ }
+ pthread_mutex_unlock(&etb_lock);
+}
+
+ return 0;
+}
+
+
+
+static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *avc_enc_handle,
+ OMX_BUFFERHEADERTYPE ***pBufHdrs,
+ OMX_U32 nPortIndex,
+ long bufCntMin, long bufSize)
+{
+ DEBUG_PRINT("Inside %s \n", __FUNCTION__);
+ OMX_ERRORTYPE error=OMX_ErrorNone;
+ long bufCnt=0;
+
+ /* To remove warning for unused variable to keep prototype same */
+ (void)avc_enc_handle;
+
+ *pBufHdrs= (OMX_BUFFERHEADERTYPE **)
+ malloc(sizeof(OMX_BUFFERHEADERTYPE*)*bufCntMin);
+
+ for(bufCnt=0; bufCnt < bufCntMin; ++bufCnt) {
+ DEBUG_PRINT("\n OMX_AllocateBuffer No %ld \n", bufCnt);
+ error = OMX_AllocateBuffer(qcelp13_enc_handle, &((*pBufHdrs)[bufCnt]),
+ nPortIndex, NULL, bufSize);
+ }
+
+ return error;
+}
+
+
+
+
+static int Read_Buffer (OMX_BUFFERHEADERTYPE *pBufHdr )
+{
+
+ int bytes_read=0;
+
+
+ pBufHdr->nFilledLen = 0;
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+
+ bytes_read = fread(pBufHdr->pBuffer, 1, pBufHdr->nAllocLen , inputBufferFile);
+
+ pBufHdr->nFilledLen = bytes_read;
+ // Time stamp logic
+ ((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp = \
+
+ (unsigned long) ((total_pcm_bytes * 1000)/(samplerate * channels *2));
+
+ DEBUG_PRINT ("\n--time stamp -- %ld\n", (unsigned long)((OMX_BUFFERHEADERTYPE *)pBufHdr)->nTimeStamp);
+ if(bytes_read == 0)
+ {
+ pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
+ DEBUG_PRINT ("\nBytes read zero\n");
+ }
+ else
+ {
+ pBufHdr->nFlags &= ~OMX_BUFFERFLAG_EOS;
+
+ total_pcm_bytes += bytes_read;
+ }
+
+ return bytes_read;;
+}
+
+
+
+//In Encoder this Should Open a PCM or WAV file for input.
+
+static int open_audio_file ()
+{
+ int error_code = 0;
+
+ if (!tunnel)
+ {
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename);
+ inputBufferFile = fopen (in_filename, "rb");
+ if (inputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ in_filename);
+ error_code = -1;
+ }
+ if(parse_pcm_header() != 0x00)
+ {
+ DEBUG_PRINT("PCM parser failed \n");
+ return -1;
+ }
+ }
+
+ DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, out_filename);
+ outputBufferFile = fopen (out_filename, "wb");
+ if (outputBufferFile == NULL) {
+ DEBUG_PRINT("\ni/p file %s could NOT be opened\n",
+ out_filename);
+ error_code = -1;
+ return error_code;
+ }
+ fseek(outputBufferFile, QCP_HEADER_SIZE, SEEK_SET);
+ return error_code;
+}
+
+static OMX_ERRORTYPE parse_pcm_header()
+{
+ struct wav_header hdr;
+
+ DEBUG_PRINT("\n***************************************************************\n");
+ if(fread(&hdr, 1, sizeof(hdr),inputBufferFile)!=sizeof(hdr))
+ {
+ DEBUG_PRINT("Wav file cannot read header\n");
+ return -1;
+ }
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE)||
+ (hdr.fmt_id != ID_FMT))
+ {
+ DEBUG_PRINT("Wav file is not a riff/wave file\n");
+ return -1;
+ }
+
+ if (hdr.audio_format != FORMAT_PCM)
+ {
+ DEBUG_PRINT("Wav file is not adpcm format %d and fmt size is %d\n",
+ hdr.audio_format, hdr.fmt_sz);
+ return -1;
+ }
+
+ DEBUG_PRINT("Samplerate is %d\n", hdr.sample_rate);
+ DEBUG_PRINT("Channel Count is %d\n", hdr.num_channels);
+ DEBUG_PRINT("\n***************************************************************\n");
+
+ samplerate = hdr.sample_rate;
+ channels = hdr.num_channels;
+ total_pcm_bytes = 0;
+
+ return OMX_ErrorNone;
+}
diff --git a/mm-audio/autogen.sh b/mm-audio/autogen.sh
new file mode 100644
index 0000000..de72aa1
--- /dev/null
+++ b/mm-audio/autogen.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# autogen.sh -- Autotools bootstrapping
+
+libtoolize --copy --force
+aclocal &&\
+autoheader &&\
+autoconf &&\
+automake --add-missing --copy
+
diff --git a/mm-audio/configure.ac b/mm-audio/configure.ac
new file mode 100644
index 0000000..b75d2ed
--- /dev/null
+++ b/mm-audio/configure.ac
@@ -0,0 +1,44 @@
+# -*- Autoconf -*-
+
+# configure.ac -- Autoconf script for mm-omxaudio
+#
+
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.61)
+AC_INIT([omxaudio],
+ 1.0.0)
+AM_INIT_AUTOMAKE([-Wall -Werror gnu foreign])
+AM_MAINTAINER_MODE
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+#release versioning
+OMXAUDIO_MAJOR_VERSION=1
+OMXAUDIO_MINOR_VERSION=0
+OMXAUDIO_MICRO_VERSION=0
+
+OMXAUDIO_LIBRARY_VERSION=$OMXAUDIO_MAJOR_VERSION:$OMXAUDIO_MINOR_VERSION:$OMXAUDIO_MICRO_VERSION
+AC_SUBST(OMXAUDIO_LIBRARY_VERSION)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+AC_PROG_AWK
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ adec-aac/Makefile \
+ adec-mp3/Makefile \
+ aenc-aac/Makefile \
+ adec-aac/qdsp6/Makefile \
+ adec-mp3/qdsp6/Makefile \
+ aenc-aac/qdsp6/Makefile \
+ ])
+AC_OUTPUT
diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk
new file mode 100644
index 0000000..b6a06e4
--- /dev/null
+++ b/policy_hal/Android.mk
@@ -0,0 +1,35 @@
+ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := AudioPolicyManager.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ liblog
+
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true)
+LOCAL_CFLAGS += -DAUDIO_EXTN_FM_ENABLED
+endif
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_PROXY_DEVICE)),true)
+LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED
+endif
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true)
+LOCAL_CFLAGS += -DAUDIO_EXTN_INCALL_MUSIC_ENABLED
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
new file mode 100644
index 0000000..0716656
--- /dev/null
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2009 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 "AudioPolicyManager"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// A device mask for all audio input devices that are considered "virtual" when evaluating
+// active inputs in getActiveInput()
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX | AUDIO_DEVICE_IN_FM_RX_A2DP
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+
+#include <utils/Log.h>
+#include "AudioPolicyManager.h"
+#include <hardware/audio_effect.h>
+#include <hardware/audio.h>
+#include <math.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <cutils/properties.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ SortedVector <audio_io_handle_t> outputs;
+
+ ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (audio_is_output_device(device)) {
+
+ if (!mHasA2dp && audio_is_a2dp_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasUsb && audio_is_usb_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+ ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+ return BAD_VALUE;
+ }
+
+ // save a copy of the opened output descriptors before any output is opened or closed
+ // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+ mPreviousOutputs = mOutputs;
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+ if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+ outputs.size());
+ // register new device as available
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+
+ if (!outputs.isEmpty()) {
+ String8 paramStr;
+ if (mHasA2dp && audio_is_a2dp_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device connection
+ mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasUsb && audio_is_usb_device(device)) {
+ // handle USB device connection
+ mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ paramStr = mUsbCardAndDevice;
+ }
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
+ if (!paramStr.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ mpClientInterface->setParameters(outputs[i], paramStr);
+ }
+ }
+ }
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableOutputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+
+ checkOutputsForDevice(device, state, outputs);
+ if (mHasA2dp && audio_is_a2dp_device(device)) {
+ // handle A2DP device disconnection
+ mA2dpDeviceAddress = "";
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device disconnection
+ mScoDeviceAddress = "";
+ } else if (mHasUsb && audio_is_usb_device(device)) {
+ // handle USB device disconnection
+ mUsbCardAndDevice = "";
+ }
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ // outputs must be closed after checkOutputForAllStrategies() is executed
+ if (!outputs.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+ // close unused outputs after device disconnection or direct outputs that have been
+ // opened by checkOutputsForDevice() to query dynamic parameters
+ if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
+ (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+ (desc->mDirectOpenCount == 0))) {
+ closeOutput(outputs[i]);
+ }
+ }
+ }
+
+ updateDevicesAndOutputs();
+ audio_devices_t newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+#ifdef AUDIO_EXTN_FM_ENABLED
+ if(device == AUDIO_DEVICE_OUT_FM) {
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::MUSIC, 1);
+ newDevice = (audio_devices_t)(getNewDevice(mPrimaryOutput, false) | AUDIO_DEVICE_OUT_FM);
+ } else {
+ mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::MUSIC, -1);
+ }
+
+ AudioParameter param = AudioParameter();
+ param.addInt(String8("handle_fm"), (int)newDevice);
+ ALOGV("setDeviceConnectionState() setParameters handle_fm");
+ mpClientInterface->setParameters(mPrimaryOutput, param.toString());
+ }
+#endif
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ // do not force device change on duplicated output because if device is 0, it will
+ // also force a device 0 for the two outputs it is duplicated to which may override
+ // a valid device selection on those outputs.
+ setOutputDevice(mOutputs.keyAt(i),
+ getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ !mOutputs.valueAt(i)->isDuplicated(),
+ 0);
+ }
+
+ if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if(device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET){
+ device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ } else {
+ return NO_ERROR;
+ }
+ }
+ // handle input devices
+ if (audio_is_input_device(device)) {
+
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE: {
+ if (mAvailableInputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+ }
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableInputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+ return NO_ERROR;
+ }
+
+ ALOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+ bool forceVolumeReeval = false;
+ switch(usage) {
+ case AudioSystem::FOR_COMMUNICATION:
+ if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return;
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_MEDIA:
+ if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+#ifdef AUDIO_EXTN_FM_ENABLED
+ config != AudioSystem::FORCE_SPEAKER &&
+#endif
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_NO_BT_A2DP) {
+ ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_RECORD:
+ if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_DOCK:
+ if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+ config != AudioSystem::FORCE_BT_DESK_DOCK &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
+ ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_SYSTEM:
+ if (config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ default:
+ ALOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+
+ // check for device and output changes triggered by new force usage
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+ for (int i = mOutputs.size() -1; i >= 0; i--) {
+ audio_io_handle_t output = mOutputs.keyAt(i);
+ audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+ if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+ applyStreamVolumes(output, newDevice, 0, true);
+ }
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setForceUse() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+}
+
+audio_io_handle_t AudioPolicyManager::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ audio_io_handle_t input = 0;
+ audio_devices_t device = getDeviceForInputSource(inputSource);
+
+ ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
+ inputSource, samplingRate, format, channelMask, acoustics);
+
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGW("getInput() could not find device for inputSource %d", inputSource);
+ return 0;
+ }
+
+
+ IOProfile *profile = getInputProfile(device,
+ samplingRate,
+ format,
+ channelMask);
+ if (profile == NULL) {
+ ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d,"
+ "channelMask %04x",
+ device, samplingRate, format, channelMask);
+ return 0;
+ }
+
+ if (profile->mModule->mHandle == 0) {
+ ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
+ return 0;
+ }
+
+ AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+
+ inputDesc->mInputSource = inputSource;
+ inputDesc->mDevice = device;
+ inputDesc->mSamplingRate = samplingRate;
+ inputDesc->mFormat = (audio_format_t)format;
+ inputDesc->mChannelMask = (audio_channel_mask_t)channelMask;
+ inputDesc->mRefCount = 0;
+ input = mpClientInterface->openInput(profile->mModule->mHandle,
+ &inputDesc->mDevice,
+ &inputDesc->mSamplingRate,
+ &inputDesc->mFormat,
+ &inputDesc->mChannelMask);
+
+ // only accept input with the exact requested set of parameters
+ if (input == 0 ||
+ (samplingRate != inputDesc->mSamplingRate) ||
+ (format != inputDesc->mFormat) ||
+ (channelMask != inputDesc->mChannelMask)) {
+ ALOGV("getInput() failed opening input: samplingRate %d, format %d, channelMask %d",
+ samplingRate, format, channelMask);
+ if (input != 0) {
+ mpClientInterface->closeInput(input);
+ }
+ delete inputDesc;
+ return 0;
+ }
+ mInputs.add(input, inputDesc);
+ return input;
+}
+
+AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(AudioSystem::stream_type stream)
+{
+#ifdef QCOM_INCALL_MUSIC_ENABLED
+ if (stream == AudioSystem::INCALL_MUSIC)
+ return STRATEGY_MEDIA;
+#endif
+
+ return getStrategy(stream);
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ if (fromCache) {
+ ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
+ strategy, mDeviceForStrategy[strategy]);
+ return mDeviceForStrategy[strategy];
+ }
+
+ switch (strategy) {
+
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActiveRemotely(AudioSystem::MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing on a remote device, use the the sonification behavior.
+ // Note that we test this usecase before testing if media is playing because
+ // the isStreamActive() method only informs about the activity of a stream, not
+ // if it's for local playback. Note also that we use the same delay between both tests
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing (or has recently played), use the same device
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ } else {
+ // when media is not playing anymore, fall back on the sonification behavior
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ }
+
+ break;
+
+ case STRATEGY_DTMF:
+ if (!isInCall()) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ break;
+ }
+ // when in call, DTMF and PHONE strategies follow the same rules
+ // FALL THROUGH
+
+ case STRATEGY_PHONE:
+ // for phone strategy, we first consider the forced use and then the available devices by order
+ // of priority
+ switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+ case AudioSystem::FORCE_BT_SCO:
+ if (!isInCall() || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ if (device) break;
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ }
+
+ // Allow voice call on USB ANLG DOCK headset
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+ }
+ break;
+ }
+ // FIXME: Why do need to replace with speaker? If voice call is active
+ // We should use device from STRATEGY_PHONE
+#ifdef AUDIO_EXTN_FM_ENABLED
+ if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
+ if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ }
+ }
+#endif
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except:
+ // - when in call where it doesn't default to STRATEGY_PHONE behavior
+ // - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+ if ((strategy == STRATEGY_SONIFICATION) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+ }
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ case STRATEGY_MEDIA: {
+ uint32_t device2 = AUDIO_DEVICE_NONE;
+
+ if (isInCall()) {
+ // when in call, get the device for Phone strategy
+ device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+ break;
+ }
+#ifdef AUDIO_EXTN_FM_ENABLED
+ if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ break;
+ }
+#endif
+
+ if (strategy != STRATEGY_SONIFICATION) {
+ // no sonification on remote submix (e.g. WFD)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ // no sonification on aux digital (e.g. HDMI)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+#ifdef AUDIO_EXTN_FM_ENABLED
+ if ((strategy != STRATEGY_SONIFICATION) && (device2 == AUDIO_DEVICE_NONE)) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX;
+ }
+#endif
+#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED
+ if ((strategy != STRATEGY_SONIFICATION) && (device2 == AUDIO_DEVICE_NONE)) {
+ // no sonification on WFD sink
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY;
+ }
+#endif
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+ device |= device2;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+ }
+ } break;
+
+ default:
+ ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return device;
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ switch (inputSource) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ break;
+ }
+ // FALL THROUGH
+
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_HOTWORD:
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+ mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) {
+ device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ }
+ break;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+#ifdef AUDIO_EXTN_FM_ENABLED
+ case AUDIO_SOURCE_FM_RX:
+ device = AUDIO_DEVICE_IN_FM_RX;
+ break;
+ case AUDIO_SOURCE_FM_RX_A2DP:
+ device = AUDIO_DEVICE_IN_FM_RX_A2DP;
+ break;
+#endif
+ default:
+ ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+ break;
+ }
+ ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return device;
+}
+
+bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device)
+{
+ switch(getDeviceForVolume(device)) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ return DEVICE_CATEGORY_EARPIECE;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+#ifdef AUDIO_EXTN_FM_ENABLED
+ case AUDIO_DEVICE_OUT_FM:
+#endif
+ return DEVICE_CATEGORY_HEADSET;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED
+ case AUDIO_DEVICE_OUT_PROXY:
+#endif
+ default:
+ return DEVICE_CATEGORY_SPEAKER;
+ }
+}
+
+status_t AudioPolicyManager::checkAndSetVolume(int stream,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
+{
+ ALOGV("checkAndSetVolume: index %d output %d device %x", index, output, device);
+ // do not change actual stream volume if the stream is muted
+ if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+ ALOGVV("checkAndSetVolume() stream %d muted count %d",
+ stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+ return NO_ERROR;
+ }
+
+ // do not change in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ float volume = computeVolume(stream, index, output, device);
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+ force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ ALOGV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+ // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+ // enabled
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
+#ifdef AUDIO_EXTN_FM_ENABLED
+ } else if (stream == AudioSystem::MUSIC &&
+ output == mPrimaryOutput) {
+ float fmVolume = -1.0;
+ fmVolume = computeVolume(stream, index, output, device);
+ if (fmVolume >= 0) {
+ AudioParameter param = AudioParameter();
+ param.addFloat(String8("fm_volume"), fmVolume);
+ ALOGV("checkAndSetVolume setParameters fm_volume, volume=:%f delay=:%d",fmVolume,delayMs*2);
+ //Double delayMs to avoid sound burst while device switch.
+ mpClientInterface->setParameters(mPrimaryOutput, param.toString(), delayMs*2);
+ }
+#endif
+ }
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+
+ // Force voice volume to max when Vgs is set for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ String8 key ("bt_headset_vgs");
+ mpClientInterface->getParameters(output,key);
+ AudioParameter result(mpClientInterface->getParameters(0,key));
+ int value;
+ if (result.getInt(String8("isVGS"),value) == NO_ERROR) {
+ ALOGV("Use BT-SCO Voice Volume");
+ voiceVolume = 1.0;
+ }
+ }
+
+ if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+float AudioPolicyManager::computeVolume(int stream,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device)
+{
+ float volume = 1.0;
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+
+ if (device == AUDIO_DEVICE_NONE) {
+ device = outputDesc->device();
+ }
+
+ // if volume is not 0 (not muted), force media volume to max on digital output
+ if (stream == AudioSystem::MUSIC &&
+ index != mStreams[stream].mIndexMin &&
+ (device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+ device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET ||
+ device == AUDIO_DEVICE_OUT_USB_ACCESSORY ||
+#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED
+ device == AUDIO_DEVICE_OUT_PROXY ||
+#endif
+ device == AUDIO_DEVICE_OUT_USB_DEVICE )) {
+ return 1.0;
+ }
+#ifdef AUDIO_EXTN_INCALL_MUSIC_ENABLED
+ if (stream == AudioSystem::INCALL_MUSIC) {
+ return 1.0;
+ }
+#endif
+ return AudioPolicyManagerBase::computeVolume(stream, index, output, device);
+}
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+}; // namespace android
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
new file mode 100644
index 0000000..2e0c6fb
--- /dev/null
+++ b/policy_hal/AudioPolicyManager.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2009 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.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManager: public AudioPolicyManagerBase
+{
+
+public:
+ AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManagerBase(clientInterface) {}
+
+ virtual ~AudioPolicyManager() {}
+
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics);
+protected:
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(AudioSystem::stream_type stream);
+
+ // return appropriate device for streams handled by the specified strategy according to current
+ // phone state, connected devices...
+ // if fromCache is true, the device is returned from mDeviceForStrategy[],
+ // otherwise it is determine by current state
+ // (device connected,phone state, force use, a2dp output...)
+ // This allows to:
+ // 1 speed up process when the state is stable (when starting or stopping an output)
+ // 2 access to either current device selection (fromCache == true) or
+ // "future" device selection (fromCache == false) when called from a context
+ // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ // before updateDevicesAndOutputs() is called.
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache = true);
+ // select input device corresponding to requested audio source
+ virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+ static bool isVirtualInputDevice(audio_devices_t device);
+
+ // compute the actual volume for a given stream according to the requested index and a particular
+ // device
+ virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device);
+
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+ // returns the category the device belongs to with regard to volume curve management
+ static device_category getDeviceCategory(audio_devices_t device);
+
+};
+};
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
new file mode 100644
index 0000000..b6966e6
--- /dev/null
+++ b/post_proc/Android.mk
@@ -0,0 +1,31 @@
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ bundle.c \
+ equalizer.c \
+ bass_boost.c \
+ virtualizer.c \
+ reverb.c \
+ effect_api.c
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+ libtinyalsa
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libqcompostprocbundle
+
+LOCAL_C_INCLUDES := \
+ external/tinyalsa/include \
+ kernel/include/sound \
+ $(call include-path-for, audio-effects)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
new file mode 100644
index 0000000..c64ba6b
--- /dev/null
+++ b/post_proc/bass_boost.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 "offload_effect_bass_boost"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_bassboost.h>
+
+#include "effect_api.h"
+#include "bass_boost.h"
+
+/* Offload bassboost UUID: 2c4a8c24-1581-487f-94f6-0002a5d5c51b */
+const effect_descriptor_t bassboost_descriptor = {
+ {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }},
+ {0x2c4a8c24, 0x1581, 0x487f, 0x94f6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload bassboost",
+ "The Android Open Source Project",
+};
+
+/*
+ * Bassboost operations
+ */
+
+int bassboost_get_strength(bassboost_context_t *context)
+{
+ ALOGV("%s: strength: %d", __func__, context->strength);
+ return context->strength;
+}
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength)
+{
+ ALOGV("%s: strength: %d", __func__, strength);
+ context->strength = strength;
+
+ offload_bassboost_set_strength(&(context->offload_bass), strength);
+ if (context->ctl)
+ offload_bassboost_send_params(context->ctl, context->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+ OFFLOAD_SEND_BASSBOOST_STRENGTH);
+ return 0;
+}
+
+int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case BASSBOOST_PARAM_STRENGTH:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__);
+ *(uint32_t *)value = 1;
+ break;
+
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__);
+ *(int16_t *)value = bassboost_get_strength(bass_ctxt);
+ break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ uint32_t strength;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__);
+ strength = (uint32_t)(*(int16_t *)value);
+ bassboost_set_strength(bass_ctxt, strength);
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int bassboost_set_device(effect_context_t *context, uint32_t device)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s: device: %d", __func__, device);
+ bass_ctxt->device = device;
+ if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
+ if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+ bass_ctxt->temp_disabled = true;
+ }
+ } else {
+ if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) &&
+ bass_ctxt->temp_disabled) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+ bass_ctxt->temp_disabled = false;
+ }
+ }
+ offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
+ return 0;
+}
+
+int bassboost_reset(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ return 0;
+}
+
+int bassboost_init(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ bass_ctxt->temp_disabled = false;
+ memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params));
+
+ return 0;
+}
+
+int bassboost_enable(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)))
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+ return 0;
+}
+
+int bassboost_disable(effect_context_t *context)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+ if (bass_ctxt->ctl)
+ offload_bassboost_send_params(bass_ctxt->ctl,
+ bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int bassboost_start(effect_context_t *context, output_context_t *output)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ bass_ctxt->ctl = output->ctl;
+ ALOGV("output->ctl: %p", output->ctl);
+ return 0;
+}
+
+int bassboost_stop(effect_context_t *context, output_context_t *output)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ bass_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
new file mode 100644
index 0000000..430a07d
--- /dev/null
+++ b/post_proc/bass_boost.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_EFFECT_BASS_BOOST_H_
+#define OFFLOAD_EFFECT_BASS_BOOST_H_
+
+#include "bundle.h"
+
+extern const effect_descriptor_t bassboost_descriptor;
+
+typedef struct bassboost_context_s {
+ effect_context_t common;
+
+ int strength;
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ bool temp_disabled;
+ uint32_t device;
+ struct bass_boost_params offload_bass;
+} bassboost_context_t;
+
+int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int bassboost_set_device(effect_context_t *context, uint32_t device);
+
+int bassboost_reset(effect_context_t *context);
+
+int bassboost_init(effect_context_t *context);
+
+int bassboost_enable(effect_context_t *context);
+
+int bassboost_disable(effect_context_t *context);
+
+int bassboost_start(effect_context_t *context, output_context_t *output);
+
+int bassboost_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_EFFECT_BASS_BOOST_H_ */
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
new file mode 100644
index 0000000..8e2bce8
--- /dev/null
+++ b/post_proc/bundle.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 "offload_effect_bundle"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
+#include <hardware/audio_effect.h>
+
+#include "bundle.h"
+#include "equalizer.h"
+#include "bass_boost.h"
+#include "virtualizer.h"
+#include "reverb.h"
+
+enum {
+ EFFECT_STATE_UNINITIALIZED,
+ EFFECT_STATE_INITIALIZED,
+ EFFECT_STATE_ACTIVE,
+};
+
+const effect_descriptor_t *descriptors[] = {
+ &equalizer_descriptor,
+ &bassboost_descriptor,
+ &virtualizer_descriptor,
+ &aux_env_reverb_descriptor,
+ &ins_env_reverb_descriptor,
+ &aux_preset_reverb_descriptor,
+ &ins_preset_reverb_descriptor,
+ NULL,
+};
+
+pthread_once_t once = PTHREAD_ONCE_INIT;
+int init_status;
+/*
+ * list of created effects.
+ * Updated by offload_effects_bundle_hal_start_output()
+ * and offload_effects_bundle_hal_stop_output()
+ */
+struct listnode created_effects_list;
+/*
+ * list of active output streams.
+ * Updated by offload_effects_bundle_hal_start_output()
+ * and offload_effects_bundle_hal_stop_output()
+ */
+struct listnode active_outputs_list;
+/*
+ * lock must be held when modifying or accessing
+ * created_effects_list or active_outputs_list
+ */
+pthread_mutex_t lock;
+
+
+/*
+ * Local functions
+ */
+static void init_once() {
+ list_init(&created_effects_list);
+ list_init(&active_outputs_list);
+
+ pthread_mutex_init(&lock, NULL);
+
+ init_status = 0;
+}
+
+int lib_init()
+{
+ pthread_once(&once, init_once);
+ return init_status;
+}
+
+bool effect_exists(effect_context_t *context)
+{
+ struct listnode *node;
+
+ list_for_each(node, &created_effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(node,
+ effect_context_t,
+ effects_list_node);
+ if (fx_ctxt == context) {
+ return true;
+ }
+ }
+ return false;
+}
+
+output_context_t *get_output(audio_io_handle_t output)
+{
+ struct listnode *node;
+
+ list_for_each(node, &active_outputs_list) {
+ output_context_t *out_ctxt = node_to_item(node,
+ output_context_t,
+ outputs_list_node);
+ if (out_ctxt->handle == output)
+ return out_ctxt;
+ }
+ return NULL;
+}
+
+void add_effect_to_output(output_context_t * output, effect_context_t *context)
+{
+ struct listnode *fx_node;
+
+ list_for_each(fx_node, &output->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt == context)
+ return;
+ }
+ list_add_tail(&output->effects_list, &context->output_node);
+ if (context->ops.start)
+ context->ops.start(context, output);
+
+}
+
+void remove_effect_from_output(output_context_t * output,
+ effect_context_t *context)
+{
+ struct listnode *fx_node;
+
+ list_for_each(fx_node, &output->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt == context) {
+ if (context->ops.stop)
+ context->ops.stop(context, output);
+ list_remove(&context->output_node);
+ return;
+ }
+ }
+}
+
+bool effects_enabled()
+{
+ struct listnode *out_node;
+
+ list_for_each(out_node, &active_outputs_list) {
+ struct listnode *fx_node;
+ output_context_t *out_ctxt = node_to_item(out_node,
+ output_context_t,
+ outputs_list_node);
+
+ list_for_each(fx_node, &out_ctxt->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
+ (fx_ctxt->ops.process != NULL))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*
+ * Interface from audio HAL
+ */
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
+{
+ int ret = 0;
+ struct listnode *node;
+ char mixer_string[128];
+
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
+
+ if (lib_init() != 0)
+ return init_status;
+
+ pthread_mutex_lock(&lock);
+ if (get_output(output) != NULL) {
+ ALOGW("%s output already started", __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ output_context_t *out_ctxt = (output_context_t *)
+ malloc(sizeof(output_context_t));
+ out_ctxt->handle = output;
+ out_ctxt->pcm_device_id = pcm_id;
+
+ /* populate the mixer control to send offload parameters */
+ snprintf(mixer_string, sizeof(mixer_string),
+ "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
+ out_ctxt->mixer = mixer_open(MIXER_CARD);
+ if (!out_ctxt->mixer) {
+ ALOGE("Failed to open mixer");
+ out_ctxt->ctl = NULL;
+ ret = -EINVAL;
+ goto exit;
+ } else {
+ out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
+ if (!out_ctxt->ctl) {
+ ALOGE("mixer_get_ctl_by_name failed");
+ mixer_close(out_ctxt->mixer);
+ out_ctxt->mixer = NULL;
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ list_init(&out_ctxt->effects_list);
+
+ list_for_each(node, &created_effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(node,
+ effect_context_t,
+ effects_list_node);
+ if (fx_ctxt->out_handle == output) {
+ if (fx_ctxt->ops.start)
+ fx_ctxt->ops.start(fx_ctxt, out_ctxt);
+ list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
+ }
+ }
+ list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
+exit:
+ pthread_mutex_unlock(&lock);
+ return ret;
+}
+
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
+{
+ int ret;
+ struct listnode *node;
+ struct listnode *fx_node;
+ output_context_t *out_ctxt;
+
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
+
+ if (lib_init() != 0)
+ return init_status;
+
+ pthread_mutex_lock(&lock);
+
+ out_ctxt = get_output(output);
+ if (out_ctxt == NULL) {
+ ALOGW("%s output not started", __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ if (out_ctxt->mixer)
+ mixer_close(out_ctxt->mixer);
+
+ list_for_each(fx_node, &out_ctxt->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt->ops.stop)
+ fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
+ }
+
+ list_remove(&out_ctxt->outputs_list_node);
+
+ free(out_ctxt);
+
+exit:
+ pthread_mutex_unlock(&lock);
+ return ret;
+}
+
+
+/*
+ * Effect operations
+ */
+int set_config(effect_context_t *context, effect_config_t *config)
+{
+ context->config = *config;
+
+ if (context->ops.reset)
+ context->ops.reset(context);
+
+ return 0;
+}
+
+void get_config(effect_context_t *context, effect_config_t *config)
+{
+ *config = context->config;
+}
+
+
+/*
+ * Effect Library Interface Implementation
+ */
+int effect_lib_create(const effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_handle_t *pHandle) {
+ int ret;
+ int i;
+
+ ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
+ if (lib_init() != 0)
+ return init_status;
+
+ if (pHandle == NULL || uuid == NULL)
+ return -EINVAL;
+
+ for (i = 0; descriptors[i] != NULL; i++) {
+ if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
+ break;
+ }
+
+ if (descriptors[i] == NULL)
+ return -EINVAL;
+
+ effect_context_t *context;
+ if (memcmp(uuid, &equalizer_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)
+ calloc(1, sizeof(equalizer_context_t));
+ context = (effect_context_t *)eq_ctxt;
+ context->ops.init = equalizer_init;
+ context->ops.reset = equalizer_reset;
+ context->ops.set_parameter = equalizer_set_parameter;
+ context->ops.get_parameter = equalizer_get_parameter;
+ context->ops.set_device = equalizer_set_device;
+ context->ops.enable = equalizer_enable;
+ context->ops.disable = equalizer_disable;
+ context->ops.start = equalizer_start;
+ context->ops.stop = equalizer_stop;
+
+ context->desc = &equalizer_descriptor;
+ eq_ctxt->ctl = NULL;
+ } else if (memcmp(uuid, &bassboost_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)
+ calloc(1, sizeof(bassboost_context_t));
+ context = (effect_context_t *)bass_ctxt;
+ context->ops.init = bassboost_init;
+ context->ops.reset = bassboost_reset;
+ context->ops.set_parameter = bassboost_set_parameter;
+ context->ops.get_parameter = bassboost_get_parameter;
+ context->ops.set_device = bassboost_set_device;
+ context->ops.enable = bassboost_enable;
+ context->ops.disable = bassboost_disable;
+ context->ops.start = bassboost_start;
+ context->ops.stop = bassboost_stop;
+
+ context->desc = &bassboost_descriptor;
+ bass_ctxt->ctl = NULL;
+ } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
+ calloc(1, sizeof(virtualizer_context_t));
+ context = (effect_context_t *)virt_ctxt;
+ context->ops.init = virtualizer_init;
+ context->ops.reset = virtualizer_reset;
+ context->ops.set_parameter = virtualizer_set_parameter;
+ context->ops.get_parameter = virtualizer_get_parameter;
+ context->ops.set_device = virtualizer_set_device;
+ context->ops.enable = virtualizer_enable;
+ context->ops.disable = virtualizer_disable;
+ context->ops.start = virtualizer_start;
+ context->ops.stop = virtualizer_stop;
+
+ context->desc = &virtualizer_descriptor;
+ virt_ctxt->ctl = NULL;
+ } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0)) {
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)
+ calloc(1, sizeof(reverb_context_t));
+ context = (effect_context_t *)reverb_ctxt;
+ context->ops.init = reverb_init;
+ context->ops.reset = reverb_reset;
+ context->ops.set_parameter = reverb_set_parameter;
+ context->ops.get_parameter = reverb_get_parameter;
+ context->ops.set_device = reverb_set_device;
+ context->ops.enable = reverb_enable;
+ context->ops.disable = reverb_disable;
+ context->ops.start = reverb_start;
+ context->ops.stop = reverb_stop;
+
+ if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &aux_env_reverb_descriptor;
+ reverb_auxiliary_init(reverb_ctxt);
+ } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &ins_env_reverb_descriptor;
+ reverb_preset_init(reverb_ctxt);
+ } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &aux_preset_reverb_descriptor;
+ reverb_auxiliary_init(reverb_ctxt);
+ } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
+ sizeof(effect_uuid_t)) == 0) {
+ context->desc = &ins_preset_reverb_descriptor;
+ reverb_preset_init(reverb_ctxt);
+ }
+ reverb_ctxt->ctl = NULL;
+ } else {
+ return -EINVAL;
+ }
+
+ context->itfe = &effect_interface;
+ context->state = EFFECT_STATE_UNINITIALIZED;
+ context->out_handle = (audio_io_handle_t)ioId;
+
+ ret = context->ops.init(context);
+ if (ret < 0) {
+ ALOGW("%s init failed", __func__);
+ free(context);
+ return ret;
+ }
+
+ context->state = EFFECT_STATE_INITIALIZED;
+
+ pthread_mutex_lock(&lock);
+ list_add_tail(&created_effects_list, &context->effects_list_node);
+ output_context_t *out_ctxt = get_output(ioId);
+ if (out_ctxt != NULL)
+ add_effect_to_output(out_ctxt, context);
+ pthread_mutex_unlock(&lock);
+
+ *pHandle = (effect_handle_t)context;
+
+ ALOGV("%s created context %p", __func__, context);
+
+ return 0;
+
+}
+
+int effect_lib_release(effect_handle_t handle)
+{
+ effect_context_t *context = (effect_context_t *)handle;
+ int status;
+
+ if (lib_init() != 0)
+ return init_status;
+
+ ALOGV("%s context %p", __func__, handle);
+ pthread_mutex_lock(&lock);
+ status = -EINVAL;
+ if (effect_exists(context)) {
+ output_context_t *out_ctxt = get_output(context->out_handle);
+ if (out_ctxt != NULL)
+ remove_effect_from_output(out_ctxt, context);
+ list_remove(&context->effects_list_node);
+ if (context->ops.release)
+ context->ops.release(context);
+ free(context);
+ status = 0;
+ }
+ pthread_mutex_unlock(&lock);
+
+ return status;
+}
+
+int effect_lib_get_descriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *descriptor)
+{
+ int i;
+
+ if (lib_init() != 0)
+ return init_status;
+
+ if (descriptor == NULL || uuid == NULL) {
+ ALOGV("%s called with NULL pointer", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; descriptors[i] != NULL; i++) {
+ if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
+ *descriptor = *descriptors[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+
+/*
+ * Effect Control Interface Implementation
+ */
+
+/* Stub function for effect interface: never called for offloaded effects */
+int effect_process(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer)
+{
+ effect_context_t * context = (effect_context_t *)self;
+ int status = 0;
+
+ ALOGW("%s Called ?????", __func__);
+
+ pthread_mutex_lock(&lock);
+ if (!effect_exists(context)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (context->state != EFFECT_STATE_ACTIVE) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+exit:
+ pthread_mutex_unlock(&lock);
+ return status;
+}
+
+int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+ void *pCmdData, uint32_t *replySize, void *pReplyData)
+{
+
+ effect_context_t * context = (effect_context_t *)self;
+ int retsize;
+ int status = 0;
+
+ pthread_mutex_lock(&lock);
+
+ if (!effect_exists(context)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ switch (cmdCode) {
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (context->ops.init)
+ *(int *) pReplyData = context->ops.init(context);
+ else
+ *(int *) pReplyData = 0;
+ break;
+ case EFFECT_CMD_SET_CONFIG:
+ if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
+ break;
+ case EFFECT_CMD_GET_CONFIG:
+ if (pReplyData == NULL ||
+ *replySize != sizeof(effect_config_t)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (!context->offload_enabled) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ get_config(context, (effect_config_t *)pReplyData);
+ break;
+ case EFFECT_CMD_RESET:
+ if (context->ops.reset)
+ context->ops.reset(context);
+ break;
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (context->state != EFFECT_STATE_INITIALIZED) {
+ status = -ENOSYS;
+ goto exit;
+ }
+ context->state = EFFECT_STATE_ACTIVE;
+ if (context->ops.enable)
+ context->ops.enable(context);
+ ALOGV("%s EFFECT_CMD_ENABLE", __func__);
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (context->state != EFFECT_STATE_ACTIVE) {
+ status = -ENOSYS;
+ goto exit;
+ }
+ context->state = EFFECT_STATE_INITIALIZED;
+ if (context->ops.disable)
+ context->ops.disable(context);
+ ALOGV("%s EFFECT_CMD_DISABLE", __func__);
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_GET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+ pReplyData == NULL ||
+ *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
+ sizeof(uint16_t))) {
+ status = -EINVAL;
+ ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
+ cmdSize, *replySize);
+ goto exit;
+ }
+ if (!context->offload_enabled) {
+ status = -EINVAL;
+ goto exit;
+ }
+ effect_param_t *q = (effect_param_t *)pCmdData;
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
+ effect_param_t *p = (effect_param_t *)pReplyData;
+ if (context->ops.get_parameter)
+ context->ops.get_parameter(context, p, replySize);
+ } break;
+ case EFFECT_CMD_SET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
+ sizeof(uint16_t)) ||
+ pReplyData == NULL || *replySize != sizeof(int32_t)) {
+ status = -EINVAL;
+ ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
+ cmdSize, *replySize);
+ goto exit;
+ }
+ *(int32_t *)pReplyData = 0;
+ effect_param_t *p = (effect_param_t *)pCmdData;
+ if (context->ops.set_parameter)
+ *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
+ *replySize);
+
+ } break;
+ case EFFECT_CMD_SET_DEVICE: {
+ uint32_t device;
+ ALOGV("\t EFFECT_CMD_SET_DEVICE start");
+ if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
+ status = -EINVAL;
+ ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
+ goto exit;
+ }
+ device = *(uint32_t *)pCmdData;
+ if (context->ops.set_device)
+ context->ops.set_device(context, device);
+ } break;
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+
+ case EFFECT_CMD_OFFLOAD: {
+ output_context_t *out_ctxt;
+
+ if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__);
+ status = -EINVAL;
+ break;
+ }
+
+ effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
+
+ ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
+ offload_param->isOffload, offload_param->ioHandle);
+
+ *(int *)pReplyData = 0;
+
+ context->offload_enabled = offload_param->isOffload;
+ if (context->out_handle == offload_param->ioHandle)
+ break;
+
+ out_ctxt = get_output(context->out_handle);
+ if (out_ctxt != NULL)
+ remove_effect_from_output(out_ctxt, context);
+
+ context->out_handle = offload_param->ioHandle;
+ out_ctxt = get_output(context->out_handle);
+ if (out_ctxt != NULL)
+ add_effect_to_output(out_ctxt, context);
+
+ } break;
+
+
+ default:
+ if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
+ status = context->ops.command(context, cmdCode, cmdSize,
+ pCmdData, replySize, pReplyData);
+ else {
+ ALOGW("%s invalid command %d", __func__, cmdCode);
+ status = -EINVAL;
+ }
+ break;
+ }
+
+exit:
+ pthread_mutex_unlock(&lock);
+
+ return status;
+}
+
+/* Effect Control Interface Implementation: get_descriptor */
+int effect_get_descriptor(effect_handle_t self,
+ effect_descriptor_t *descriptor)
+{
+ effect_context_t *context = (effect_context_t *)self;
+
+ if (!effect_exists(context) || (descriptor == NULL))
+ return -EINVAL;
+
+ *descriptor = *context->desc;
+
+ return 0;
+}
+
+
+/* effect_handle_t interface implementation for offload effects */
+const struct effect_interface_s effect_interface = {
+ effect_process,
+ effect_command,
+ effect_get_descriptor,
+ NULL,
+};
+
+__attribute__ ((visibility ("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+ tag : AUDIO_EFFECT_LIBRARY_TAG,
+ version : EFFECT_LIBRARY_API_VERSION,
+ name : "Offload Effects Bundle Library",
+ implementor : "The Linux Foundation",
+ create_effect : effect_lib_create,
+ release_effect : effect_lib_release,
+ get_descriptor : effect_lib_get_descriptor,
+};
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
new file mode 100644
index 0000000..a8e0f93
--- /dev/null
+++ b/post_proc/bundle.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_EFFECT_BUNDLE_H
+#define OFFLOAD_EFFECT_BUNDLE_H
+
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include "effect_api.h"
+
+/* Retry for delay for mixer open */
+#define RETRY_NUMBER 10
+#define RETRY_US 500000
+
+#define MIXER_CARD 0
+#define SOUND_CARD 0
+
+extern const struct effect_interface_s effect_interface;
+
+typedef struct output_context_s output_context_t;
+typedef struct effect_ops_s effect_ops_t;
+typedef struct effect_context_s effect_context_t;
+
+struct output_context_s {
+ /* node in active_outputs_list */
+ struct listnode outputs_list_node;
+ /* io handle */
+ audio_io_handle_t handle;
+ /* list of effects attached to this output */
+ struct listnode effects_list;
+ /* pcm device id */
+ int pcm_device_id;
+ struct mixer *mixer;
+ struct mixer_ctl *ctl;
+};
+
+/* effect specific operations.
+ * Only the init() and process() operations must be defined.
+ * Others are optional.
+ */
+struct effect_ops_s {
+ int (*init)(effect_context_t *context);
+ int (*release)(effect_context_t *context);
+ int (*reset)(effect_context_t *context);
+ int (*enable)(effect_context_t *context);
+ int (*start)(effect_context_t *context, output_context_t *output);
+ int (*stop)(effect_context_t *context, output_context_t *output);
+ int (*disable)(effect_context_t *context);
+ int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out);
+ int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
+ int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
+ int (*set_device)(effect_context_t *context, uint32_t device);
+ int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize,
+ void *pCmdData, uint32_t *replySize, void *pReplyData);
+};
+
+struct effect_context_s {
+ const struct effect_interface_s *itfe;
+ /* node in created_effects_list */
+ struct listnode effects_list_node;
+ /* node in output_context_t.effects_list */
+ struct listnode output_node;
+ effect_config_t config;
+ const effect_descriptor_t *desc;
+ /* io handle of the output the effect is attached to */
+ audio_io_handle_t out_handle;
+ uint32_t state;
+ bool offload_enabled;
+ effect_ops_t ops;
+};
+
+int set_config(effect_context_t *context, effect_config_t *config);
+
+#endif /* OFFLOAD_EFFECT_BUNDLE_H */
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
new file mode 100644
index 0000000..a2e4f45
--- /dev/null
+++ b/post_proc/effect_api.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "offload_effect_api"
+#define LOG_NDEBUG 0
+
+#include <stdbool.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+
+#include "effect_api.h"
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19
+const int map_eq_opensl_preset_2_offload_preset[] = {
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL, /* Normal Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+1, /* Classical Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+2, /* Dance Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+3, /* Flat Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+4, /* Folk Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+5, /* Heavy Metal Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+6, /* Hip Hop Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+7, /* Jazz Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+8, /* Pop Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+9, /* Rock Preset */
+ OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+10 /* FX Booster */
+};
+
+const int map_reverb_opensl_preset_2_offload_preset
+ [NUM_OSL_REVERB_PRESETS_SUPPORTED][2] = {
+ {1, 15},
+ {2, 16},
+ {3, 17},
+ {4, 18},
+ {5, 3},
+ {6, 20}
+};
+
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+ struct mixer *mixer,
+ struct mixer_ctl *ctl)
+{
+ char mixer_string[128];
+
+ snprintf(mixer_string, sizeof(mixer_string),
+ "%s %d", "Audio Effects Config", device_id);
+ ALOGV("%s: mixer_string: %s", __func__, mixer_string);
+ mixer = mixer_open(card);
+ if (!mixer) {
+ ALOGE("Failed to open mixer");
+ ctl = NULL;
+ return -EINVAL;
+ } else {
+ ctl = mixer_get_ctl_by_name(mixer, mixer_string);
+ if (!ctl) {
+ ALOGE("mixer_get_ctl_by_name failed");
+ mixer_close(mixer);
+ mixer = NULL;
+ return -EINVAL;
+ }
+ }
+ ALOGV("mixer: %p, ctl: %p", mixer, ctl);
+ return 0;
+}
+
+void offload_close_mixer(struct mixer *mixer)
+{
+ mixer_close(mixer);
+}
+
+void offload_bassboost_set_device(struct bass_boost_params *bassboost,
+ uint32_t device)
+{
+ ALOGV("%s", __func__);
+ bassboost->device = device;
+}
+
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+ bool enable)
+{
+ ALOGV("%s", __func__);
+ bassboost->enable_flag = enable;
+}
+
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost)
+{
+ ALOGV("%s", __func__);
+ return bassboost->enable_flag;
+}
+
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+ int strength)
+{
+ ALOGV("%s", __func__);
+ bassboost->strength = strength;
+}
+
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+ int mode)
+{
+ ALOGV("%s", __func__);
+ bassboost->mode = mode;
+}
+
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+ struct bass_boost_params bassboost,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+
+ ALOGV("%s", __func__);
+ *p_param_values++ = BASS_BOOST_MODULE;
+ *p_param_values++ = bassboost.device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) {
+ *p_param_values++ = BASS_BOOST_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN;
+ *p_param_values++ = bassboost.enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) {
+ *p_param_values++ = BASS_BOOST_STRENGTH;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN;
+ *p_param_values++ = bassboost.strength;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) {
+ *p_param_values++ = BASS_BOOST_MODE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN;
+ *p_param_values++ = bassboost.mode;
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
+
+void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
+ uint32_t device)
+{
+ ALOGV("%s", __func__);
+ virtualizer->device = device;
+}
+
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+ bool enable)
+{
+ ALOGV("%s", __func__);
+ virtualizer->enable_flag = enable;
+}
+
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer)
+{
+ ALOGV("%s", __func__);
+ return virtualizer->enable_flag;
+}
+
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+ int strength)
+{
+ ALOGV("%s", __func__);
+ virtualizer->strength = strength;
+}
+
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+ int out_type)
+{
+ ALOGV("%s", __func__);
+ virtualizer->out_type = out_type;
+}
+
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+ int gain_adjust)
+{
+ ALOGV("%s", __func__);
+ virtualizer->gain_adjust = gain_adjust;
+}
+
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+ struct virtualizer_params virtualizer,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+
+ ALOGV("%s", __func__);
+ *p_param_values++ = VIRTUALIZER_MODULE;
+ *p_param_values++ = virtualizer.device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) {
+ *p_param_values++ = VIRTUALIZER_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN;
+ *p_param_values++ = virtualizer.enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) {
+ *p_param_values++ = VIRTUALIZER_STRENGTH;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN;
+ *p_param_values++ = virtualizer.strength;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) {
+ *p_param_values++ = VIRTUALIZER_OUT_TYPE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN;
+ *p_param_values++ = virtualizer.out_type;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) {
+ *p_param_values++ = VIRTUALIZER_GAIN_ADJUST;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN;
+ *p_param_values++ = virtualizer.gain_adjust;
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
+
+void offload_eq_set_device(struct eq_params *eq, uint32_t device)
+{
+ ALOGV("%s", __func__);
+ eq->device = device;
+}
+
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable)
+{
+ ALOGV("%s", __func__);
+ eq->enable_flag = enable;
+}
+
+int offload_eq_get_enable_flag(struct eq_params *eq)
+{
+ ALOGV("%s", __func__);
+ return eq->enable_flag;
+}
+
+void offload_eq_set_preset(struct eq_params *eq, int preset)
+{
+ ALOGV("%s", __func__);
+ eq->config.preset_id = preset;
+ eq->config.eq_pregain = Q27_UNITY;
+}
+
+void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
+ const uint16_t *band_freq_list,
+ int *band_gain_list)
+{
+ int i;
+ ALOGV("%s", __func__);
+ eq->config.num_bands = num_bands;
+ for (i=0; i<num_bands; i++) {
+ eq->per_band_cfg[i].band_idx = i;
+ eq->per_band_cfg[i].filter_type = EQ_BAND_BOOST;
+ eq->per_band_cfg[i].freq_millihertz = band_freq_list[i] * 1000;
+ eq->per_band_cfg[i].gain_millibels = band_gain_list[i] * 100;
+ eq->per_band_cfg[i].quality_factor = Q8_UNITY;
+ }
+}
+
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+ uint32_t i;
+
+ ALOGV("%s", __func__);
+ if (eq.config.preset_id < -1 ) {
+ ALOGV("No Valid preset to set");
+ return 0;
+ }
+ *p_param_values++ = EQ_MODULE;
+ *p_param_values++ = eq.device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) {
+ *p_param_values++ = EQ_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = EQ_ENABLE_PARAM_LEN;
+ *p_param_values++ = eq.enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) {
+ *p_param_values++ = EQ_CONFIG;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = EQ_CONFIG_PARAM_LEN;
+ *p_param_values++ = eq.config.eq_pregain;
+ *p_param_values++ =
+ map_eq_opensl_preset_2_offload_preset[eq.config.preset_id];
+ *p_param_values++ = 0;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_EQ_BANDS_LEVEL) {
+ *p_param_values++ = EQ_CONFIG;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = EQ_CONFIG_PARAM_LEN +
+ eq.config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
+ *p_param_values++ = eq.config.eq_pregain;
+ *p_param_values++ = CUSTOM_OPENSL_PRESET;
+ *p_param_values++ = eq.config.num_bands;
+ for (i=0; i<eq.config.num_bands; i++) {
+ *p_param_values++ = eq.per_band_cfg[i].band_idx;
+ *p_param_values++ = eq.per_band_cfg[i].filter_type;
+ *p_param_values++ = eq.per_band_cfg[i].freq_millihertz;
+ *p_param_values++ = eq.per_band_cfg[i].gain_millibels;
+ *p_param_values++ = eq.per_band_cfg[i].quality_factor;
+ }
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
+
+void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device)
+{
+ ALOGV("%s", __func__);
+ reverb->device = device;
+}
+
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable)
+{
+ ALOGV("%s", __func__);
+ reverb->enable_flag = enable;
+}
+
+int offload_reverb_get_enable_flag(struct reverb_params *reverb)
+{
+ ALOGV("%s", __func__);
+ return reverb->enable_flag;
+}
+
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode)
+{
+ ALOGV("%s", __func__);
+ reverb->mode = mode;
+}
+
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset)
+{
+ ALOGV("%s", __func__);
+ if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED))
+ reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset][1];
+}
+
+void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix)
+{
+ ALOGV("%s", __func__);
+ reverb->wet_mix = wet_mix;
+}
+
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+ int gain_adjust)
+{
+ ALOGV("%s", __func__);
+ reverb->gain_adjust = gain_adjust;
+}
+
+void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level)
+{
+ ALOGV("%s", __func__);
+ reverb->room_level = room_level;
+}
+
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+ int room_hf_level)
+{
+ ALOGV("%s", __func__);
+ reverb->room_hf_level = room_hf_level;
+}
+
+void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time)
+{
+ ALOGV("%s", __func__);
+ reverb->decay_time = decay_time;
+}
+
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+ int decay_hf_ratio)
+{
+ ALOGV("%s", __func__);
+ reverb->decay_hf_ratio = decay_hf_ratio;
+}
+
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+ int reflections_level)
+{
+ ALOGV("%s", __func__);
+ reverb->reflections_level = reflections_level;
+}
+
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+ int reflections_delay)
+{
+ ALOGV("%s", __func__);
+ reverb->reflections_delay = reflections_delay;
+}
+
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+ int reverb_level)
+{
+ ALOGV("%s", __func__);
+ reverb->level = reverb_level;
+}
+
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay)
+{
+ ALOGV("%s", __func__);
+ reverb->delay = delay;
+}
+
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion)
+{
+ ALOGV("%s", __func__);
+ reverb->diffusion = diffusion;
+}
+
+void offload_reverb_set_density(struct reverb_params *reverb, int density)
+{
+ ALOGV("%s", __func__);
+ reverb->density = density;
+}
+
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+ struct reverb_params reverb,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int *p_param_values = param_values;
+
+ ALOGV("%s", __func__);
+ *p_param_values++ = REVERB_MODULE;
+ *p_param_values++ = reverb.device;
+ *p_param_values++ = 0; /* num of commands*/
+
+ if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) {
+ *p_param_values++ = REVERB_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_ENABLE_PARAM_LEN;
+ *p_param_values++ = reverb.enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) {
+ *p_param_values++ = REVERB_MODE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_MODE_PARAM_LEN;
+ *p_param_values++ = reverb.mode;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) {
+ *p_param_values++ = REVERB_PRESET;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_PRESET_PARAM_LEN;
+ *p_param_values++ = reverb.preset;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) {
+ *p_param_values++ = REVERB_WET_MIX;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_WET_MIX_PARAM_LEN;
+ *p_param_values++ = reverb.wet_mix;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) {
+ *p_param_values++ = REVERB_GAIN_ADJUST;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN;
+ *p_param_values++ = reverb.gain_adjust;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) {
+ *p_param_values++ = REVERB_ROOM_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb.room_level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) {
+ *p_param_values++ = REVERB_ROOM_HF_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb.room_hf_level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) {
+ *p_param_values++ = REVERB_DECAY_TIME;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN;
+ *p_param_values++ = reverb.decay_time;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) {
+ *p_param_values++ = REVERB_DECAY_HF_RATIO;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN;
+ *p_param_values++ = reverb.decay_hf_ratio;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) {
+ *p_param_values++ = REVERB_REFLECTIONS_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb.reflections_level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) {
+ *p_param_values++ = REVERB_REFLECTIONS_DELAY;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN;
+ *p_param_values++ = reverb.reflections_delay;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) {
+ *p_param_values++ = REVERB_LEVEL;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_LEVEL_PARAM_LEN;
+ *p_param_values++ = reverb.level;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) {
+ *p_param_values++ = REVERB_DELAY;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DELAY_PARAM_LEN;
+ *p_param_values++ = reverb.delay;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) {
+ *p_param_values++ = REVERB_DIFFUSION;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN;
+ *p_param_values++ = reverb.diffusion;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) {
+ *p_param_values++ = REVERB_DENSITY;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = REVERB_DENSITY_PARAM_LEN;
+ *p_param_values++ = reverb.density;
+ param_values[2] += 1;
+ }
+
+ if (param_values[2] && ctl)
+ mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+ return 0;
+}
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
new file mode 100644
index 0000000..342c606
--- /dev/null
+++ b/post_proc/effect_api.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OFFLOAD_EFFECT_API_H_
+#define OFFLOAD_EFFECT_API_H_
+
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+ struct mixer *mixer,
+ struct mixer_ctl *ctl);
+void offload_close_mixer(struct mixer *mixer);
+
+#define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_BASSBOOST_STRENGTH \
+ (OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_BASSBOOST_MODE \
+ (OFFLOAD_SEND_BASSBOOST_STRENGTH << 1)
+void offload_bassboost_set_device(struct bass_boost_params *bassboost,
+ uint32_t device);
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+ bool enable);
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost);
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+ int strength);
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+ int mode);
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+ struct bass_boost_params bassboost,
+ unsigned param_send_flags);
+
+#define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_VIRTUALIZER_STRENGTH \
+ (OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE \
+ (OFFLOAD_SEND_VIRTUALIZER_STRENGTH << 1)
+#define OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST \
+ (OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE << 1)
+void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
+ uint32_t device);
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+ bool enable);
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer);
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+ int strength);
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+ int out_type);
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+ int gain_adjust);
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+ struct virtualizer_params virtualizer,
+ unsigned param_send_flags);
+
+#define OFFLOAD_SEND_EQ_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_EQ_PRESET \
+ (OFFLOAD_SEND_EQ_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_EQ_BANDS_LEVEL \
+ (OFFLOAD_SEND_EQ_PRESET << 1)
+void offload_eq_set_device(struct eq_params *eq, uint32_t device);
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable);
+int offload_eq_get_enable_flag(struct eq_params *eq);
+void offload_eq_set_preset(struct eq_params *eq, int preset);
+void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
+ const uint16_t *band_freq_list,
+ int *band_gain_list);
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
+ unsigned param_send_flags);
+
+#define OFFLOAD_SEND_REVERB_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_REVERB_MODE \
+ (OFFLOAD_SEND_REVERB_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_REVERB_PRESET \
+ (OFFLOAD_SEND_REVERB_MODE << 1)
+#define OFFLOAD_SEND_REVERB_WET_MIX \
+ (OFFLOAD_SEND_REVERB_PRESET << 1)
+#define OFFLOAD_SEND_REVERB_GAIN_ADJUST \
+ (OFFLOAD_SEND_REVERB_WET_MIX << 1)
+#define OFFLOAD_SEND_REVERB_ROOM_LEVEL \
+ (OFFLOAD_SEND_REVERB_GAIN_ADJUST << 1)
+#define OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL \
+ (OFFLOAD_SEND_REVERB_ROOM_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DECAY_TIME \
+ (OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DECAY_HF_RATIO \
+ (OFFLOAD_SEND_REVERB_DECAY_TIME << 1)
+#define OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL \
+ (OFFLOAD_SEND_REVERB_DECAY_HF_RATIO << 1)
+#define OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY \
+ (OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_LEVEL \
+ (OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY << 1)
+#define OFFLOAD_SEND_REVERB_DELAY \
+ (OFFLOAD_SEND_REVERB_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DIFFUSION \
+ (OFFLOAD_SEND_REVERB_DELAY << 1)
+#define OFFLOAD_SEND_REVERB_DENSITY \
+ (OFFLOAD_SEND_REVERB_DIFFUSION << 1)
+void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device);
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable);
+int offload_reverb_get_enable_flag(struct reverb_params *reverb);
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode);
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset);
+void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix);
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+ int gain_adjust);
+void offload_reverb_set_room_level(struct reverb_params *reverb,
+ int room_level);
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+ int room_hf_level);
+void offload_reverb_set_decay_time(struct reverb_params *reverb,
+ int decay_time);
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+ int decay_hf_ratio);
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+ int reflections_level);
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+ int reflections_delay);
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+ int reverb_level);
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay);
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion);
+void offload_reverb_set_density(struct reverb_params *reverb, int density);
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+ struct reverb_params reverb,
+ unsigned param_send_flags);
+
+#endif /*OFFLOAD_EFFECT_API_H_*/
diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
new file mode 100644
index 0000000..e31d2b9
--- /dev/null
+++ b/post_proc/equalizer.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 "offload_effect_equalizer"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_equalizer.h>
+
+#include "effect_api.h"
+#include "equalizer.h"
+
+/* Offload equalizer UUID: a0dac280-401c-11e3-9379-0002a5d5c51b */
+const effect_descriptor_t equalizer_descriptor = {
+ {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+ {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload equalizer",
+ "The Android Open Source Project",
+};
+
+static const char *equalizer_preset_names[] = {
+ "Normal",
+ "Classical",
+ "Dance",
+ "Flat",
+ "Folk",
+ "Heavy Metal",
+ "Hip Hop",
+ "Jazz",
+ "Pop",
+ "Rock"
+ };
+
+static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = {
+ {30000, 120000},
+ {120001, 460000},
+ {460001, 1800000},
+ {1800001, 7000000},
+ {7000001, 20000000}};
+
+static const uint16_t equalizer_band_presets_level[] = {
+ 3, 0, 0, 0, 3, /* Normal Preset */
+ 5, 3, -2, 4, 4, /* Classical Preset */
+ 6, 0, 2, 4, 1, /* Dance Preset */
+ 0, 0, 0, 0, 0, /* Flat Preset */
+ 3, 0, 0, 2, -1, /* Folk Preset */
+ 4, 1, 9, 3, 0, /* Heavy Metal Preset */
+ 5, 3, 0, 1, 3, /* Hip Hop Preset */
+ 4, 2, -2, 2, 5, /* Jazz Preset */
+ -1, 2, 5, 1, -2, /* Pop Preset */
+ 5, 3, -1, 3, 5}; /* Rock Preset */
+
+const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = {
+ 60, /* Frequencies in Hz */
+ 230,
+ 910,
+ 3600,
+ 14000
+};
+
+/*
+ * Equalizer operations
+ */
+
+int equalizer_get_band_level(equalizer_context_t *context, int32_t band)
+{
+ ALOGV("%s: band: %d level: %d", __func__, band,
+ context->band_levels[band] * 100);
+ return context->band_levels[band] * 100;
+}
+
+int equalizer_set_band_level(equalizer_context_t *context, int32_t band,
+ int32_t level)
+{
+ ALOGV("%s: band: %d, level: %d", __func__, band, level);
+ if (level > 0) {
+ level = (int)((level+50)/100);
+ } else {
+ level = (int)((level-50)/100);
+ }
+ context->band_levels[band] = level;
+ context->preset = PRESET_CUSTOM;
+
+ offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM);
+ offload_eq_set_bands_level(&(context->offload_eq),
+ NUM_EQ_BANDS,
+ equalizer_band_presets_freq,
+ context->band_levels);
+ if (context->ctl)
+ offload_eq_send_params(context->ctl, context->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_BANDS_LEVEL);
+ return 0;
+}
+
+int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band)
+{
+ ALOGV("%s: band: %d", __func__, band);
+ return (equalizer_band_freq_range[band][0] +
+ equalizer_band_freq_range[band][1]) / 2;
+}
+
+int equalizer_get_band_freq_range(equalizer_context_t *context, int32_t band,
+ uint32_t *low, uint32_t *high)
+{
+ ALOGV("%s: band: %d", __func__, band);
+ *low = equalizer_band_freq_range[band][0];
+ *high = equalizer_band_freq_range[band][1];
+ return 0;
+}
+
+int equalizer_get_band(equalizer_context_t *context, uint32_t freq)
+{
+ int i;
+
+ ALOGV("%s: freq: %d", __func__, freq);
+ for(i = 0; i < NUM_EQ_BANDS; i++) {
+ if (freq <= equalizer_band_freq_range[i][1]) {
+ return i;
+ }
+ }
+ return NUM_EQ_BANDS - 1;
+}
+
+int equalizer_get_preset(equalizer_context_t *context)
+{
+ ALOGV("%s: preset: %d", __func__, context->preset);
+ return context->preset;
+}
+
+int equalizer_set_preset(equalizer_context_t *context, int preset)
+{
+ int i;
+
+ ALOGV("%s: preset: %d", __func__, preset);
+ context->preset = preset;
+ for (i=0; i<NUM_EQ_BANDS; i++)
+ context->band_levels[i] =
+ equalizer_band_presets_level[i + preset * NUM_EQ_BANDS];
+
+ offload_eq_set_preset(&(context->offload_eq), preset);
+ offload_eq_set_bands_level(&(context->offload_eq),
+ NUM_EQ_BANDS,
+ equalizer_band_presets_freq,
+ context->band_levels);
+ if(context->ctl)
+ offload_eq_send_params(context->ctl, context->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_PRESET);
+ return 0;
+}
+
+const char * equalizer_get_preset_name(equalizer_context_t *context,
+ int32_t preset)
+{
+ ALOGV("%s: preset: %s", __func__, equalizer_preset_names[preset]);
+ if (preset == PRESET_CUSTOM) {
+ return "Custom";
+ } else {
+ return equalizer_preset_names[preset];
+ }
+}
+
+int equalizer_get_num_presets(equalizer_context_t *context)
+{
+ ALOGV("%s: presets_num: %d", __func__,
+ sizeof(equalizer_preset_names)/sizeof(char *));
+ return sizeof(equalizer_preset_names)/sizeof(char *);
+}
+
+int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ int32_t param2;
+ char *name;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case EQ_PARAM_NUM_BANDS:
+ case EQ_PARAM_CUR_PRESET:
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ case EQ_PARAM_BAND_LEVEL:
+ case EQ_PARAM_GET_BAND:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ if (p->vsize < 2 * sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = 2 * sizeof(int16_t);
+ break;
+ case EQ_PARAM_BAND_FREQ_RANGE:
+ if (p->vsize < 2 * sizeof(int32_t))
+ p->status = -EINVAL;
+ p->vsize = 2 * sizeof(int32_t);
+ break;
+
+ case EQ_PARAM_CENTER_FREQ:
+ if (p->vsize < sizeof(int32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int32_t);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ break;
+
+ case EQ_PARAM_PROPERTIES:
+ if (p->vsize < (2 + NUM_EQ_BANDS) * sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = (2 + NUM_EQ_BANDS) * sizeof(uint16_t);
+ break;
+
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case EQ_PARAM_NUM_BANDS:
+ ALOGV("%s: EQ_PARAM_NUM_BANDS", __func__);
+ *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS;
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ ALOGV("%s: EQ_PARAM_LEVEL_RANGE", __func__);
+ *(int16_t *)value = -1500;
+ *((int16_t *)value + 1) = 1500;
+ break;
+
+ case EQ_PARAM_BAND_LEVEL:
+ ALOGV("%s: EQ_PARAM_BAND_LEVEL", __func__);
+ param2 = *param_tmp;
+ if (param2 >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ *(int16_t *)value = (int16_t)equalizer_get_band_level(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_CENTER_FREQ:
+ ALOGV("%s: EQ_PARAM_CENTER_FREQ", __func__);
+ param2 = *param_tmp;
+ if (param2 >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ *(int32_t *)value = equalizer_get_center_frequency(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_BAND_FREQ_RANGE:
+ ALOGV("%s: EQ_PARAM_BAND_FREQ_RANGE", __func__);
+ param2 = *param_tmp;
+ if (param2 >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ equalizer_get_band_freq_range(eq_ctxt, param2, (uint32_t *)value,
+ ((uint32_t *)value + 1));
+ break;
+
+ case EQ_PARAM_GET_BAND:
+ ALOGV("%s: EQ_PARAM_GET_BAND", __func__);
+ param2 = *param_tmp;
+ *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_CUR_PRESET:
+ ALOGV("%s: EQ_PARAM_CUR_PRESET", __func__);
+ *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt);
+ break;
+
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ ALOGV("%s: EQ_PARAM_GET_NUM_OF_PRESETS", __func__);
+ *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ ALOGV("%s: EQ_PARAM_GET_PRESET_NAME", __func__);
+ param2 = *param_tmp;
+ ALOGV("param2: %d", param2);
+ if (param2 >= equalizer_get_num_presets(eq_ctxt)) {
+ p->status = -EINVAL;
+ break;
+ }
+ name = (char *)value;
+ strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1);
+ name[p->vsize - 1] = 0;
+ p->vsize = strlen(name) + 1;
+ break;
+
+ case EQ_PARAM_PROPERTIES: {
+ ALOGV("%s: EQ_PARAM_PROPERTIES", __func__);
+ int16_t *prop = (int16_t *)value;
+ prop[0] = (int16_t)equalizer_get_preset(eq_ctxt);
+ prop[1] = (int16_t)NUM_EQ_BANDS;
+ for (i = 0; i < NUM_EQ_BANDS; i++) {
+ prop[2 + i] = (int16_t)equalizer_get_band_level(eq_ctxt, i);
+ }
+ } break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ int32_t preset;
+ int32_t band;
+ int32_t level;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case EQ_PARAM_CUR_PRESET:
+ ALOGV("EQ_PARAM_CUR_PRESET");
+ preset = (int32_t)(*(uint16_t *)value);
+
+ if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) {
+ p->status = -EINVAL;
+ break;
+ }
+ equalizer_set_preset(eq_ctxt, preset);
+ break;
+ case EQ_PARAM_BAND_LEVEL:
+ ALOGV("EQ_PARAM_BAND_LEVEL");
+ band = *param_tmp;
+ level = (int32_t)(*(int16_t *)value);
+ if (band >= NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ equalizer_set_band_level(eq_ctxt, band, level);
+ break;
+ case EQ_PARAM_PROPERTIES: {
+ ALOGV("EQ_PARAM_PROPERTIES");
+ int16_t *prop = (int16_t *)value;
+ if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) {
+ p->status = -EINVAL;
+ break;
+ }
+ if (prop[0] >= 0) {
+ equalizer_set_preset(eq_ctxt, (int)prop[0]);
+ } else {
+ if ((int)prop[1] != NUM_EQ_BANDS) {
+ p->status = -EINVAL;
+ break;
+ }
+ for (i = 0; i < NUM_EQ_BANDS; i++) {
+ equalizer_set_band_level(eq_ctxt, i, (int)prop[2 + i]);
+ }
+ }
+ } break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int equalizer_set_device(effect_context_t *context, uint32_t device)
+{
+ ALOGV("%s: device: %d", __func__, device);
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+ eq_ctxt->device = device;
+ offload_eq_set_device(&(eq_ctxt->offload_eq), device);
+ return 0;
+}
+
+int equalizer_reset(effect_context_t *context)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ return 0;
+}
+
+int equalizer_init(effect_context_t *context)
+{
+ ALOGV("%s", __func__);
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params));
+ offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET);
+
+ return 0;
+}
+
+int equalizer_enable(effect_context_t *context)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
+ offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true);
+ if (eq_ctxt->ctl)
+ offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG |
+ OFFLOAD_SEND_EQ_BANDS_LEVEL);
+ }
+ return 0;
+}
+
+int equalizer_disable(effect_context_t *context)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
+ offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false);
+ if (eq_ctxt->ctl)
+ offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+ OFFLOAD_SEND_EQ_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int equalizer_start(effect_context_t *context, output_context_t *output)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s: %p", __func__, output->ctl);
+ eq_ctxt->ctl = output->ctl;
+ return 0;
+}
+
+int equalizer_stop(effect_context_t *context, output_context_t *output)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ eq_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h
new file mode 100644
index 0000000..19af186
--- /dev/null
+++ b/post_proc/equalizer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_EQUALIZER_H_
+#define OFFLOAD_EQUALIZER_H_
+
+#include "bundle.h"
+
+#define NUM_EQ_BANDS 5
+#define INVALID_PRESET -2
+#define PRESET_CUSTOM -1
+
+extern const effect_descriptor_t equalizer_descriptor;
+
+typedef struct equalizer_context_s {
+ effect_context_t common;
+
+ int preset;
+ int band_levels[NUM_EQ_BANDS];
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ uint32_t device;
+ struct eq_params offload_eq;
+} equalizer_context_t;
+
+int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int equalizer_set_device(effect_context_t *context, uint32_t device);
+
+int equalizer_reset(effect_context_t *context);
+
+int equalizer_init(effect_context_t *context);
+
+int equalizer_enable(effect_context_t *context);
+
+int equalizer_disable(effect_context_t *context);
+
+int equalizer_start(effect_context_t *context, output_context_t *output);
+
+int equalizer_stop(effect_context_t *context, output_context_t *output);
+
+#endif /*OFFLOAD_EQUALIZER_H_*/
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
new file mode 100644
index 0000000..4fc8c83
--- /dev/null
+++ b/post_proc/reverb.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 "offload_effect_reverb"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_environmentalreverb.h>
+#include <audio_effects/effect_presetreverb.h>
+
+#include "effect_api.h"
+#include "reverb.h"
+
+/* Offload auxiliary environmental reverb UUID: 79a18026-18fd-4185-8233-0002a5d5c51b */
+const effect_descriptor_t aux_env_reverb_descriptor = {
+ { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
+ { 0x79a18026, 0x18fd, 0x4185, 0x8233, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Auxiliary Environmental Reverb",
+ "The Android Open Source Project",
+};
+
+/* Offload insert environmental reverb UUID: eb64ea04-973b-43d2-8f5e-0002a5d5c51b */
+const effect_descriptor_t ins_env_reverb_descriptor = {
+ {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+ {0xeb64ea04, 0x973b, 0x43d2, 0x8f5e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Insert Environmental Reverb",
+ "The Android Open Source Project",
+};
+
+// Offload auxiliary preset reverb UUID: 6987be09-b142-4b41-9056-0002a5d5c51b */
+const effect_descriptor_t aux_preset_reverb_descriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x6987be09, 0xb142, 0x4b41, 0x9056, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Auxiliary Preset Reverb",
+ "The Android Open Source Project",
+};
+
+// Offload insert preset reverb UUID: aa2bebf6-47cf-4613-9bca-0002a5d5c51b */
+const effect_descriptor_t ins_preset_reverb_descriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0xaa2bebf6, 0x47cf, 0x4613, 0x9bca, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload Insert Preset Reverb",
+ "The Android Open Source Project",
+};
+
+static const reverb_settings_t reverb_presets[] = {
+ // REVERB_PRESET_NONE: values are unused
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ // REVERB_PRESET_SMALLROOM
+ {-400, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000},
+ // REVERB_PRESET_MEDIUMROOM
+ {-400, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000},
+ // REVERB_PRESET_LARGEROOM
+ {-400, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000},
+ // REVERB_PRESET_MEDIUMHALL
+ {-400, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000},
+ // REVERB_PRESET_LARGEHALL
+ {-400, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000},
+ // REVERB_PRESET_PLATE
+ {-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750},
+};
+
+
+void reverb_auxiliary_init(reverb_context_t *context)
+{
+ context->auxiliary = true;
+ context->preset = false;
+}
+
+void reverb_preset_init(reverb_context_t *context)
+{
+ context->auxiliary = false;
+ context->preset = true;
+ context->cur_preset = REVERB_PRESET_LAST + 1;
+ context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
+/*
+ * Reverb operations
+ */
+int16_t reverb_get_room_level(reverb_context_t *context)
+{
+ ALOGV("%s: room level: %d", __func__, context->reverb_settings.roomLevel);
+ return context->reverb_settings.roomLevel;
+}
+
+void reverb_set_room_level(reverb_context_t *context, int16_t room_level)
+{
+ ALOGV("%s: room level: %d", __func__, room_level);
+ context->reverb_settings.roomLevel = room_level;
+ offload_reverb_set_room_level(&(context->offload_reverb), room_level);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_ROOM_LEVEL);
+}
+
+int16_t reverb_get_room_hf_level(reverb_context_t *context)
+{
+ ALOGV("%s: room hf level: %d", __func__,
+ context->reverb_settings.roomHFLevel);
+ return context->reverb_settings.roomHFLevel;
+}
+
+void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level)
+{
+ ALOGV("%s: room hf level: %d", __func__, room_hf_level);
+ context->reverb_settings.roomHFLevel = room_hf_level;
+ offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL);
+}
+
+uint32_t reverb_get_decay_time(reverb_context_t *context)
+{
+ ALOGV("%s: decay time: %d", __func__, context->reverb_settings.decayTime);
+ return context->reverb_settings.decayTime;
+}
+
+void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time)
+{
+ ALOGV("%s: decay_time: %d", __func__, decay_time);
+ context->reverb_settings.decayTime = decay_time;
+ offload_reverb_set_decay_time(&(context->offload_reverb), decay_time);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DECAY_TIME);
+}
+
+int16_t reverb_get_decay_hf_ratio(reverb_context_t *context)
+{
+ ALOGV("%s: decay hf ratio: %d", __func__,
+ context->reverb_settings.decayHFRatio);
+ return context->reverb_settings.decayHFRatio;
+}
+
+void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio)
+{
+ ALOGV("%s: decay_hf_ratio: %d", __func__, decay_hf_ratio);
+ context->reverb_settings.decayHFRatio = decay_hf_ratio;
+ offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DECAY_HF_RATIO);
+}
+
+int16_t reverb_get_reverb_level(reverb_context_t *context)
+{
+ ALOGV("%s: reverb level: %d", __func__, context->reverb_settings.reverbLevel);
+ return context->reverb_settings.reverbLevel;
+}
+
+void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level)
+{
+ ALOGV("%s: reverb level: %d", __func__, reverb_level);
+ context->reverb_settings.reverbLevel = reverb_level;
+ offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_LEVEL);
+}
+
+int16_t reverb_get_diffusion(reverb_context_t *context)
+{
+ ALOGV("%s: diffusion: %d", __func__, context->reverb_settings.diffusion);
+ return context->reverb_settings.diffusion;
+}
+
+void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion)
+{
+ ALOGV("%s: diffusion: %d", __func__, diffusion);
+ context->reverb_settings.diffusion = diffusion;
+ offload_reverb_set_diffusion(&(context->offload_reverb), diffusion);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DIFFUSION);
+}
+
+int16_t reverb_get_density(reverb_context_t *context)
+{
+ ALOGV("%s: density: %d", __func__, context->reverb_settings.density);
+ return context->reverb_settings.density;
+}
+
+void reverb_set_density(reverb_context_t *context, int16_t density)
+{
+ ALOGV("%s: density: %d", __func__, density);
+ context->reverb_settings.density = density;
+ offload_reverb_set_density(&(context->offload_reverb), density);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_DENSITY);
+}
+
+void reverb_set_preset(reverb_context_t *context, int16_t preset)
+{
+ ALOGV("%s: preset: %d", __func__, preset);
+ context->next_preset = preset;
+ offload_reverb_set_preset(&(context->offload_reverb), preset);
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_PRESET);
+}
+
+void reverb_set_all_properties(reverb_context_t *context,
+ reverb_settings_t *reverb_settings)
+{
+ ALOGV("%s", __func__);
+ context->reverb_settings.roomLevel = reverb_settings->roomLevel;
+ context->reverb_settings.roomHFLevel = reverb_settings->roomHFLevel;
+ context->reverb_settings.decayTime = reverb_settings->decayTime;
+ context->reverb_settings.decayHFRatio = reverb_settings->decayHFRatio;
+ context->reverb_settings.reverbLevel = reverb_settings->reverbLevel;
+ context->reverb_settings.diffusion = reverb_settings->diffusion;
+ context->reverb_settings.density = reverb_settings->density;
+ if (context->ctl)
+ offload_reverb_send_params(context->ctl, context->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+ OFFLOAD_SEND_REVERB_ROOM_LEVEL |
+ OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
+ OFFLOAD_SEND_REVERB_DECAY_TIME |
+ OFFLOAD_SEND_REVERB_DECAY_HF_RATIO |
+ OFFLOAD_SEND_REVERB_LEVEL |
+ OFFLOAD_SEND_REVERB_DIFFUSION |
+ OFFLOAD_SEND_REVERB_DENSITY);
+}
+
+void reverb_load_preset(reverb_context_t *context)
+{
+ context->cur_preset = context->next_preset;
+
+ if (context->cur_preset != REVERB_PRESET_NONE) {
+ const reverb_settings_t *preset = &reverb_presets[context->cur_preset];
+ reverb_set_room_level(context, preset->roomLevel);
+ reverb_set_room_hf_level(context, preset->roomHFLevel);
+ reverb_set_decay_time(context, preset->decayTime);
+ reverb_set_decay_hf_ratio(context, preset->decayHFRatio);
+ reverb_set_reverb_level(context, preset->reverbLevel);
+ reverb_set_diffusion(context, preset->diffusion);
+ reverb_set_density(context, preset->density);
+ }
+}
+
+int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ reverb_settings_t *reverb_settings;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ if (reverb_ctxt->preset) {
+ if (param != REVERB_PARAM_PRESET || p->vsize < sizeof(uint16_t))
+ return -EINVAL;
+ *(uint16_t *)value = reverb_ctxt->next_preset;
+ ALOGV("get REVERB_PARAM_PRESET, preset %d", reverb_ctxt->next_preset);
+ }
+ switch (param) {
+ case REVERB_PARAM_ROOM_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_REVERB_DELAY:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_DENSITY:
+ if (p->vsize < sizeof(uint16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint16_t);
+ break;
+ case REVERB_PARAM_PROPERTIES:
+ if (p->vsize < sizeof(reverb_settings_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(reverb_settings_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case REVERB_PARAM_PROPERTIES:
+ ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+ reverb_settings = (reverb_settings_t *)value;
+ reverb_settings->roomLevel = reverb_get_room_level(reverb_ctxt);
+ reverb_settings->roomHFLevel = reverb_get_room_hf_level(reverb_ctxt);
+ reverb_settings->decayTime = reverb_get_decay_time(reverb_ctxt);
+ reverb_settings->decayHFRatio = reverb_get_decay_hf_ratio(reverb_ctxt);
+ reverb_settings->reflectionsLevel = 0;
+ reverb_settings->reflectionsDelay = 0;
+ reverb_settings->reverbDelay = 0;
+ reverb_settings->reverbLevel = reverb_get_reverb_level(reverb_ctxt);
+ reverb_settings->diffusion = reverb_get_diffusion(reverb_ctxt);
+ reverb_settings->density = reverb_get_density(reverb_ctxt);
+ break;
+ case REVERB_PARAM_ROOM_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_room_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+ *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+ *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+ *(int16_t *)value = reverb_get_diffusion(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DENSITY:
+ ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+ *(int16_t *)value = reverb_get_density(reverb_ctxt);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REFLECTIONS_LEVEL", __func__);
+ *(uint16_t *)value = 0;
+ break;
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ ALOGV("%s: REVERB_PARAM_REFLECTIONS_DELAY", __func__);
+ *(uint32_t *)value = 0;
+ break;
+ case REVERB_PARAM_REVERB_DELAY:
+ ALOGV("%s: REVERB_PARAM_REVERB_DELAY", __func__);
+ *(uint32_t *)value = 0;
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ reverb_settings_t *reverb_settings;
+ int16_t level;
+ int16_t ratio;
+ uint32_t time;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ if (reverb_ctxt->preset) {
+ if (param != REVERB_PARAM_PRESET)
+ return -EINVAL;
+ uint16_t preset = *(uint16_t *)value;
+ ALOGV("set REVERB_PARAM_PRESET, preset %d", preset);
+ if (preset > REVERB_PRESET_LAST) {
+ return -EINVAL;
+ }
+ reverb_set_preset(reverb_ctxt, preset);
+ }
+ switch (param) {
+ case REVERB_PARAM_PROPERTIES:
+ ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+ reverb_settings = (reverb_settings_t *)value;
+ break;
+ case REVERB_PARAM_ROOM_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_room_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_room_hf_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+ time = *(uint32_t *)value;
+ reverb_set_decay_time(reverb_ctxt, time);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_decay_hf_ratio(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_reverb_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_diffusion(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_DENSITY:
+ ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_density(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ case REVERB_PARAM_REVERB_DELAY:
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int reverb_set_device(effect_context_t *context, uint32_t device)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s: device: %d", __func__, device);
+ reverb_ctxt->device = device;
+ offload_reverb_set_device(&(reverb_ctxt->offload_reverb), device);
+ return 0;
+}
+
+int reverb_reset(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ return 0;
+}
+
+int reverb_init(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ /*
+ FIXME: channel mode is mono for auxiliary. is it needed for offload ?
+ If so, this set config needs to be updated accordingly
+ */
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t));
+ memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params));
+
+ if (reverb_ctxt->preset &&
+ reverb_ctxt->next_preset != reverb_ctxt->cur_preset)
+ reverb_load_preset(reverb_ctxt);
+
+ return 0;
+}
+
+int reverb_enable(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb)))
+ offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true);
+ return 0;
+}
+
+int reverb_disable(effect_context_t *context)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
+ offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false);
+ if (reverb_ctxt->ctl)
+ offload_reverb_send_params(reverb_ctxt->ctl,
+ reverb_ctxt->offload_reverb,
+ OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int reverb_start(effect_context_t *context, output_context_t *output)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ reverb_ctxt->ctl = output->ctl;
+ return 0;
+}
+
+int reverb_stop(effect_context_t *context, output_context_t *output)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ reverb_ctxt->ctl = NULL;
+ return 0;
+}
+
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
new file mode 100644
index 0000000..63192eb
--- /dev/null
+++ b/post_proc/reverb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_REVERB_H_
+#define OFFLOAD_REVERB_H_
+
+#include "bundle.h"
+
+#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE
+
+extern const effect_descriptor_t aux_env_reverb_descriptor;
+extern const effect_descriptor_t ins_env_reverb_descriptor;
+extern const effect_descriptor_t aux_preset_reverb_descriptor;
+extern const effect_descriptor_t ins_preset_reverb_descriptor;
+
+typedef struct reverb_settings_s {
+ int16_t roomLevel;
+ int16_t roomHFLevel;
+ uint32_t decayTime;
+ int16_t decayHFRatio;
+ int16_t reflectionsLevel;
+ uint32_t reflectionsDelay;
+ int16_t reverbLevel;
+ uint32_t reverbDelay;
+ int16_t diffusion;
+ int16_t density;
+} reverb_settings_t;
+
+typedef struct reverb_context_s {
+ effect_context_t common;
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ bool auxiliary;
+ bool preset;
+ uint16_t cur_preset;
+ uint16_t next_preset;
+ reverb_settings_t reverb_settings;
+ uint32_t device;
+ struct reverb_params offload_reverb;
+} reverb_context_t;
+
+
+void reverb_auxiliary_init(reverb_context_t *context);
+
+void reverb_preset_init(reverb_context_t *context);
+
+int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int reverb_set_device(effect_context_t *context, uint32_t device);
+
+int reverb_reset(effect_context_t *context);
+
+int reverb_init(effect_context_t *context);
+
+int reverb_enable(effect_context_t *context);
+
+int reverb_disable(effect_context_t *context);
+
+int reverb_start(effect_context_t *context, output_context_t *output);
+
+int reverb_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_REVERB_H_ */
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
new file mode 100644
index 0000000..2f0ca6b
--- /dev/null
+++ b/post_proc/virtualizer.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 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 "offload_effect_virtualizer"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_virtualizer.h>
+
+#include "effect_api.h"
+#include "virtualizer.h"
+
+/* Offload Virtualizer UUID: 509a4498-561a-4bea-b3b1-0002a5d5c51b */
+const effect_descriptor_t virtualizer_descriptor = {
+ {0x37cc2c00, 0xdddd, 0x11db, 0x8577, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x509a4498, 0x561a, 0x4bea, 0xb3b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+ 0, /* TODO */
+ 1,
+ "MSM offload virtualizer",
+ "The Android Open Source Project",
+};
+
+/*
+ * Virtualizer operations
+ */
+
+int virtualizer_get_strength(virtualizer_context_t *context)
+{
+ ALOGV("%s: strength: %d", __func__, context->strength);
+ return context->strength;
+}
+
+int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength)
+{
+ ALOGV("%s: strength: %d", __func__, strength);
+ context->strength = strength;
+
+ offload_virtualizer_set_strength(&(context->offload_virt), strength);
+ if (context->ctl)
+ offload_virtualizer_send_params(context->ctl, context->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+ OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+ return 0;
+}
+
+int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case VIRTUALIZER_PARAM_STRENGTH:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
+ ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH_SUPPORTED", __func__);
+ *(uint32_t *)value = 1;
+ break;
+
+ case VIRTUALIZER_PARAM_STRENGTH:
+ ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH", __func__);
+ *(int16_t *)value = virtualizer_get_strength(virt_ctxt);
+ break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ uint32_t strength;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH:
+ ALOGV("%s VIRTUALIZER_PARAM_STRENGTH", __func__);
+ strength = (uint32_t)(*(int16_t *)value);
+ virtualizer_set_strength(virt_ctxt, strength);
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int virtualizer_set_device(effect_context_t *context, uint32_t device)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s: device: %d", __func__, device);
+ virt_ctxt->device = device;
+ if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
+ if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+ virt_ctxt->temp_disabled = true;
+ }
+ } else {
+ if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) &&
+ virt_ctxt->temp_disabled) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+ virt_ctxt->temp_disabled = false;
+ }
+ }
+ offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device);
+ return 0;
+}
+
+int virtualizer_reset(effect_context_t *context)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ return 0;
+}
+
+int virtualizer_init(effect_context_t *context)
+{
+ ALOGV("%s", __func__);
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
+
+ return 0;
+}
+
+int virtualizer_enable(effect_context_t *context)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+ return 0;
+}
+
+int virtualizer_disable(effect_context_t *context)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int virtualizer_start(effect_context_t *context, output_context_t *output)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ virt_ctxt->ctl = output->ctl;
+ return 0;
+}
+
+int virtualizer_stop(effect_context_t *context, output_context_t *output)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ virt_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
new file mode 100644
index 0000000..4a5005f
--- /dev/null
+++ b/post_proc/virtualizer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_VIRTUALIZER_H_
+#define OFFLOAD_VIRTUALIZER_H_
+
+#include "bundle.h"
+
+extern const effect_descriptor_t virtualizer_descriptor;
+
+typedef struct virtualizer_context_s {
+ effect_context_t common;
+
+ int strength;
+
+ // Offload vars
+ struct mixer_ctl *ctl;
+ bool temp_disabled;
+ uint32_t device;
+ struct virtualizer_params offload_virt;
+} virtualizer_context_t;
+
+int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int virtualizer_set_device(effect_context_t *context, uint32_t device);
+
+int virtualizer_reset(effect_context_t *context);
+
+int virtualizer_init(effect_context_t *context);
+
+int virtualizer_enable(effect_context_t *context);
+
+int virtualizer_disable(effect_context_t *context);
+
+int virtualizer_start(effect_context_t *context, output_context_t *output);
+
+int virtualizer_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_VIRTUALIZER_H_ */
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index eb43558..95b4687 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -37,6 +37,7 @@
};
typedef struct effect_context_s effect_context_t;
+typedef struct output_context_s output_context_t;
/* effect specific operations. Only the init() and process() operations must be defined.
* Others are optional.
@@ -47,6 +48,8 @@
int (*reset)(effect_context_t *context);
int (*enable)(effect_context_t *context);
int (*disable)(effect_context_t *context);
+ int (*start)(effect_context_t *context, output_context_t *output);
+ int (*stop)(effect_context_t *context, output_context_t *output);
int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out);
int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
@@ -247,6 +250,8 @@
return;
}
list_add_tail(&output->effects_list, &context->output_node);
+ if (context->ops.start)
+ context->ops.start(context, output);
}
void remove_effect_from_output(output_context_t * output, effect_context_t *context) {
@@ -257,6 +262,8 @@
effect_context_t,
output_node);
if (fx_ctxt == context) {
+ if (context->ops.stop)
+ context->ops.stop(context, output);
list_remove(&context->output_node);
return;
}
@@ -276,7 +283,7 @@
effect_context_t *fx_ctxt = node_to_item(fx_node,
effect_context_t,
output_node);
- if (fx_ctxt->state == EFFECT_STATE_ACTIVE)
+ if (fx_ctxt->state == EFFECT_STATE_ACTIVE && fx_ctxt->ops.process != NULL)
return true;
}
}
@@ -379,7 +386,8 @@
effect_context_t *fx_ctxt = node_to_item(fx_node,
effect_context_t,
output_node);
- fx_ctxt->ops.process(fx_ctxt, &buf, &buf);
+ if (fx_ctxt->ops.process != NULL)
+ fx_ctxt->ops.process(fx_ctxt, &buf, &buf);
}
}
} else {
@@ -405,11 +413,11 @@
*/
__attribute__ ((visibility ("default")))
-int visualizer_hal_start_output(audio_io_handle_t output) {
+int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) {
int ret;
struct listnode *node;
- ALOGV("%s", __func__);
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
if (lib_init() != 0)
return init_status;
@@ -431,6 +439,8 @@
effect_context_t,
effects_list_node);
if (fx_ctxt->out_handle == output) {
+ if (fx_ctxt->ops.start)
+ fx_ctxt->ops.start(fx_ctxt, out_ctxt);
list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
}
}
@@ -449,12 +459,13 @@
}
__attribute__ ((visibility ("default")))
-int visualizer_hal_stop_output(audio_io_handle_t output) {
+int visualizer_hal_stop_output(audio_io_handle_t output, int pcm_id) {
int ret;
struct listnode *node;
+ struct listnode *fx_node;
output_context_t *out_ctxt;
- ALOGV("%s", __func__);
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
if (lib_init() != 0)
return init_status;
@@ -468,7 +479,13 @@
ret = -ENOSYS;
goto exit;
}
-
+ list_for_each(fx_node, &out_ctxt->effects_list) {
+ effect_context_t *fx_ctxt = node_to_item(fx_node,
+ effect_context_t,
+ output_node);
+ if (fx_ctxt->ops.stop)
+ fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
+ }
list_remove(&out_ctxt->outputs_list_node);
pthread_cond_signal(&cond);
@@ -917,6 +934,7 @@
context->ops.set_parameter = visualizer_set_parameter;
context->ops.get_parameter = visualizer_get_parameter;
context->ops.command = visualizer_command;
+ context->desc = &visualizer_descriptor;
} else {
return -EINVAL;
}
@@ -924,7 +942,6 @@
context->itfe = &effect_interface;
context->state = EFFECT_STATE_UNINITIALIZED;
context->out_handle = (audio_io_handle_t)ioId;
- context->desc = &visualizer_descriptor;
ret = context->ops.init(context);
if (ret < 0) {
@@ -1177,12 +1194,12 @@
out_ctxt = get_output(context->out_handle);
if (out_ctxt != NULL)
remove_effect_from_output(out_ctxt, context);
+
+ context->out_handle = offload_param->ioHandle;
out_ctxt = get_output(offload_param->ioHandle);
if (out_ctxt != NULL)
add_effect_to_output(out_ctxt, context);
- context->out_handle = offload_param->ioHandle;
-
} break;