From 22c0113ff656e8b8a0b5c5a152743fb9db57b4ad Mon Sep 17 00:00:00 2001 From: Yamit Mehta Date: Fri, 21 Jun 2013 19:33:51 +0530 Subject: [PATCH] alsa_sound: Initial commit for Audio HAL. Change-Id: Ie1b32383feae5b4b50463a97a3513c86bf985679 --- Android.mk | 1 - legacy/Android.mk | 9 +- legacy/alsa_sound/ALSAControl.cpp | 131 - legacy/alsa_sound/ALSADevice.cpp | 2774 +++++++++ legacy/alsa_sound/ALSAMixer.cpp | 1 + legacy/alsa_sound/ALSAStreamOps.cpp | 257 +- legacy/alsa_sound/Android.mk | 187 +- legacy/alsa_sound/AudioHardwareALSA.cpp | 2107 +++++-- legacy/alsa_sound/AudioHardwareALSA.h | 527 +- legacy/alsa_sound/AudioPolicyManagerALSA.cpp | 2023 ++++++- legacy/alsa_sound/AudioPolicyManagerALSA.h | 122 +- legacy/alsa_sound/AudioSessionOut.cpp | 1091 ++++ legacy/alsa_sound/AudioStreamInALSA.cpp | 305 +- legacy/alsa_sound/AudioStreamOutALSA.cpp | 271 +- legacy/alsa_sound/AudioUsbALSA.cpp | 593 +- legacy/alsa_sound/AudioUsbALSA.h | 24 +- legacy/alsa_sound/AudioUtil.cpp | 460 ++ legacy/alsa_sound/AudioUtil.h | 45 +- legacy/alsa_sound/alsa_default.cpp | 1833 ------ legacy/alsa_sound/audio_hw_hal.cpp | 211 +- legacy/alsa_sound/audio_policy_hal.cpp | 48 +- legacy/audiod/Android.mk | 22 + legacy/audiod/AudioDaemon.cpp | 148 + legacy/audiod/AudioDaemon.h | 59 + legacy/audiod/audiod_main.cpp | 60 + legacy/libalsa-intf/Android.mk | 20 +- legacy/libalsa-intf/Makefile.am | 18 +- legacy/libalsa-intf/alsa_audio.h | 113 +- legacy/libalsa-intf/alsa_mixer.c | 74 +- legacy/libalsa-intf/alsa_pcm.c | 201 +- legacy/libalsa-intf/alsa_ucm.c | 447 +- legacy/libalsa-intf/alsaucm_test.c | 10 +- legacy/libalsa-intf/amix.c | 2 +- legacy/libalsa-intf/aplay.c | 213 +- legacy/libalsa-intf/arec.c | 277 +- legacy/libalsa-intf/msm8960_use_cases.h | 85 +- legacy/mm-audio/Android.mk | 1 + legacy/mm-audio/Makefile | 10 + legacy/mm-audio/Makefile.am | 5 + legacy/mm-audio/adec-aac/Android.mk | 1 + legacy/mm-audio/adec-aac/Makefile | 6 + legacy/mm-audio/adec-aac/Makefile.am | 1 + legacy/mm-audio/adec-aac/sw/Android.mk | 58 + .../adec-aac/sw/test/omx_aac_dec_test.c | 1302 +++++ legacy/mm-audio/adec-amr/Android.mk | 1 + legacy/mm-audio/adec-amr/sw/Android.mk | 59 + .../adec-amr/sw/test/omx_amr_dec_test.c | 1297 +++++ legacy/mm-audio/adec-amrwb/Android.mk | 1 + legacy/mm-audio/adec-amrwb/sw/Android.mk | 58 + .../adec-amrwb/sw/test/omx_amrwb_dec_test.c | 1283 +++++ legacy/mm-audio/adec-mp3/Android.mk | 1 + legacy/mm-audio/adec-mp3/Makefile | 6 + legacy/mm-audio/adec-mp3/Makefile.am | 1 + legacy/mm-audio/adec-mp3/sw/Android.mk | 59 + .../adec-mp3/sw/test/omx_mp3_dec_test.c | 2159 +++++++ legacy/mm-audio/aenc-aac/Android.mk | 16 + legacy/mm-audio/aenc-aac/Makefile | 6 + legacy/mm-audio/aenc-aac/Makefile.am | 1 + legacy/mm-audio/aenc-aac/qdsp6/Android.mk | 76 + legacy/mm-audio/aenc-aac/qdsp6/Makefile | 81 + legacy/mm-audio/aenc-aac/qdsp6/Makefile.am | 30 + legacy/mm-audio/aenc-aac/qdsp6/inc/Map.h | 244 + legacy/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h | 120 + .../aenc-aac/qdsp6/inc/omx_aac_aenc.h | 624 ++ legacy/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c | 206 + .../aenc-aac/qdsp6/src/omx_aac_aenc.cpp | 5003 +++++++++++++++++ .../aenc-aac/qdsp6/test/omx_aac_enc_test.c | 1289 +++++ legacy/mm-audio/aenc-amrnb/Android.mk | 16 + legacy/mm-audio/aenc-amrnb/Makefile | 6 + legacy/mm-audio/aenc-amrnb/qdsp6/Android.mk | 76 + legacy/mm-audio/aenc-amrnb/qdsp6/Makefile | 81 + legacy/mm-audio/aenc-amrnb/qdsp6/inc/Map.h | 244 + .../mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h | 120 + .../aenc-amrnb/qdsp6/inc/omx_amr_aenc.h | 538 ++ .../mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c | 205 + .../aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp | 4519 +++++++++++++++ .../aenc-amrnb/qdsp6/test/omx_amr_enc_test.c | 1051 ++++ legacy/mm-audio/aenc-evrc/Android.mk | 16 + legacy/mm-audio/aenc-evrc/Makefile | 6 + legacy/mm-audio/aenc-evrc/qdsp6/Android.mk | 75 + legacy/mm-audio/aenc-evrc/qdsp6/Makefile | 81 + legacy/mm-audio/aenc-evrc/qdsp6/inc/Map.h | 244 + .../mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h | 122 + .../aenc-evrc/qdsp6/inc/omx_evrc_aenc.h | 539 ++ .../mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c | 205 + .../aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp | 4518 +++++++++++++++ .../aenc-evrc/qdsp6/test/omx_evrc_enc_test.c | 1094 ++++ legacy/mm-audio/aenc-qcelp13/Android.mk | 16 + legacy/mm-audio/aenc-qcelp13/Makefile | 6 + legacy/mm-audio/aenc-qcelp13/qdsp6/Android.mk | 78 + legacy/mm-audio/aenc-qcelp13/qdsp6/Makefile | 81 + legacy/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h | 244 + .../aenc-qcelp13/qdsp6/inc/aenc_svr.h | 120 + .../aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h | 539 ++ .../aenc-qcelp13/qdsp6/src/aenc_svr.c | 208 + .../qdsp6/src/omx_qcelp13_aenc.cpp | 4519 +++++++++++++++ .../qdsp6/test/omx_qcelp13_enc_test.c | 1097 ++++ legacy/mm-audio/autogen.sh | 10 + legacy/mm-audio/configure.ac | 44 + voice_processing/Android.mk | 23 - voice_processing/voice_processing.c | 725 --- 101 files changed, 46060 insertions(+), 4180 deletions(-) delete mode 100644 legacy/alsa_sound/ALSAControl.cpp create mode 100644 legacy/alsa_sound/ALSADevice.cpp create mode 100644 legacy/alsa_sound/AudioSessionOut.cpp delete mode 100644 legacy/alsa_sound/alsa_default.cpp create mode 100644 legacy/audiod/Android.mk create mode 100644 legacy/audiod/AudioDaemon.cpp create mode 100644 legacy/audiod/AudioDaemon.h create mode 100644 legacy/audiod/audiod_main.cpp create mode 100644 legacy/mm-audio/Android.mk create mode 100644 legacy/mm-audio/Makefile create mode 100644 legacy/mm-audio/Makefile.am create mode 100644 legacy/mm-audio/adec-aac/Android.mk create mode 100644 legacy/mm-audio/adec-aac/Makefile create mode 100644 legacy/mm-audio/adec-aac/Makefile.am create mode 100644 legacy/mm-audio/adec-aac/sw/Android.mk create mode 100644 legacy/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c create mode 100644 legacy/mm-audio/adec-amr/Android.mk create mode 100644 legacy/mm-audio/adec-amr/sw/Android.mk create mode 100644 legacy/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c create mode 100644 legacy/mm-audio/adec-amrwb/Android.mk create mode 100644 legacy/mm-audio/adec-amrwb/sw/Android.mk create mode 100644 legacy/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c create mode 100644 legacy/mm-audio/adec-mp3/Android.mk create mode 100644 legacy/mm-audio/adec-mp3/Makefile create mode 100644 legacy/mm-audio/adec-mp3/Makefile.am create mode 100644 legacy/mm-audio/adec-mp3/sw/Android.mk create mode 100644 legacy/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c create mode 100644 legacy/mm-audio/aenc-aac/Android.mk create mode 100644 legacy/mm-audio/aenc-aac/Makefile create mode 100644 legacy/mm-audio/aenc-aac/Makefile.am create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/Android.mk create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/Makefile create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/Makefile.am create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/inc/Map.h create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp create mode 100644 legacy/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c create mode 100644 legacy/mm-audio/aenc-amrnb/Android.mk create mode 100644 legacy/mm-audio/aenc-amrnb/Makefile create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/Android.mk create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/Makefile create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/inc/Map.h create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp create mode 100644 legacy/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c create mode 100644 legacy/mm-audio/aenc-evrc/Android.mk create mode 100644 legacy/mm-audio/aenc-evrc/Makefile create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/Android.mk create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/Makefile create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/inc/Map.h create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp create mode 100644 legacy/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c create mode 100644 legacy/mm-audio/aenc-qcelp13/Android.mk create mode 100644 legacy/mm-audio/aenc-qcelp13/Makefile create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/Android.mk create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/Makefile create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp create mode 100644 legacy/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c create mode 100644 legacy/mm-audio/autogen.sh create mode 100644 legacy/mm-audio/configure.ac delete mode 100644 voice_processing/Android.mk delete mode 100644 voice_processing/voice_processing.c diff --git a/Android.mk b/Android.mk index 1c5c5b3db..b70735868 100644 --- a/Android.mk +++ b/Android.mk @@ -6,7 +6,6 @@ ifeq ($(BOARD_USES_LEGACY_ALSA_AUDIO),true) include $(MY_LOCAL_PATH)/legacy/Android.mk else include $(MY_LOCAL_PATH)/hal/Android.mk -include $(MY_LOCAL_PATH)/voice_processing/Android.mk endif endif diff --git a/legacy/Android.mk b/legacy/Android.mk index 95d9adac3..ac9c9040b 100644 --- a/legacy/Android.mk +++ b/legacy/Android.mk @@ -1,5 +1,8 @@ -ifneq ($(filter msm8960,$(TARGET_BOARD_PLATFORM)),) - -include $(call all-subdir-makefiles) +AUDIO_HW_ROOT := $(call my-dir) +ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true) + include $(AUDIO_HW_ROOT)/alsa_sound/Android.mk + include $(AUDIO_HW_ROOT)/libalsa-intf/Android.mk + include $(AUDIO_HW_ROOT)/mm-audio/Android.mk + include $(AUDIO_HW_ROOT)/audiod/Android.mk endif diff --git a/legacy/alsa_sound/ALSAControl.cpp b/legacy/alsa_sound/ALSAControl.cpp deleted file mode 100644 index 2d610a15f..000000000 --- a/legacy/alsa_sound/ALSAControl.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* ALSAControl.cpp - ** - ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. - ** - ** 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 -#include -#include -#include -#include -#include -#include - -#define LOG_TAG "ALSAControl" -//#define LOG_NDEBUG 0 -#define LOG_NDDEBUG 0 -#include -#include - -#include -#include -#include - -#include "AudioHardwareALSA.h" - -namespace android_audio_legacy -{ - -ALSAControl::ALSAControl(const char *device) -{ - ALOGD("ALSAControl: ctor device %s", device); - mHandle = mixer_open(device); - ALOGV("ALSAControl: ctor mixer %p", mHandle); -} - -ALSAControl::~ALSAControl() -{ - if (mHandle) mixer_close(mHandle); -} - -status_t ALSAControl::get(const char *name, unsigned int &value, int index) -{ - struct mixer_ctl *ctl; - - if (!mHandle) { - ALOGE("Control not initialized"); - return NO_INIT; - } - - ctl = mixer_get_control(mHandle, name, index); - if (!ctl) - return BAD_VALUE; - - mixer_ctl_get(ctl, &value); - return NO_ERROR; -} - -status_t ALSAControl::set(const char *name, unsigned int value, int index) -{ - struct mixer_ctl *ctl; - int ret = 0; - ALOGD("set:: name %s value %d index %d", name, value, index); - if (!mHandle) { - ALOGE("Control not initialized"); - return NO_INIT; - } - - // ToDo: Do we need to send index here? Right now it works with 0 - ctl = mixer_get_control(mHandle, name, 0); - if(ctl == NULL) { - ALOGE("Could not get the mixer control"); - return BAD_VALUE; - } - ret = mixer_ctl_set(ctl, value); - return (ret < 0) ? BAD_VALUE : NO_ERROR; -} - -status_t ALSAControl::set(const char *name, const char *value) -{ - struct mixer_ctl *ctl; - int ret = 0; - ALOGD("set:: name %s value %s", name, value); - - if (!mHandle) { - ALOGE("Control not initialized"); - return NO_INIT; - } - - ctl = mixer_get_control(mHandle, name, 0); - if(ctl == NULL) { - ALOGE("Could not get the mixer control"); - return BAD_VALUE; - } - ret = mixer_ctl_select(ctl, value); - return (ret < 0) ? BAD_VALUE : NO_ERROR; -} - -status_t ALSAControl::setext(const char *name, int count, char **setValues) -{ - struct mixer_ctl *ctl; - int ret = 0; - ALOGD("setext:: name %s count %d", name, count); - if (!mHandle) { - ALOGE("Control not initialized"); - return NO_INIT; - } - - // ToDo: Do we need to send index here? Right now it works with 0 - ctl = mixer_get_control(mHandle, name, 0); - if(ctl == NULL) { - ALOGE("Could not get the mixer control"); - return BAD_VALUE; - } - ret = mixer_ctl_set_value(ctl, count, setValues); - return (ret < 0) ? BAD_VALUE : NO_ERROR; -} - -}; // namespace android diff --git a/legacy/alsa_sound/ALSADevice.cpp b/legacy/alsa_sound/ALSADevice.cpp new file mode 100644 index 000000000..79443995e --- /dev/null +++ b/legacy/alsa_sound/ALSADevice.cpp @@ -0,0 +1,2774 @@ +/* ALSADevice.cpp + ** + ** Copyright 2009 Wind River Systems + ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. + ** + ** 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 "ALSADevice" +#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 +#include +#include +#include +#include "AudioUtil.h" +#include "AudioHardwareALSA.h" +#include +#include +extern "C" { +#ifdef QCOM_CSDCLIENT_ENABLED +static int (*csd_disable_device)(); +static int (*csd_enable_device)(int, int, uint32_t); +static int (*csd_enable_device_config)(int, int); +static int (*csd_volume)(uint32_t, int); +static int (*csd_mic_mute)(uint32_t, int); +static int (*csd_wide_voice)(uint32_t, uint8_t); +static int (*csd_slow_talk)(uint32_t, uint8_t); +static int (*csd_fens)(uint32_t, uint8_t); +static int (*csd_start_voice)(uint32_t); +static int (*csd_stop_voice)(uint32_t); +#endif +#ifdef QCOM_ACDB_ENABLED +static int (*acdb_loader_get_ecrx_device)(int acdb_id); +#endif +} + +#define SAMPLE_RATE_8KHZ 8000 + +#define BTSCO_RATE_16KHZ 16000 +#define USECASE_TYPE_RX 1 +#define USECASE_TYPE_TX 2 +#define MAX_HDMI_CHANNEL_CNT 8 + +#define AFE_PROXY_PERIOD_SIZE 3072 +#define KILL_A2DP_THREAD 1 +#define SIGNAL_A2DP_THREAD 2 + +// Setting number of periods to 4. If the system is loaded +// and record obtain buffer is seen increase +// PCM_RECORD_PERIOD_COUNT to a value between 4-16. +#define PCM_RECORD_PERIOD_COUNT 4 +#define PROXY_CAPTURE_DEVICE_NAME (const char *)("hw:0,8") +namespace sys_close { + ssize_t lib_close(int fd) { + return close(fd); + } +}; + +namespace android_audio_legacy +{ + +ALSADevice::ALSADevice() { +#ifdef USES_FLUENCE_INCALL + mDevSettingsFlag = TTY_OFF | DMIC_FLAG; +#else + mSSRComplete = false; + mDevSettingsFlag = TTY_OFF; +#endif + mBtscoSamplerate = 8000; + mCallMode = AUDIO_MODE_NORMAL; + mInChannels = 0; + mIsFmEnabled = false; + char value[128], platform[128], baseband[128]; + + property_get("persist.audio.handset.mic",value,"0"); + strlcpy(mMicType, value, sizeof(mMicType)); + property_get("persist.audio.fluence.mode",value,"0"); + if (!strcmp("broadside", value)) { + mFluenceMode = FLUENCE_MODE_BROADSIDE; + } else { + mFluenceMode = FLUENCE_MODE_ENDFIRE; + } + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strcmp("msm8960", platform) && !strcmp("sglte", baseband)) { + mIsSglte = true; + } + else { + mIsSglte = false; + } + strlcpy(mCurRxUCMDevice, "None", sizeof(mCurRxUCMDevice)); + strlcpy(mCurTxUCMDevice, "None", sizeof(mCurTxUCMDevice)); + + mMixer = mixer_open("/dev/snd/controlC0"); + + mProxyParams.mExitRead = false; + mProxyParams.mPfdProxy[1].fd = -1; + resetProxyVariables(); + mProxyParams.mCaptureBufferSize = AFE_PROXY_PERIOD_SIZE; + mProxyParams.mCaptureBuffer = NULL; + mProxyParams.mProxyState = proxy_params::EProxyClosed; + mProxyParams.mProxyPcmHandle = NULL; + + ALOGD("ALSA module opened"); +} + +//static int s_device_close(hw_device_t* device) +ALSADevice::~ALSADevice() +{ + if (mMixer) mixer_close(mMixer); + if(mProxyParams.mCaptureBuffer != NULL) { + free(mProxyParams.mCaptureBuffer); + mProxyParams.mCaptureBuffer = NULL; + } + mProxyParams.mProxyState = proxy_params::EProxyClosed; + +} + +static bool isPlatformFusion3() { + char platform[128], baseband[128]; + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strcmp("msm8960", platform) && + (!strcmp("mdm", baseband) || !strcmp("sglte2", baseband))) + return true; + else + return false; +} + +static bool shouldUseHandsetAnc(int flags, int inChannels) +{ + if (!isPlatformFusion3()) { + return false; + } + return (flags & ANC_FLAG) && (inChannels == 1); +} + +static int adjustFlagsForCsd(int flags, const char *rxDevice) +{ + int adjustedFlags = flags; + if (0 != strcmp(rxDevice, SND_USE_CASE_DEV_ANC_HANDSET)) { + /* if not using Adaptive ANC, clear the ANC bit; this + is the only adaptive mode CSD Client cares about */ + adjustedFlags &= ~(ANC_FLAG); + } + ALOGD("%s: current Rx device: %s, flags: %x, adjustedFlags: %x", + __FUNCTION__, rxDevice, flags, adjustedFlags); + return adjustedFlags; +} + +int ALSADevice::deviceName(alsa_handle_t *handle, unsigned flags, char **value) +{ + int ret = 0; + char ident[70]; + + if (flags & PCM_IN) { + strlcpy(ident, "CapturePCM/", sizeof(ident)); + } else { + strlcpy(ident, "PlaybackPCM/", sizeof(ident)); + } + strlcat(ident, handle->useCase, sizeof(ident)); + ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value); + ALOGD("Device value returned is %s", (*value)); + return ret; +} + +status_t ALSADevice::setHDMIChannelCount() +{ + status_t err = NO_ERROR; + int channel_count = 0; + const char *channel_cnt_str = NULL; + EDID_AUDIO_INFO info = { 0 }; + +#ifdef TARGET_8974 + char hdmiEDIDData[MAX_SHORT_AUDIO_DESC_CNT+1]; + if(!getEDIDData(hdmiEDIDData)) { + if (AudioUtil::getHDMIAudioSinkCaps(&info, hdmiEDIDData)) { + for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) { + if (info.AudioBlocksArray[i].nChannels > channel_count && + info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) { + channel_count = info.AudioBlocksArray[i].nChannels; + } + } + pcm_set_channel_map(NULL, mMixer, MAX_HDMI_CHANNEL_CNT, info.channelMap); + setChannelAlloc(info.channelAllocation); + } + } +#else + if (AudioUtil::getHDMIAudioSinkCaps(&info)) { + for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) { + if (info.AudioBlocksArray[i].nChannels > channel_count && + info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) { + channel_count = info.AudioBlocksArray[i].nChannels; + } + } + } +#endif + + 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; + } + ALOGD("HDMI channel count: %s", channel_cnt_str); + setMixerControl("HDMI_RX Channels", channel_cnt_str); + + return err; +} + +status_t ALSADevice::setHardwareParams(alsa_handle_t *handle) +{ + struct snd_pcm_hw_params *params; + unsigned long bufferSize, reqBuffSize; + unsigned int periodTime, bufferTime; + unsigned int requestedRate = handle->sampleRate; + int status = 0; + int channels = handle->channels; + status_t err; + snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE; + struct snd_compr_caps compr_cap; + struct snd_compr_params compr_params; + uint32_t codec_id = 0; + + ALOGD("handle->format: 0x%x", handle->format); + if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL))) { + ALOGV("Tunnel mode detected..."); + //get the list of codec supported by hardware + if (ioctl(handle->handle->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) { + ALOGE("SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno); + err = -errno; + return err; + } + if( handle->format == AUDIO_FORMAT_AAC ) { + codec_id = get_compressed_format("AAC"); + ALOGV("### AAC CODEC codec_id %d",codec_id); + } + else if (handle->format == AUDIO_FORMAT_AMR_WB) { + codec_id = get_compressed_format("AMR_WB"); + if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL))) { + compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/ + compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/ + } + ALOGV("### AMR WB CODEC codec_id %d",codec_id); + } +#ifdef QCOM_AUDIO_FORMAT_ENABLED + else if (handle->format == AUDIO_FORMAT_AMR_WB_PLUS) { + codec_id = get_compressed_format("AMR_WB_PLUS"); + ALOGV("### AMR WB+ CODEC codec_id %d",codec_id); + } +#endif + else if (handle->format == AUDIO_FORMAT_MP3) { + codec_id = get_compressed_format("MP3"); + ALOGV("### MP3 CODEC codec_id %d",codec_id); + } + else { + return UNKNOWN_ERROR; + } + //find if codec_id matches with any of h/w supported codecs. + for (int i = 0; i < compr_cap.num_codecs; i++) { + if (compr_cap.codecs[i] == codec_id) { + ALOGV("### MatchedFcodec_id %u", codec_id); + compr_params.codec.id = codec_id; + break; + } + } + if (!compr_params.codec.id) { + ALOGE("### Codec %u not supported",codec_id); + return UNKNOWN_ERROR; + } + + if (ioctl(handle->handle->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) { + ALOGE("SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno); + err = -errno; + return err; + } + } + + params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params)); + if (!params) { + ALOGE("Failed to allocate ALSA hardware parameters!"); + return NO_INIT; + } + + reqBuffSize = handle->bufferSize; + ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d", + (int) reqBuffSize, handle->channels, handle->sampleRate); + +#ifdef QCOM_SSR_ENABLED + if (channels == 6) { + if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) + || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + channels = 4; + reqBuffSize = DEFAULT_IN_BUFFER_SIZE*4; + ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording reqBuffSize:%d", handle->useCase,reqBuffSize); + } + } +#endif + + param_init(params); + if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { + param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); + } + else { + param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_RW_INTERLEAVED); + } + + if (handle->format != SNDRV_PCM_FORMAT_S16_LE) { + if (handle->format == AUDIO_FORMAT_AMR_NB + || handle->format == AUDIO_FORMAT_AMR_WB +#ifdef QCOM_AUDIO_FORMAT_ENABLED + || handle->format == AUDIO_FORMAT_EVRC + || handle->format == AUDIO_FORMAT_EVRCB + || handle->format == AUDIO_FORMAT_EVRCWB +#endif + ) { + if ((strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) && + (strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) && + (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) && + (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) && + (strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) && + (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) && + (strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) && + (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + format = SNDRV_PCM_FORMAT_SPECIAL; + ALOGW("setting format to SNDRV_PCM_FORMAT_SPECIAL"); + } + } + } + //TODO: Add format setting for tunnel mode using the usecase. + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + format); + param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_SUBFORMAT_STD); + param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize); + //Setting number of periods to 4. If the system is loaded and record + // obtain buffer is seen increase PCM_RECORD_PERIOD_COUNT to a value between 4-16. + if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, + strlen(SND_USE_CASE_VERB_HIFI_REC)) || + !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, + strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { + param_set_int(params, SNDRV_PCM_HW_PARAM_PERIODS, PCM_RECORD_PERIOD_COUNT); + } + param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16); + param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS, + channels * 16); + param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS, + channels); + param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate); + param_set_hw_refine(handle->handle, params); + + if (param_set_hw_params(handle->handle, params)) { + ALOGE("cannot set hw params"); + if(params) { + free(params); + } + return NO_INIT; + } + param_dump(params); + + handle->handle->buffer_size = pcm_buffer_size(params); + handle->handle->period_size = pcm_period_size(params); + handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size; + ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d", + handle->handle->buffer_size, handle->handle->period_size, + handle->handle->period_cnt); + handle->handle->rate = handle->sampleRate; + handle->handle->channels = handle->channels; + handle->periodSize = handle->handle->period_size; + if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) && + strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) && + strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) && + strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED) && + (6 != handle->channels)) { + //Do not update buffersize for 5.1 recording + if (handle->format == AUDIO_FORMAT_AMR_WB && + format != SNDRV_PCM_FORMAT_SPECIAL) { + ALOGV("### format AMWB, set bufsize to 61"); + handle->bufferSize = 61; + } else { + handle->bufferSize = handle->handle->period_size; + } + } + + return NO_ERROR; +} + +status_t ALSADevice::setSoftwareParams(alsa_handle_t *handle) +{ + struct snd_pcm_sw_params* params; + struct pcm* pcm = handle->handle; + + unsigned long periodSize = pcm->period_size; + int channels = handle->channels; + + params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params)); + if (!params) { + LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!"); + return NO_INIT; + } + +#ifdef QCOM_SSR_ENABLED + if (channels == 6) { + if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) + || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase); + channels = 4; + } + } +#endif + + // Get the current software parameters + params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; + params->period_step = 1; + if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) || + (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){ + ALOGV("setparam: start & stop threshold for Voip "); + params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2; + params->start_threshold = periodSize/2; + params->stop_threshold = INT_MAX; + } else { + params->avail_min = periodSize/(channels * 2); + params->start_threshold = periodSize/(channels * 2); + params->stop_threshold = INT_MAX; + } + params->silence_threshold = 0; + params->silence_size = 0; + + if (param_set_sw_params(handle->handle, params)) { + ALOGE("cannot set sw params"); + if (params) { + free(params); + } + return NO_INIT; + } + return NO_ERROR; +} + +void ALSADevice::switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode) +{ + const char **mods_list; + use_case_t useCaseNode; + unsigned usecase_type = 0; + bool inCallDevSwitch = false; + char *rxDevice, *txDevice, ident[70], *use_case = NULL; + int err = 0, index, mods_size; + int rx_dev_id, tx_dev_id; + ALOGV("%s: device %#x mode:%d", __FUNCTION__, devices, mode); + + if ((mode == AUDIO_MODE_IN_CALL) || (mode == AUDIO_MODE_IN_COMMUNICATION)) { + if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || + (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) { + devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET | + AudioSystem::DEVICE_IN_WIRED_HEADSET); + } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) { + devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE | + AudioSystem::DEVICE_IN_BUILTIN_MIC); + } else if ((devices & AudioSystem::DEVICE_OUT_EARPIECE) || + (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC)) { + if((mode == AudioSystem::MODE_IN_COMMUNICATION) + && devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) { + ALOGV("Current Rx device %s",mCurRxUCMDevice); + if(!strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER , + strlen(SND_USE_CASE_DEV_SPEAKER))) { + devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC | + AudioSystem::DEVICE_OUT_SPEAKER); + ALOGV("Selecting Speaker: device %d",devices); + } + else{ + ALOGV("Selecting earpiece: device %d",devices); + devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC | + AudioSystem::DEVICE_OUT_EARPIECE); + } + } + else{ + devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC | + AudioSystem::DEVICE_OUT_EARPIECE); + } + } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) { + devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC | + AudioSystem::DEVICE_OUT_SPEAKER); + } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) || + (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) || + (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) { + devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET | + AudioSystem::DEVICE_OUT_BLUETOOTH_SCO); +#ifdef QCOM_ANC_HEADSET_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || + (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) { + devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET | + AudioSystem::DEVICE_IN_ANC_HEADSET); + } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) { + devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE | + AudioSystem::DEVICE_IN_BUILTIN_MIC); +#endif +#ifdef QCOM_USBAUDIO_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ) || + (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET )) { + devices = devices | (AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET | + AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET); +#endif + } else if ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) || + (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL)) { + devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL | + AudioSystem::DEVICE_IN_AUX_DIGITAL); +#ifdef QCOM_PROXY_DEVICE_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) || + (devices & AudioSystem::DEVICE_IN_PROXY)) { + devices = devices | (AudioSystem::DEVICE_OUT_PROXY | + AudioSystem::DEVICE_IN_PROXY); +#endif + } else if (devices & AUDIO_DEVICE_OUT_ALL_USB) { + devices = devices | AudioSystem::DEVICE_IN_BUILTIN_MIC; + } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP) { + ALOGE("SwitchDevice:: Invalid A2DP Combination for mode %d", mode); + } + } +#ifdef QCOM_SSR_ENABLED + if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) { + if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) + || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase); + setFlags(SSRQMIC_FLAG); + } + } +#endif + + rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL); + ALOGV("%s: rxDevice %s devices:0x%x", __FUNCTION__, rxDevice,devices); + txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice); + ALOGV("%s: txDevice:%s devices:0x%x", __FUNCTION__, txDevice,devices); + + if ((rxDevice != NULL) && (txDevice != NULL)) { + if (((strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) || + (strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN))) && + ((mode == AUDIO_MODE_IN_CALL) || + (mode == AUDIO_MODE_IN_COMMUNICATION))) + inCallDevSwitch = true; + } + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3() && (inCallDevSwitch == true)) { + if (csd_disable_device == NULL) { + ALOGE("csd_client_disable_device is NULL"); + } else { + err = csd_disable_device(); + if (err < 0) + { + ALOGE("csd_client_disable_device, failed, error %d", err); + } + } + } +#endif + + snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case); + mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list); + if (rxDevice != NULL) { + if ((strncmp(mCurRxUCMDevice, "None", 4)) && + (mSSRComplete || (strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) { + if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, + strlen(SND_USE_CASE_VERB_INACTIVE)))) { + usecase_type = getUseCaseType(use_case); + if (usecase_type & USECASE_TYPE_RX) { + ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type); + strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN); + snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE); + mUseCaseList.push_front(useCaseNode); + } + } + if (mods_size) { + for(index = 0; index < mods_size; index++) { + usecase_type = getUseCaseType(mods_list[index]); + if (usecase_type & USECASE_TYPE_RX) { + ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type); + strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN); + snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]); + mUseCaseList.push_back(useCaseNode); + } + } + } + snd_use_case_set(handle->ucMgr, "_disdev", mCurRxUCMDevice); + } + } + if (txDevice != NULL) { + if ((strncmp(mCurTxUCMDevice, "None", 4)) && + (mSSRComplete || (strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) { + if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, + strlen(SND_USE_CASE_VERB_INACTIVE)))) { + usecase_type = getUseCaseType(use_case); + if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) { + ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type); + strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN); + snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE); + mUseCaseList.push_front(useCaseNode); + } + } + if (mods_size) { + for(index = 0; index < mods_size; index++) { + usecase_type = getUseCaseType(mods_list[index]); + if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) { + ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type); + strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN); + snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]); + mUseCaseList.push_back(useCaseNode); + } + } + } + snd_use_case_set(handle->ucMgr, "_disdev", mCurTxUCMDevice); + } + } + + ALOGV("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, mCurRxUCMDevice, mCurTxUCMDevice); + + if (rxDevice != NULL) { + snd_use_case_set(handle->ucMgr, "_enadev", rxDevice); + strlcpy(mCurRxUCMDevice, rxDevice, sizeof(mCurRxUCMDevice)); + } + if (txDevice != NULL) { + snd_use_case_set(handle->ucMgr, "_enadev", txDevice); + strlcpy(mCurTxUCMDevice, txDevice, sizeof(mCurTxUCMDevice)); + } +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3() && (inCallDevSwitch == true)) { + + /* Get tx acdb id */ + memset(&ident,0,sizeof(ident)); + strlcpy(ident, "ACDBID/", sizeof(ident)); + strlcat(ident, mCurTxUCMDevice, sizeof(ident)); + tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL); + + /* Get rx acdb id */ + memset(&ident,0,sizeof(ident)); + strlcpy(ident, "ACDBID/", sizeof(ident)); + strlcat(ident, mCurRxUCMDevice, sizeof(ident)); + rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL); + + if (rx_dev_id == DEVICE_SPEAKER_RX_ACDB_ID && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) { + tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID; + } + + /* Parallelize codec configuration on APQ with CSD voice call + * sequence on MDM. This will reduce in call device switch delay + */ + if (csd_enable_device_config == NULL) { + ALOGE("csd_enable_device_config is NULL"); + } else { + err = csd_enable_device_config(rx_dev_id, tx_dev_id); + if (err < 0) { + ALOGE("csd_enable_device_config failed, error %d", err); + } + } + } +#endif + for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) { + ALOGD("Route use case %s\n", it->useCase); + if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, + strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) { + snd_use_case_set(handle->ucMgr, "_verb", it->useCase); + } else { + snd_use_case_set(handle->ucMgr, "_enamod", it->useCase); + } + } + if (!mUseCaseList.empty()) + mUseCaseList.clear(); + if (use_case != NULL) { + free(use_case); + use_case = NULL; + } +#ifdef QCOM_FM_ENABLED + if (rxDevice != NULL) { + setFmVolume(mFmVolume); + } +#endif + ALOGD("switchDevice: mCurTxUCMDevivce %s mCurRxDevDevice %s", mCurTxUCMDevice, mCurRxUCMDevice); +#ifdef QCOM_ACDB_ENABLED + if (((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) || (devices & AudioSystem::DEVICE_IN_BACK_MIC)) + && (mInChannels == 1)) { + ALOGD("switchDevice:use device %x for channels:%d usecase:%s",devices,handle->channels,handle->useCase); + int ec_acdbid; + char *ec_dev; + char *ec_rx_dev; + memset(&ident,0,sizeof(ident)); + strlcpy(ident, "ACDBID/", sizeof(ident)); + strlcat(ident, mCurTxUCMDevice, sizeof(ident)); + tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL); + if (acdb_loader_get_ecrx_device) { + ec_acdbid = acdb_loader_get_ecrx_device(tx_dev_id); + ec_dev = getUCMDeviceFromAcdbId(ec_acdbid); + if (ec_dev) { + memset(&ident,0,sizeof(ident)); + strlcpy(ident, "EC_REF_RXMixerCTL/", sizeof(ident)); + strlcat(ident, ec_dev, sizeof(ident)); + snd_use_case_get(handle->ucMgr, ident, (const char **)&ec_rx_dev); + ALOGD("SwitchDevice: ec_ref_rx_acdbid:%d ec_dev:%s ec_rx_dev:%s", ec_acdbid, ec_dev, ec_rx_dev); + if (ec_rx_dev) { + setEcrxDevice(ec_rx_dev); + free(ec_rx_dev); + } + } + } else { + ALOGE("acdb_loader_get_ecrx_device is NULL"); + } + } +#endif +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3() && (inCallDevSwitch == true)) { + if (rx_dev_id == DEVICE_SPEAKER_RX_ACDB_ID && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) { + tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID; + } + ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id); + + if (csd_enable_device == NULL) { + ALOGE("csd_client_enable_device is NULL"); + } else { + int adjustedFlags = adjustFlagsForCsd(mDevSettingsFlag, + mCurRxUCMDevice); + err = csd_enable_device(rx_dev_id, tx_dev_id, adjustedFlags); + if (err < 0) + { + ALOGE("csd_client_disable_device failed, error %d", err); + } + } + } +#endif + + if (rxDevice != NULL) { + free(rxDevice); + rxDevice = NULL; + } + if (txDevice != NULL) { + free(txDevice); + txDevice = NULL; + } +} + +// ---------------------------------------------------------------------------- +/* +status_t ALSADevice::init(alsa_device_t *module, ALSAHandleList &list) +{ + ALOGD("s_init: Initializing devices for ALSA module"); + + list.clear(); + + return NO_ERROR; +} +*/ +status_t ALSADevice::open(alsa_handle_t *handle) +{ + char *devName = NULL; + unsigned flags = 0; + int err = NO_ERROR; + + if(mCurDevice & AudioSystem::DEVICE_OUT_AUX_DIGITAL) { + err = setHDMIChannelCount(); + if(err != OK) { + ALOGE("setHDMIChannelCount err = %d", err); + return err; + } + } + close(handle); + + ALOGD("open: handle %p, format 0x%x", handle, handle->format); + + // ASoC multicomponent requires a valid path (frontend/backend) for + // the device to be opened + + // The PCM stream is opened in blocking mode, per ALSA defaults. The + // AudioFlinger seems to assume blocking mode too, so asynchronous mode + // should not be used. + if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { + ALOGV("LPA/tunnel use case"); + flags |= PCM_MMAP; + flags |= DEBUG_ON; + } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) { + ALOGV("Music case"); + flags = PCM_OUT; + } else { + flags = PCM_IN; + } + + if (handle->channels == 1) { + flags |= PCM_MONO; + } + else if (handle->channels == 4 ) { + flags |= PCM_QUAD; + } else if (handle->channels == 6 ) { +#ifdef QCOM_SSR_ENABLED + if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) + || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + flags |= PCM_QUAD; + } else +#endif + { + flags |= PCM_5POINT1; + } + } + else { + flags |= PCM_STEREO; + } + + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node: %s", devName); + return NO_INIT; + } + if (devName != NULL) { + ALOGV("flags %x, devName %s",flags,devName); + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + ALOGV("pcm_open returned fd %d", handle->handle->fd); + + if (!handle->handle || (handle->handle->fd < 0)) { + ALOGE("open: Failed to initialize ALSA device '%s'", devName); + if (devName) { + free(devName); + devName = NULL; + } + return NO_INIT; + } + + handle->handle->flags = flags; + err = setHardwareParams(handle); + + if (err == NO_ERROR) { + err = setSoftwareParams(handle); + } + + if(err != NO_ERROR) { + ALOGE("Set HW/SW params failed: Closing the pcm stream"); + standby(handle); + free(devName); + devName = NULL; + return err; + } + + if (devName) { + free(devName); + devName = NULL; + } + +#ifdef TARGET_8974 + if(handle->channels > 2) + setChannelMap(handle, MAX_HDMI_CHANNEL_CNT); +#endif + + return NO_ERROR; +} + +status_t ALSADevice::startVoipCall(alsa_handle_t *handle) +{ + + char* devName = NULL; + unsigned flags = 0; + int err = NO_ERROR; + uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE]; + + close(handle); + flags = PCM_OUT; + flags |= PCM_MONO; + ALOGV("startVoipCall handle %p", handle); + + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + + if (devName != NULL) { + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + + if (!handle->handle || (handle->handle->fd < 0)) { + if (devName) { + free(devName); + devName = NULL; + } + ALOGE("s_open: Failed to initialize ALSA device '%s'", devName); + return NO_INIT; + } + + if (!pcm_ready(handle->handle)) { + ALOGE(" pcm ready failed"); + } + + handle->handle->flags = flags; + err = setHardwareParams(handle); + + if (err == NO_ERROR) { + err = setSoftwareParams(handle); + } + + err = pcm_prepare(handle->handle); + if(err != NO_ERROR) { + ALOGE("startVoipCall: pcm_prepare failed"); + } + + /* first write required start dsp */ + memset(&voc_pkt,0,sizeof(voc_pkt)); + pcm_write(handle->handle,&voc_pkt,handle->handle->period_size); + handle->rxHandle = handle->handle; + if (devName) { + free(devName); + devName = NULL; + } + ALOGV("s_open: DEVICE_IN_COMMUNICATION "); + flags = PCM_IN; + flags |= PCM_MONO; + handle->handle = 0; + + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + if (devName != NULL) { + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + + if (!handle->handle) { + if (devName) { + free(devName); + devName = NULL; + } + ALOGE("s_open: Failed to initialize ALSA device '%s'", devName); + return NO_INIT; + } + + if (!pcm_ready(handle->handle)) { + ALOGE(" pcm ready in failed"); + } + + handle->handle->flags = flags; + + err = setHardwareParams(handle); + + if (err == NO_ERROR) { + err = setSoftwareParams(handle); + } + + + err = pcm_prepare(handle->handle); + if(err != NO_ERROR) { + ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed"); + } + + /* first read required start dsp */ + memset(&voc_pkt,0,sizeof(voc_pkt)); + pcm_read(handle->handle,&voc_pkt,handle->handle->period_size); + if (devName) { + free(devName); + devName = NULL; + } + return NO_ERROR; +} + +status_t ALSADevice::startVoiceCall(alsa_handle_t *handle, uint32_t vsid) +{ + char* devName = NULL; + unsigned flags = 0; + int err = NO_ERROR; + + ALOGD("startVoiceCall: handle %p", handle); + // ASoC multicomponent requires a valid path (frontend/backend) for + // the device to be opened + + flags = PCM_OUT | PCM_MONO; + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + if (devName != NULL) { + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + + if (!handle->handle || (handle->handle->fd < 0)) { + ALOGE("startVoiceCall: could not open PCM device"); + goto Error; + } + + handle->handle->flags = flags; + err = setHardwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startVoiceCall: setHardwareParams failed"); + goto Error; + } + + err = setSoftwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startVoiceCall: setSoftwareParams failed"); + goto Error; + } + + err = pcm_prepare(handle->handle); + if(err != NO_ERROR) { + ALOGE("startVoiceCall: pcm_prepare failed"); + goto Error; + } + + if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { + ALOGE("startVoiceCall:SNDRV_PCM_IOCTL_START failed\n"); + goto Error; + } + + // Store the PCM playback device pointer in rxHandle + handle->rxHandle = handle->handle; + if (devName) { + free(devName); + devName = NULL; + } + + // Open PCM capture device + flags = PCM_IN | PCM_MONO; + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node"); + goto Error; + } + if (devName != NULL) { + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + if (!handle->handle || (handle->handle->fd < 0)) { + free(devName); + goto Error; + } + + handle->handle->flags = flags; + err = setHardwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startVoiceCall: setHardwareParams failed"); + goto Error; + } + + err = setSoftwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startVoiceCall: setSoftwareParams failed"); + goto Error; + } + + err = pcm_prepare(handle->handle); + if(err != NO_ERROR) { + ALOGE("startVoiceCall: pcm_prepare failed"); + goto Error; + } + + if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { + ALOGE("startVoiceCall:SNDRV_PCM_IOCTL_START failed\n"); + goto Error; + } + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_start_voice == NULL) { + ALOGE("csd_client_start_voice is NULL"); + } else { + err = csd_start_voice(vsid); + if (err < 0){ + ALOGE("s_start_voice_call: csd_client error %d\n", err); + goto Error; + } + } + } +#endif + + if (devName) { + free(devName); + devName = NULL; + } + return NO_ERROR; + +Error: + ALOGE("startVoiceCall: Failed to initialize ALSA device '%s'", devName); + if (devName) { + free(devName); + devName = NULL; + } + close(handle, vsid); + return NO_INIT; +} + +status_t ALSADevice::startFm(alsa_handle_t *handle) +{ + char *devName = NULL; + unsigned flags = 0; + int err = NO_ERROR; + + ALOGV("startFm: handle %p", handle); + + // ASoC multicomponent requires a valid path (frontend/backend) for + // the device to be opened + + flags = PCM_OUT | PCM_STEREO; + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node"); + goto Error; + } + if (devName != NULL) { + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + if (!handle->handle || (handle->handle->fd < 0)) { + ALOGE("startFm: could not open PCM device"); + goto Error; + } + + handle->handle->flags = flags; + err = setHardwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startFm: setHardwareParams failed"); + goto Error; + } + + err = setSoftwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startFm: setSoftwareParams failed"); + goto Error; + } + + err = pcm_prepare(handle->handle); + if(err != NO_ERROR) { + ALOGE("startFm: setSoftwareParams failed"); + goto Error; + } + + if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { + ALOGE("startFm: SNDRV_PCM_IOCTL_START failed\n"); + goto Error; + } + + // Store the PCM playback device pointer in rxHandle + handle->rxHandle = handle->handle; + if (devName) { + free(devName); + devName = NULL; + } + + // Open PCM capture device + flags = PCM_IN | PCM_STEREO; + if (deviceName(handle, flags, &devName) < 0) { + ALOGE("Failed to get pcm device node"); + goto Error; + } + if (devName != NULL) { + handle->handle = pcm_open(flags, (char*)devName); + } else { + ALOGE("Failed to get pcm device node"); + return NO_INIT; + } + if (!handle->handle) { + goto Error; + } + + handle->handle->flags = flags; + err = setHardwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startFm: setHardwareParams failed"); + goto Error; + } + + err = setSoftwareParams(handle); + if(err != NO_ERROR) { + ALOGE("startFm: setSoftwareParams failed"); + goto Error; + } + + err = pcm_prepare(handle->handle); + if(err != NO_ERROR) { + ALOGE("startFm: pcm_prepare failed"); + goto Error; + } + + if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { + ALOGE("startFm: SNDRV_PCM_IOCTL_START failed\n"); + goto Error; + } + + mIsFmEnabled = true; + setFmVolume(mFmVolume); + if (devName) { + free(devName); + devName = NULL; + } + return NO_ERROR; + +Error: + if (devName) { + free(devName); + devName = NULL; + } + close(handle); + return NO_INIT; +} + +status_t ALSADevice::setFmVolume(int value) +{ + status_t err = NO_ERROR; + if (!mIsFmEnabled) { + return INVALID_OPERATION; + } + + setMixerControl("Internal FM RX Volume",value,0); + mFmVolume = value; + + return err; +} + +status_t ALSADevice::setLpaVolume(int value) +{ + status_t err = NO_ERROR; + + setMixerControl("LPA RX Volume",value,0); + + return err; +} + +status_t ALSADevice::start(alsa_handle_t *handle) +{ + status_t err = NO_ERROR; + + if(!handle->handle) { + ALOGE("No active PCM driver to start"); + return err; + } + + err = pcm_prepare(handle->handle); + + return err; +} + +status_t ALSADevice::close(alsa_handle_t *handle, uint32_t vsid) +{ + int ret; + status_t err = NO_ERROR; + struct pcm *h = handle->rxHandle; + + handle->rxHandle = 0; + ALOGD("close: handle %p h %p", handle, h); + if (h) { +#ifdef QCOM_CSDCLIENT_ENABLED + if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) || + !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_VOLTE) || + !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOLTE)) || + (!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICE2) || + !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE2)) && + isPlatformFusion3()) { + if (csd_stop_voice == NULL) { + ALOGE("csd_client_disable_device is NULL"); + } else { + err = csd_stop_voice(vsid); + if (err < 0) { + ALOGE("s_close: csd_client error %d\n", err); + } + } + } +#endif + + if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) || + (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_FM))) { + mIsFmEnabled = false; + } + + ALOGV("close rxHandle\n"); + err = pcm_close(h); + if(err != NO_ERROR) { + ALOGE("close: pcm_close failed for rxHandle with err %d", err); + } + } + + h = handle->handle; + handle->handle = 0; + + if (h) { + ALOGV("close handle h %p\n", h); + err = pcm_close(h); + if(err != NO_ERROR) { + ALOGE("close: pcm_close failed for handle with err %d", err); + } + disableDevice(handle); + } + + return err; +} + +/* + this is same as s_close, but don't discard + the device/mode info. This way we can still + close the device, hit idle and power-save, reopen the pcm + for the same device/mode after resuming +*/ +status_t ALSADevice::standby(alsa_handle_t *handle) +{ + int ret; + status_t err = NO_ERROR; + struct pcm *h = handle->rxHandle; + handle->rxHandle = 0; + ALOGD("standby: handle %p h %p", handle, h); + if (h) { + ALOGV("standby rxHandle\n"); + err = pcm_close(h); + if(err != NO_ERROR) { + ALOGE("standby: pcm_close failed for rxHandle with err %d", err); + } + } + + h = handle->handle; + handle->handle = 0; + + if (h) { + ALOGV("standby handle h %p\n", h); + err = pcm_close(h); + if(err != NO_ERROR) { + ALOGE("standby: pcm_close failed for handle with err %d", err); + } + disableDevice(handle); + } + + return err; +} + +status_t ALSADevice::route(alsa_handle_t *handle, uint32_t devices, int mode) +{ + status_t status = NO_ERROR; + + ALOGD("route: devices 0x%x in mode %d", devices, mode); + mCallMode = mode; + switchDevice(handle, devices, mode); + return status; +} + +int ALSADevice::getUseCaseType(const char *useCase) +{ + ALOGV("use case is %s\n", useCase); + if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI2, + MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI2, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) || + !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, + MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, + MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) { + return USECASE_TYPE_RX; + } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, + MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) || + !strncmp(useCase, SND_USE_CASE_VERB_FM_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, + MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, + MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + return USECASE_TYPE_TX; + } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL, + MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) || + !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL, + MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) || + !strncmp(useCase, SND_USE_CASE_VERB_DL_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC, + MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, + MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) || + !strncmp(useCase, SND_USE_CASE_VERB_VOICE2, + MAX_LEN(useCase, SND_USE_CASE_VERB_VOICE2)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE2, + MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOICE2)) || + !strncmp(useCase, SND_USE_CASE_VERB_VOLTE, + MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE, + MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) { + return (USECASE_TYPE_RX | USECASE_TYPE_TX); + } else { + ALOGV("unknown use case %s\n", useCase); + return 0; + } +} + +void ALSADevice::disableDevice(alsa_handle_t *handle) +{ + unsigned usecase_type = 0; + int i, mods_size; + char *useCase; + const char **mods_list; + + snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase); + if (useCase != NULL) { + if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) { + snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE); + } else { + snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase); + } + free(useCase); + snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase); + if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE, + strlen(SND_USE_CASE_VERB_INACTIVE))) + usecase_type |= getUseCaseType(useCase); + mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list); + ALOGV("Number of modifiers %d\n", mods_size); + if (mods_size) { + for(i = 0; i < mods_size; i++) { + ALOGV("index %d modifier %s\n", i, mods_list[i]); + usecase_type |= getUseCaseType(mods_list[i]); + } + } + ALOGV("usecase_type is %d\n", usecase_type); + if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(mCurTxUCMDevice, "None", 4))) + snd_use_case_set(handle->ucMgr, "_disdev", mCurTxUCMDevice); + if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(mCurRxUCMDevice, "None", 4))) + snd_use_case_set(handle->ucMgr, "_disdev", mCurRxUCMDevice); + } else { + ALOGE("Invalid state, no valid use case found to disable"); + } + free(useCase); +} + +char *ALSADevice::getUCMDeviceFromAcdbId(int acdb_id) +{ + switch(acdb_id) { + case DEVICE_HANDSET_RX_ACDB_ID: + return strdup(SND_USE_CASE_DEV_HANDSET); + case DEVICE_SPEAKER_MONO_RX_ACDB_ID: + case DEVICE_SPEAKER_RX_ACDB_ID: + return strdup(SND_USE_CASE_DEV_SPEAKER); + case DEVICE_HEADSET_RX_ACDB_ID: + return strdup(SND_USE_CASE_DEV_HEADPHONES); + case DEVICE_TTY_HEADSET_MONO_RX_ACDB_ID: + return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX); + case DEVICE_ANC_HEADSET_STEREO_RX_ACDB_ID: + return strdup(SND_USE_CASE_DEV_ANC_HEADSET); + default: + return NULL; + } +} + +char* ALSADevice::getUCMDevice(uint32_t devices, int input, char *rxDevice) +{ + if (!input) { + ALOGV("getUCMDevice for output device: devices:%x is input device:%d",devices,input); + if (!(mDevSettingsFlag & TTY_OFF) && + (mCallMode == AUDIO_MODE_IN_CALL) && + ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) + || (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) +#ifdef QCOM_ANC_HEADSET_ENABLED + || (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) + || (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) +#endif + )) { + if (mDevSettingsFlag & TTY_VCO) { + return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX); + } else if (mDevSettingsFlag & TTY_FULL) { + return strdup(SND_USE_CASE_DEV_TTY_FULL_RX); + } else if (mDevSettingsFlag & TTY_HCO) { + return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */ + } + } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP && + devices & AudioSystem::DEVICE_OUT_SPEAKER) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); + } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP) { + return strdup(SND_USE_CASE_DEV_PROXY_RX); + } else if (devices & AUDIO_DEVICE_OUT_ALL_USB && + devices & AudioSystem::DEVICE_OUT_SPEAKER) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); + } else if (devices & AUDIO_DEVICE_OUT_ALL_USB) { + return strdup(SND_USE_CASE_DEV_PROXY_RX); + } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET || + devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) && + devices & AudioSystem::DEVICE_OUT_SPEAKER) { + return strdup(SND_USE_CASE_DEV_USB_PROXY_RX_SPEAKER); /* USB PROXY RX + SPEAKER */ + } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) { + return strdup(SND_USE_CASE_DEV_USB_PROXY_RX); /* PROXY RX */ +#ifdef QCOM_PROXY_DEVICE_ENABLED + } else if( (devices & AudioSystem::DEVICE_OUT_SPEAKER) && + (devices & AudioSystem::DEVICE_OUT_PROXY) && + ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) ) ) { + if (mDevSettingsFlag & ANC_FLAG) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER_ANC_HEADSET); + } else { + return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER_HEADSET); + } +#endif + } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && + ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) { + if (mDevSettingsFlag & ANC_FLAG) { + return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */ + } else { + return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */ + } + } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && + ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) { + return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER); +#ifdef QCOM_ANC_HEADSET_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) && + ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET)|| + (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) ) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET); + } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && + ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) { + return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */ +#endif +#ifdef QCOM_FM_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && + (devices & AudioSystem::DEVICE_OUT_FM_TX)) { + return strdup(SND_USE_CASE_DEV_SPEAKER_FM_TX); /* COMBO SPEAKER+FM_TX RX */ +#endif +#ifdef QCOM_PROXY_DEVICE_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && + (devices & AudioSystem::DEVICE_OUT_PROXY)) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); /* COMBO SPEAKER + PROXY RX */ + } else if ((devices & AudioSystem::DEVICE_OUT_EARPIECE) && + (devices & AudioSystem::DEVICE_OUT_PROXY)) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_HANDSET); /* COMBO EARPIECE + PROXY RX */ +#endif + } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) { + if (mCallMode == AUDIO_MODE_IN_CALL || + mCallMode == AUDIO_MODE_IN_COMMUNICATION) { + if (shouldUseHandsetAnc(mDevSettingsFlag, mInChannels)) { + return strdup(SND_USE_CASE_DEV_ANC_HANDSET); /* ANC Handset RX */ + } else { + return strdup(SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */ + } + } else { + return strdup(SND_USE_CASE_DEV_EARPIECE); /* HANDSET RX */ + } + } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) { + return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */ + } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) { + if (mDevSettingsFlag & ANC_FLAG) { + if (mCallMode == AUDIO_MODE_IN_CALL || + mCallMode == AUDIO_MODE_IN_COMMUNICATION) { + return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */ + } else { + return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */ + } + } else { + if (mCallMode == AUDIO_MODE_IN_CALL || + mCallMode == AUDIO_MODE_IN_COMMUNICATION) { + return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */ + } else { + return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */ + } + } +#ifdef QCOM_ANC_HEADSET_ENABLED + } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) && + ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) { + if (mDevSettingsFlag & ANC_FLAG) { + return strdup(SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET); + } else { + return strdup(SND_USE_CASE_DEV_PROXY_RX_HEADSET); + } + } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) { + if (mCallMode == AUDIO_MODE_IN_CALL || + mCallMode == AUDIO_MODE_IN_COMMUNICATION) { + return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */ + } else { + return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */ + } +#endif + } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) || + (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) || + (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) { + if (mBtscoSamplerate == BTSCO_RATE_16KHZ) + return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/ + else + return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/ + } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) { + return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */ +#ifdef QCOM_PROXY_DEVICE_ENABLED + } else if (devices & AudioSystem::DEVICE_OUT_PROXY) { + return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */ +#endif +#ifdef QCOM_FM_ENABLED + } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) { + return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */ +#endif + } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) { + return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */ + } else { + ALOGD("No valid output device: %u", devices); + } + } else { + ALOGV("getUCMDevice for input device: devices:%x is input device:%d",devices,input); + if (!(mDevSettingsFlag & TTY_OFF) && + (mCallMode == AUDIO_MODE_IN_CALL) && + ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) +#ifdef QCOM_ANC_HEADSET_ENABLED + || (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) +#endif + )) { + if (mDevSettingsFlag & TTY_HCO) { + return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX); + } else if (mDevSettingsFlag & TTY_FULL) { + return strdup(SND_USE_CASE_DEV_TTY_FULL_TX); + } else if (mDevSettingsFlag & TTY_VCO) { + if (!strncmp(mMicType, "analog", 6)) { + return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX); + } else { + return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX); + } + } + } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) { + if (!strncmp(mMicType, "analog", 6)) { + return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */ + } else { + if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels == 1)) { +#ifdef USES_FLUENCE_INCALL + if(callMode == AUDIO_MODE_IN_CALL) { + if (fluence_mode == FLUENCE_MODE_ENDFIRE) { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */ + } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */ + } else { + return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */ + } + } +#else + if (((rxDevice != NULL) && + !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER, + (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) || + ((rxDevice == NULL) && + !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, + (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) { + if (mFluenceMode == FLUENCE_MODE_ENDFIRE) { + if (mIsSglte == false) { + return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */ + } + else { + return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE_SGLTE); /* DUALMIC EF TX */ + } + } else if (mFluenceMode == FLUENCE_MODE_BROADSIDE) { + return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */ + } + } else { + if (mFluenceMode == FLUENCE_MODE_ENDFIRE) { + if (mIsSglte == false) { + if ((rxDevice != NULL) && + !strncmp(rxDevice, SND_USE_CASE_DEV_ANC_HANDSET, + strlen(SND_USE_CASE_DEV_ANC_HANDSET) + 1)) { + /* if using ANC_HANDSET, already in-call */ + return strdup(SND_USE_CASE_DEV_AANC_DMIC_ENDFIRE); /* DUALMIC AANC TX */ + } else { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */ + } + } + else { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_SGLTE); /* DUALMIC EF TX */ + } + } else if (mFluenceMode == FLUENCE_MODE_BROADSIDE) { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */ + } + } +#endif + } else if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels > 1)) { + if (((rxDevice != NULL) && + !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER, + (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) || + ((rxDevice == NULL) && + !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, + (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) { + if (mIsSglte == false) { + return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO); /* DUALMIC EF TX */ + } + else { + return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO_SGLTE); /* DUALMIC EF TX */ + } + } else { + if (mIsSglte == false) { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO); /* DUALMIC EF TX */ + } + else { + return strdup(SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO_SGLTE); /* DUALMIC EF TX */ + } + } + } else if ((mDevSettingsFlag & QMIC_FLAG) && (mInChannels == 1)) { + if (((rxDevice != NULL) && + !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER, + (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) || + ((rxDevice == NULL) && + !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, + (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) { + return strdup(SND_USE_CASE_DEV_QUAD_MIC); /* QUADMIC TX */ + } else { + if ((rxDevice != NULL) && + !strncmp(rxDevice, SND_USE_CASE_DEV_ANC_HANDSET, + strlen(SND_USE_CASE_DEV_ANC_HANDSET) + 1)) { + /* if using ANC_HANDSET, already in-call */ + return strdup(SND_USE_CASE_DEV_AANC_LINE); /* AANC LINE TX */ + } else { + return strdup(SND_USE_CASE_DEV_LINE); + } + } + } +#ifdef QCOM_SSR_ENABLED + else if ((mDevSettingsFlag & QMIC_FLAG) && (mInChannels > 1)) { + return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); + } else if ((mDevSettingsFlag & SSRQMIC_FLAG) && (mInChannels > 1)){ + ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices); + // Mapping for quad mic input device. + return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */ + } +#endif +#ifdef SEPERATED_AUDIO_INPUT + if(mInput_source == AUDIO_SOURCE_VOICE_RECOGNITION) { + return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */ + } +#endif + else { + if ((rxDevice != NULL) && + !strncmp(rxDevice, SND_USE_CASE_DEV_ANC_HANDSET, + strlen(SND_USE_CASE_DEV_ANC_HANDSET) + 1)) { + return strdup(SND_USE_CASE_DEV_AANC_LINE); /* AANC LINE TX */ + } else { + return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */ + } + } + } + } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) { + return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */ + } else if ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) { + return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */ +#ifdef QCOM_ANC_HEADSET_ENABLED + } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) { + return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */ +#endif + } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + if (mBtscoSamplerate == BTSCO_RATE_16KHZ) + return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/ + else + return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/ +#ifdef QCOM_USBAUDIO_ENABLED + } else if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) { + if ((mCallMode == AUDIO_MODE_IN_CALL) || + (mCallMode == AUDIO_MODE_IN_COMMUNICATION)) { + if ((rxDevice != NULL) && + (!strncmp(rxDevice, SND_USE_CASE_DEV_USB_PROXY_RX, + (strlen(SND_USE_CASE_DEV_USB_PROXY_RX)+1)))) { + return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */ + } else if ((rxDevice != NULL) && + (!strncmp(rxDevice, SND_USE_CASE_DEV_PROXY_RX, + (strlen(SND_USE_CASE_DEV_PROXY_RX)+1)))) { + return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */ + } else { + return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */ + } + } else { + return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */ + } +#endif +#ifdef QCOM_PROXY_DEVICE_ENABLED + } else if (devices & AudioSystem::DEVICE_IN_PROXY) { + return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */ +#endif + } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) || + (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) { + /* Nothing to be done, use current active device */ + if (strncmp(mCurTxUCMDevice, "None", 4)) { + return strdup(mCurTxUCMDevice); + } +#ifdef QCOM_FM_ENABLED + } else if ((devices & AudioSystem::DEVICE_IN_FM_RX) || + (devices & AudioSystem::DEVICE_IN_FM_RX_A2DP)) { + /* Nothing to be done, use current tx device or set dummy device */ + if (strncmp(mCurTxUCMDevice, "None", 4)) { + return strdup(mCurTxUCMDevice); + } else { + return strdup(SND_USE_CASE_DEV_DUMMY_TX); + } +#endif + } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) || + (devices & AudioSystem::DEVICE_IN_BACK_MIC)) { + ALOGI("No proper mapping found with UCM device list, setting default"); + if (!strncmp(mMicType, "analog", 6)) { + return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */ + } else { +#ifdef SEPERATED_AUDIO_INPUT + if (callMode == AUDIO_MODE_IN_CALL) { + return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */ + } else if(mInput_source == AUDIO_SOURCE_CAMCORDER) { + return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */ + } else +#endif + return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */ + } + } else { + ALOGD("No valid input device: %u", devices); + } + } + return NULL; +} + +void ALSADevice::setVoiceVolume(int vol) +{ + int err = 0; + + ALOGD("setVoiceVolume: volume %d", vol); + setMixerControl("Voice Rx Volume", vol, 0); + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_volume == NULL) { + ALOGE("csd_client_volume is NULL"); + } else { + err = csd_volume(ALL_SESSION_VSID, vol); + if (err < 0) { + ALOGE("s_set_voice_volume: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::setVoice2Volume(int vol) +{ + int err = 0; + + ALOGD("setVoice2Volume: volume %d", vol); + setMixerControl("Voice2 Rx Volume", vol, 0); + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_volume == NULL) { + ALOGE("csd_client_volume is NULL"); + } else { + err = csd_volume(ALL_SESSION_VSID, vol); + if (err < 0) { + ALOGE("s_set_voice_volume: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::setVoLTEVolume(int vol) +{ + int err = 0; + + ALOGD("setVoLTEVolume: volume %d", vol); + setMixerControl("VoLTE Rx Volume", vol, 0); + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_volume == NULL) { + ALOGE("csd_client_volume is NULL"); + } else { + err = csd_volume(ALL_SESSION_VSID, vol); + if (err < 0) { + ALOGE("s_set_voice_volume: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::setVoipVolume(int vol) +{ + ALOGD("setVoipVolume: volume %d", vol); + setMixerControl("Voip Rx Volume", vol, 0); +} + +void ALSADevice::setMicMute(int state) +{ + int err = 0; + + ALOGD("setMicMute: state %d", state); + setMixerControl("Voice Tx Mute", state, 0); + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_mic_mute == NULL) { + ALOGE("csd_mic_mute is NULL"); + } else { + err = csd_mic_mute(ALL_SESSION_VSID, state); + if (err < 0) { + ALOGE("s_set_mic_mute: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::setVoice2MicMute(int state) +{ + int err = 0; + + ALOGD("setVoice2MicMute: state %d", state); + setMixerControl("Voice2 Tx Mute", state, 0); + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_mic_mute == NULL) { + ALOGE("csd_mic_mute is NULL"); + } else { + err = csd_mic_mute(ALL_SESSION_VSID, state); + if (err < 0) { + ALOGE("s_set_mic_mute: csd_client error %d", err); + } + } + + } +#endif +} + +void ALSADevice::setVoLTEMicMute(int state) +{ + int err = 0; + + ALOGD("setVolteMicMute: state %d", state); + setMixerControl("VoLTE Tx Mute", state, 0); + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_mic_mute == NULL) { + ALOGE("csd_mic_mute is NULL"); + } else { + err = csd_mic_mute(ALL_SESSION_VSID, state); + if (err < 0) { + ALOGE("s_set_mic_mute: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::setVoipMicMute(int state) +{ + ALOGD("setVoipMicMute: state %d", state); + setMixerControl("Voip Tx Mute", state, 0); +} + +void ALSADevice::setVoipConfig(int mode, int rate) +{ + char** setValues; + ALOGD("setVoipConfig: mode %d,rate %d", mode, rate); + + setValues = (char**)malloc(2*sizeof(char*)); + if (setValues == NULL) { + return; + } + setValues[0] = (char*)malloc(4*sizeof(char)); + if (setValues[0] == NULL) { + free(setValues); + return; + } + + setValues[1] = (char*)malloc(8*sizeof(char)); + if (setValues[1] == NULL) { + free(setValues); + free(setValues[0]); + return; + } + + sprintf(setValues[0], "%d",mode); + sprintf(setValues[1], "%d",rate); + + setMixerControlExt("Voip Mode Rate Config", 2, setValues); + free(setValues[1]); + free(setValues[0]); + free(setValues); + return; +} + +void ALSADevice::setBtscoRate(int rate) +{ + mBtscoSamplerate = rate; +} + +void ALSADevice::enableWideVoice(bool flag, uint32_t vsid) +{ + int err = 0; + + ALOGD("enableWideVoice: flag %d", flag); + if(flag == true) { + setMixerControl("Widevoice Enable", 1, 0); + } else { + setMixerControl("Widevoice Enable", 0, 0); + } + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_wide_voice == NULL) { + ALOGE("csd_wide_voice is NULL"); + } else { + err = csd_wide_voice(vsid, flag); + if (err < 0) { + ALOGE("enableWideVoice: csd_client_wide_voice error %d", err); + } + } + } +#endif +} + +void ALSADevice::setVocRecMode(uint8_t mode) +{ + ALOGD("setVocRecMode: mode %d", mode); + setMixerControl("Incall Rec Mode", mode, 0); +} + +void ALSADevice::enableFENS(bool flag, uint32_t vsid) +{ + int err = 0; + + ALOGD("enableFENS: flag %d", flag); + if(flag == true) { + setMixerControl("FENS Enable", 1, 0); + setMixerControl("FENS_VOIP Enable", 1 , 0); + } else { + setMixerControl("FENS Enable", 0, 0); + setMixerControl("FENS_VOIP Enable", 0 , 0); + } + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_fens == NULL) { + ALOGE("csd_fens is NULL"); + } else { + err = csd_fens(vsid, flag); + if (err < 0) { + ALOGE("s_enable_fens: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::enableSlowTalk(bool flag, uint32_t vsid) +{ + int err = 0; + + ALOGD("enableSlowTalk: flag %d", flag); + if(flag == true) { + setMixerControl("Slowtalk Enable", 1, 0); + } else { + setMixerControl("Slowtalk Enable", 0, 0); + } + +#ifdef QCOM_CSDCLIENT_ENABLED + if (isPlatformFusion3()) { + if (csd_slow_talk == NULL) { + ALOGE("csd_slow_talk is NULL"); + } else { + err = csd_slow_talk(vsid, flag); + if (err < 0) { + ALOGE("s_enable_slow_talk: csd_client error %d", err); + } + } + } +#endif +} + +void ALSADevice::setFlags(uint32_t flags) +{ + ALOGV("setFlags: flags %d", flags); + mDevSettingsFlag = flags; +} + +status_t ALSADevice::setCompressedVolume(int value) +{ + status_t err = NO_ERROR; + + setMixerControl("COMPRESSED RX Volume",value,0); + + return err; +} + +status_t ALSADevice::setChannelMap(alsa_handle_t *handle, int maxChannels) +{ + status_t status = NO_ERROR; + char channelMap[maxChannels]; + + memset(channelMap, 0, sizeof(channelMap)); + switch (handle->channels) { + case 3: + case 4: + case 5: + ALOGE("TODO: Investigate and add appropriate channel map appropriately"); + break; + case 6: + channelMap[0] = PCM_CHANNEL_FL; + channelMap[1] = PCM_CHANNEL_FR; + channelMap[2] = PCM_CHANNEL_FC; + channelMap[3] = PCM_CHANNEL_LFE; + channelMap[4] = PCM_CHANNEL_LB; + channelMap[5] = PCM_CHANNEL_RB; + break; + case 7: + case 8: + channelMap[0] = PCM_CHANNEL_FL; + channelMap[1] = PCM_CHANNEL_FR; + channelMap[2] = PCM_CHANNEL_FC; + channelMap[3] = PCM_CHANNEL_LFE; + channelMap[4] = PCM_CHANNEL_LB; + channelMap[5] = PCM_CHANNEL_RB; + channelMap[6] = PCM_CHANNEL_FLC; + channelMap[7] = PCM_CHANNEL_FRC; + break; + default: + ALOGE("un supported channels for setting channel map"); + return -1; + } + + if(handle) + status = pcm_set_channel_map(handle->handle, mMixer, + maxChannels, channelMap); + return status; +} + +void ALSADevice::setChannelAlloc(int channelAlloc) +{ + ALOGV("channel allocation = 0x%x", channelAlloc); + char** setValues; + setValues = (char**)malloc(sizeof(char*)); + if (setValues == NULL) { + return; + } + setValues[0] = (char*)malloc(4*sizeof(char)); + if (setValues[0] == NULL) { + free(setValues); + return; + } + sprintf(setValues[0], "%d", channelAlloc); + setMixerControlExt("HDMI RX CA", 1, setValues); + free(setValues[0]); + free(setValues); + return; +} + +status_t ALSADevice::getMixerControl(const char *name, unsigned int &value, int index) +{ + struct mixer_ctl *ctl; + + if (!mMixer) { + ALOGE("Control not initialized"); + return NO_INIT; + } + + ctl = mixer_get_control(mMixer, name, index); + if (!ctl) + return BAD_VALUE; + + mixer_ctl_get(ctl, &value); + return NO_ERROR; +} + +status_t ALSADevice::getMixerControlExt(const char *name, unsigned **getValues, unsigned *count) +{ + struct mixer_ctl *ctl; + + if (!mMixer) { + ALOGE("Control not initialized"); + return NO_INIT; + } + + ctl = mixer_get_control(mMixer, name, 0); + if (!ctl) + return BAD_VALUE; + + mixer_ctl_get_mulvalues(ctl, getValues, count); + return NO_ERROR; +} + +status_t ALSADevice::setMixerControl(const char *name, unsigned int value, int index) +{ + struct mixer_ctl *ctl; + int ret = 0; + ALOGD("setMixerControl:: name %s value %d index %d", name, value, index); + if (!mMixer) { + ALOGE("Control not initialized"); + return NO_INIT; + } + + // ToDo: Do we need to send index here? Right now it works with 0 + ctl = mixer_get_control(mMixer, name, 0); + if(ctl == NULL) { + ALOGE("Could not get the mixer control"); + return BAD_VALUE; + } + ret = mixer_ctl_set(ctl, value); + return (ret < 0) ? BAD_VALUE : NO_ERROR; +} + +status_t ALSADevice::setMixerControl(const char *name, const char *value) +{ + struct mixer_ctl *ctl; + int ret = 0; + ALOGD("setMixerControl:: name %s value %s", name, value); + + if (!mMixer) { + ALOGE("Control not initialized"); + return NO_INIT; + } + + ctl = mixer_get_control(mMixer, name, 0); + if(ctl == NULL) { + ALOGE("Could not get the mixer control"); + return BAD_VALUE; + } + ret = mixer_ctl_select(ctl, value); + return (ret < 0) ? BAD_VALUE : NO_ERROR; +} + +status_t ALSADevice::setMixerControlExt(const char *name, int count, char **setValues) +{ + struct mixer_ctl *ctl; + int ret = 0; + ALOGD("setMixerControl:: name %s count %d", name, count); + if (!mMixer) { + ALOGE("Control not initialized"); + return NO_INIT; + } + + // ToDo: Do we need to send index here? Right now it works with 0 + ctl = mixer_get_control(mMixer, name, 0); + if(ctl == NULL) { + ALOGE("Could not get the mixer control"); + return BAD_VALUE; + } + ret = mixer_ctl_set_value(ctl, count, setValues); + return (ret < 0) ? BAD_VALUE : NO_ERROR; +} + +status_t ALSADevice::setEcrxDevice(char *device) +{ + status_t err = NO_ERROR; + setMixerControl("EC_REF_RX", device); + return err; +} + +void ALSADevice::setInChannels(int channels) +{ + mInChannels = channels; + ALOGV("mInChannels:%d", mInChannels); +} + +status_t ALSADevice::exitReadFromProxy() +{ + ALOGV("exitReadFromProxy"); + mProxyParams.mExitRead = true; + if(mProxyParams.mPfdProxy[1].fd != -1) { + uint64_t writeValue = KILL_A2DP_THREAD; + ALOGD("Writing to mPfdProxy[1].fd %d",mProxyParams.mPfdProxy[1].fd); + write(mProxyParams.mPfdProxy[1].fd, &writeValue, sizeof(uint64_t)); + } + return NO_ERROR; +} + +void ALSADevice::resetProxyVariables() { + + mProxyParams.mAvail = 0; + mProxyParams.mFrames = 0; + mProxyParams.mX.frames = 0; + if(mProxyParams.mPfdProxy[1].fd != -1) { + sys_close::lib_close(mProxyParams.mPfdProxy[1].fd); + mProxyParams.mPfdProxy[1].fd = -1; + } +} + +ssize_t ALSADevice::readFromProxy(void **captureBuffer , ssize_t *bufferSize) { + + status_t err = NO_ERROR; + int err_poll = 0; + initProxyParams(); + err = startProxy(); + if(err) { + ALOGE("ReadFromProxy-startProxy returned err = %d", err); + *captureBuffer = NULL; + *bufferSize = 0; + return err; + } + struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle; + + while(!mProxyParams.mExitRead) { + ALOGV("Calling sync_ptr(proxy"); + err = sync_ptr(capture_handle); + if(err == EPIPE) { + ALOGE("Failed in sync_ptr \n"); + /* we failed to make our window -- try to restart */ + capture_handle->underruns++; + capture_handle->running = 0; + capture_handle->start = 0; + continue; + } else if (err != NO_ERROR) { + ALOGE("Error: Sync ptr returned %d", err); + break; + } + + mProxyParams.mAvail = pcm_avail(capture_handle); + ALOGV("avail is = %d frames = %ld, avai_min = %d\n",\ + mProxyParams.mAvail, mProxyParams.mFrames,(int)capture_handle->sw_p->avail_min); + if (mProxyParams.mAvail < capture_handle->sw_p->avail_min) { + err_poll = poll(mProxyParams.mPfdProxy, NUM_FDS, TIMEOUT_INFINITE); + if (mProxyParams.mPfdProxy[1].revents & POLLIN) { + ALOGV("Event on userspace fd"); + } + if ((mProxyParams.mPfdProxy[1].revents & POLLERR) || + (mProxyParams.mPfdProxy[1].revents & POLLNVAL)) { + ALOGV("POLLERR or INVALID POLL"); + err = BAD_VALUE; + break; + } + if((mProxyParams.mPfdProxy[0].revents & POLLERR) || + (mProxyParams.mPfdProxy[0].revents & POLLNVAL)) { + ALOGV("POLLERR or INVALID POLL on zero"); + err = BAD_VALUE; + break; + } + if (mProxyParams.mPfdProxy[0].revents & POLLIN) { + ALOGV("POLLIN on zero"); + } + ALOGV("err_poll = %d",err_poll); + continue; + } + break; + } + if(err != NO_ERROR) { + ALOGE("Reading from proxy failed = err = %d", err); + *captureBuffer = NULL; + *bufferSize = 0; + return err; + } + if (mProxyParams.mX.frames > mProxyParams.mAvail) + mProxyParams.mFrames = mProxyParams.mAvail; + void *data = dst_address(capture_handle); + //TODO: Return a pointer to AudioHardware + if(mProxyParams.mCaptureBuffer == NULL) + mProxyParams.mCaptureBuffer = malloc(mProxyParams.mCaptureBufferSize); + memcpy(mProxyParams.mCaptureBuffer, (char *)data, + mProxyParams.mCaptureBufferSize); + mProxyParams.mX.frames -= mProxyParams.mFrames; + capture_handle->sync_ptr->c.control.appl_ptr += mProxyParams.mFrames; + capture_handle->sync_ptr->flags = 0; + ALOGV("Calling sync_ptr for proxy after sync"); + err = sync_ptr(capture_handle); + if(err == EPIPE) { + ALOGV("Failed in sync_ptr \n"); + capture_handle->running = 0; + err = sync_ptr(capture_handle); + } + if(err != NO_ERROR ) { + ALOGE("Error: Sync ptr end returned %d", err); + *captureBuffer = NULL; + *bufferSize = 0; + return err; + } + *captureBuffer = mProxyParams.mCaptureBuffer; + *bufferSize = mProxyParams.mCaptureBufferSize; + return err; +} + +void ALSADevice::initProxyParams() { + if(mProxyParams.mPfdProxy[1].fd == -1) { + ALOGV("Allocating A2Dp poll fd"); + mProxyParams.mPfdProxy[0].fd = mProxyParams.mProxyPcmHandle->fd; + mProxyParams.mPfdProxy[0].events = (POLLIN | POLLERR | POLLNVAL); + ALOGV("Allocated A2DP poll fd"); + mProxyParams.mPfdProxy[1].fd = eventfd(0,0); + mProxyParams.mPfdProxy[1].events = (POLLIN | POLLERR | POLLNVAL); + mProxyParams.mFrames = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ? + (mProxyParams.mProxyPcmHandle->period_size / 2) : + (mProxyParams.mProxyPcmHandle->period_size / 4); + mProxyParams.mX.frames = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ? + (mProxyParams.mProxyPcmHandle->period_size / 2) : + (mProxyParams.mProxyPcmHandle->period_size / 4); + } +} + +status_t ALSADevice::startProxy() { + + status_t err = NO_ERROR; + struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle; + while(1) { + if (!capture_handle->start) { + if(ioctl(capture_handle->fd, SNDRV_PCM_IOCTL_START)) { + err = -errno; + if (errno == EPIPE) { + ALOGV("Failed in SNDRV_PCM_IOCTL_START\n"); + /* we failed to make our window -- try to restart */ + capture_handle->underruns++; + capture_handle->running = 0; + capture_handle->start = 0; + continue; + } else { + ALOGE("IGNORE - IOCTL_START failed for proxy err: %d \n", errno); + err = NO_ERROR; + break; + } + } else { + ALOGD(" Proxy Driver started(IOCTL_START Success)\n"); + break; + } + } + else { + ALOGV("Proxy Already started break out of condition"); + break; + } + } + ALOGV("startProxy - Proxy started"); + capture_handle->start = 1; + capture_handle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN; + return err; +} + +status_t ALSADevice::openProxyDevice() +{ + struct snd_pcm_hw_params *params = NULL; + struct snd_pcm_sw_params *sparams = NULL; + int flags = (DEBUG_ON | PCM_MMAP| PCM_STEREO | PCM_IN); + + ALOGV("openProxyDevice"); + mProxyParams.mProxyPcmHandle = pcm_open(flags, PROXY_CAPTURE_DEVICE_NAME); + if (!pcm_ready(mProxyParams.mProxyPcmHandle)) { + ALOGE("Opening proxy device failed"); + goto bail; + } + ALOGV("Proxy device opened successfully: mProxyPcmHandle %p", mProxyParams.mProxyPcmHandle); + mProxyParams.mProxyPcmHandle->channels = AFE_PROXY_CHANNEL_COUNT; + mProxyParams.mProxyPcmHandle->rate = AFE_PROXY_SAMPLE_RATE; + mProxyParams.mProxyPcmHandle->flags = flags; + mProxyParams.mProxyPcmHandle->period_size = AFE_PROXY_PERIOD_SIZE; + mProxyParams.mBufferTime = (AFE_PROXY_PERIOD_SIZE*1000)/(AFE_PROXY_CHANNEL_COUNT*AFE_PROXY_SAMPLE_RATE*2); + + params = (struct snd_pcm_hw_params*) calloc(1,sizeof(struct snd_pcm_hw_params)); + if (!params) { + goto bail; + } + + param_init(params); + + param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS, + (mProxyParams.mProxyPcmHandle->flags & PCM_MMAP)? + SNDRV_PCM_ACCESS_MMAP_INTERLEAVED + : SNDRV_PCM_ACCESS_RW_INTERLEAVED); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S16_LE); + param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_SUBFORMAT_STD); + param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + mProxyParams.mProxyPcmHandle->period_size); + param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16); + param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS, + mProxyParams.mProxyPcmHandle->channels - 1 ? 32 : 16); + param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS, + mProxyParams.mProxyPcmHandle->channels); + param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, + mProxyParams.mProxyPcmHandle->rate); + + param_set_hw_refine(mProxyParams.mProxyPcmHandle, params); + + if (param_set_hw_params(mProxyParams.mProxyPcmHandle, params)) { + ALOGE("Failed to set hardware params on Proxy device"); + goto bail; + } + + mProxyParams.mProxyPcmHandle->buffer_size = pcm_buffer_size(params); + mProxyParams.mProxyPcmHandle->period_size = pcm_period_size(params); + mProxyParams.mProxyPcmHandle->period_cnt = + mProxyParams.mProxyPcmHandle->buffer_size / + mProxyParams.mProxyPcmHandle->period_size; + ALOGV("Capture - period_size (%d)",\ + mProxyParams.mProxyPcmHandle->period_size); + ALOGV("Capture - buffer_size (%d)",\ + mProxyParams.mProxyPcmHandle->buffer_size); + ALOGV("Capture - period_cnt (%d)\n",\ + mProxyParams.mProxyPcmHandle->period_cnt); + sparams = (struct snd_pcm_sw_params*) calloc(1,sizeof(struct snd_pcm_sw_params)); + if (!sparams) { + ALOGE("Failed to allocated software params for Proxy device"); + goto bail; + } + + sparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; + sparams->period_step = 1; + sparams->avail_min = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ? + mProxyParams.mProxyPcmHandle->period_size/2 + : mProxyParams.mProxyPcmHandle->period_size/4; + sparams->start_threshold = 1; + sparams->stop_threshold = mProxyParams.mProxyPcmHandle->buffer_size; + sparams->xfer_align = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ? + mProxyParams.mProxyPcmHandle->period_size/2 + : mProxyParams.mProxyPcmHandle->period_size/4; /* needed for old kernels */ + sparams->silence_size = 0; + sparams->silence_threshold = 0; + + if (param_set_sw_params(mProxyParams.mProxyPcmHandle, sparams)) { + ALOGE("Failed to set software params on Proxy device"); + goto bail; + } + mmap_buffer(mProxyParams.mProxyPcmHandle); + + if (pcm_prepare(mProxyParams.mProxyPcmHandle)) { + ALOGE("Failed to pcm_prepare on Proxy device"); + goto bail; + } + mProxyParams.mProxyState = proxy_params::EProxySuspended; + return NO_ERROR; + +bail: + if(mProxyParams.mProxyPcmHandle) { + pcm_close(mProxyParams.mProxyPcmHandle); + mProxyParams.mProxyPcmHandle = NULL; + } + mProxyParams.mProxyState = proxy_params::EProxyClosed; + return NO_INIT; +} + +status_t ALSADevice::closeProxyDevice() { + status_t err = NO_ERROR; + if(mProxyParams.mProxyPcmHandle) { + pcm_close(mProxyParams.mProxyPcmHandle); + mProxyParams.mProxyPcmHandle = NULL; + } + resetProxyVariables(); + mProxyParams.mProxyState = proxy_params::EProxyClosed; + mProxyParams.mExitRead = false; + return err; +} + +bool ALSADevice::isProxyDeviceOpened() { + + //TODO : Add some intelligence to return appropriate value + if(mProxyParams.mProxyState == proxy_params::EProxyOpened || + mProxyParams.mProxyState == proxy_params::EProxyCapture || + mProxyParams.mProxyState == proxy_params::EProxySuspended) + return true; + return false; +} + +bool ALSADevice::isProxyDeviceSuspended() { + + if(mProxyParams.mProxyState == proxy_params::EProxySuspended) + return true; + return false; +} + +bool ALSADevice::suspendProxy() { + + status_t err = NO_ERROR; + if(mProxyParams.mProxyState == proxy_params::EProxyOpened || + mProxyParams.mProxyState == proxy_params::EProxyCapture) { + mProxyParams.mProxyState = proxy_params::EProxySuspended; + } + else { + ALOGE("Proxy already suspend or closed, in state = %d",\ + mProxyParams.mProxyState); + } + return err; +} + +bool ALSADevice::resumeProxy() { + + status_t err = NO_ERROR; + struct pcm *capture_handle= mProxyParams.mProxyPcmHandle; + ALOGD("resumeProxy mProxyParams.mProxyState = %d, capture_handle =%p",\ + mProxyParams.mProxyState, capture_handle); + if((mProxyParams.mProxyState == proxy_params::EProxyOpened || + mProxyParams.mProxyState == proxy_params::EProxySuspended) && + capture_handle != NULL) { + ALOGV("pcm_prepare from Resume"); + capture_handle->start = 0; + err = pcm_prepare(capture_handle); + if(err != OK) { + ALOGE("IGNORE: PCM Prepare - capture failed err = %d", err); + } + err = startProxy(); + if(err) { + ALOGE("IGNORE:startProxy returned error = %d", err); + } + mProxyParams.mProxyState = proxy_params::EProxyCapture; + err = sync_ptr(capture_handle); + if (err) { + ALOGE("IGNORE: sync ptr from resumeProxy returned error = %d", err); + } + ALOGV("appl_ptr= %d", (int)capture_handle->sync_ptr->c.control.appl_ptr); + } + else { + ALOGV("resume Proxy ignored in invalid state - ignore"); + if(mProxyParams.mProxyState == proxy_params::EProxyClosed || + capture_handle == NULL) { + ALOGE("resumeProxy = BAD_VALUE"); + err = BAD_VALUE; + return err; + } + } + return NO_ERROR; +} + +status_t ALSADevice::getEDIDData(char *hdmiEDIDData) +{ + status_t err = NO_ERROR; + unsigned **EDIDData; + EDIDData = (unsigned **)malloc((MAX_SHORT_AUDIO_DESC_CNT + 1)*sizeof(unsigned*)); + // additional 1 byte for length of the EDID + unsigned count; + if(EDIDData) { + for (int i=0; i(handle); + ALOGI("%s csd_handle: %p", __func__, mcsd_handle); + + csd_disable_device = (int (*)())::dlsym(mcsd_handle, + "csd_client_disable_device"); + csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(mcsd_handle, + "csd_client_enable_device"); + csd_enable_device_config = (int (*)(int,int))::dlsym(mcsd_handle, + "csd_client_enable_device_config"); + csd_start_voice = (int (*)(uint32_t))::dlsym(mcsd_handle, + "csd_client_start_voice"); + csd_stop_voice = (int (*)(uint32_t))::dlsym(mcsd_handle, + "csd_client_stop_voice"); + csd_volume = (int (*)(uint32_t, int))::dlsym(mcsd_handle, + "csd_client_volume"); + csd_mic_mute = (int (*)(uint32_t, int))::dlsym(mcsd_handle, + "csd_client_mic_mute"); + csd_wide_voice = (int (*)(uint32_t, uint8_t))::dlsym(mcsd_handle, + "csd_client_wide_voice"); + csd_fens = (int (*)(uint32_t, uint8_t))::dlsym(mcsd_handle, + "csd_client_fens"); + csd_slow_talk = (int (*)(uint32_t, uint8_t))::dlsym(mcsd_handle, + "csd_client_slow_talk"); +} +#endif + + +#ifdef QCOM_ACDB_ENABLED +void ALSADevice::setACDBHandle(void* handle) +{ + macdb_handle = static_cast(handle); + ALOGI("%s ACDB_handle: %p", __func__, macdb_handle); + + acdb_loader_get_ecrx_device = (int (*)(int))::dlsym(macdb_handle, + "acdb_loader_get_ecrx_device"); +} +#endif + + +} diff --git a/legacy/alsa_sound/ALSAMixer.cpp b/legacy/alsa_sound/ALSAMixer.cpp index d1383cf41..0875a57a4 100644 --- a/legacy/alsa_sound/ALSAMixer.cpp +++ b/legacy/alsa_sound/ALSAMixer.cpp @@ -1,6 +1,7 @@ /* ALSAMixer.cpp ** ** Copyright 2008-2010 Wind River Systems + ** Copyright (c) 2012, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/legacy/alsa_sound/ALSAStreamOps.cpp b/legacy/alsa_sound/ALSAStreamOps.cpp index c7c0ca171..903cbaf56 100644 --- a/legacy/alsa_sound/ALSAStreamOps.cpp +++ b/legacy/alsa_sound/ALSAStreamOps.cpp @@ -1,7 +1,8 @@ /* ALSAStreamOps.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011, Code Aurora Forum. All rights reserved. + ** 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. @@ -57,15 +58,12 @@ ALSAStreamOps::~ALSAStreamOps() if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { - if((mParent->mVoipStreamCount)) { - mParent->mVoipStreamCount--; - if(mParent->mVoipStreamCount > 0) { - ALOGD("ALSAStreamOps::close() Ignore"); - return ; - } - } - mParent->mVoipStreamCount = 0; - mParent->mVoipBitRate = 0; + if(mParent->mVoipInStreamCount^mParent->mVoipOutStreamCount) { + ALOGD("ALSAStreamOps::close() Ignore"); + return ; + } + mParent->mVoipMicMute = 0; + mParent->mVoipBitRate = 0; } close(); @@ -101,32 +99,44 @@ status_t ALSAStreamOps::set(int *format, if (mHandle->channels != popCount(*channels)) return BAD_VALUE; } else if (channels) { + *channels = 0; if (mHandle->devices & AudioSystem::DEVICE_OUT_ALL) { - switch(*channels) { - case AUDIO_CHANNEL_OUT_5POINT1: // 5.0 - case (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER): // 5.1 - case AUDIO_CHANNEL_OUT_QUAD: - case AUDIO_CHANNEL_OUT_STEREO: - case AUDIO_CHANNEL_OUT_MONO: + switch(mHandle->channels) { + case 8: + case 7: + case 6: + case 5: + *channels |= audio_channel_out_mask_from_count(mHandle->channels); break; + // Do not fall through + case 4: + *channels |= AUDIO_CHANNEL_OUT_BACK_LEFT; + *channels |= AUDIO_CHANNEL_OUT_BACK_RIGHT; + // Fall through... default: - *channels = AUDIO_CHANNEL_OUT_STEREO; - return BAD_VALUE; + case 2: + *channels |= AUDIO_CHANNEL_OUT_FRONT_RIGHT; + // Fall through... + case 1: + *channels |= AUDIO_CHANNEL_OUT_FRONT_LEFT; + break; } } else { - switch(*channels) { + switch(mHandle->channels) { #ifdef QCOM_SSR_ENABLED // For 5.1 recording - case AudioSystem::CHANNEL_IN_5POINT1: + case 6 : + *channels |= AUDIO_CHANNEL_IN_5POINT1; + break; #endif // Do not fall through... - case AUDIO_CHANNEL_IN_MONO: - case AUDIO_CHANNEL_IN_STEREO: - case AUDIO_CHANNEL_IN_FRONT_BACK: - break; default: - *channels = AUDIO_CHANNEL_IN_MONO; - return BAD_VALUE; + case 2: + *channels |= AUDIO_CHANNEL_IN_RIGHT; + // Fall through... + case 1: + *channels |= AUDIO_CHANNEL_IN_LEFT; + break; } } } @@ -142,23 +152,23 @@ status_t ALSAStreamOps::set(int *format, if (format) { switch(*format) { - case AudioSystem::FORMAT_DEFAULT: + case AUDIO_FORMAT_DEFAULT: break; - case AudioSystem::PCM_16_BIT: + case AUDIO_FORMAT_PCM_16_BIT: iformat = SNDRV_PCM_FORMAT_S16_LE; break; - case AudioSystem::AMR_NB: - case AudioSystem::AMR_WB: -#ifdef QCOM_QCHAT_ENABLED - case AudioSystem::EVRC: - case AudioSystem::EVRCB: - case AudioSystem::EVRCWB: + case AUDIO_FORMAT_AMR_NB: + case AUDIO_FORMAT_AMR_WB: +#ifdef QCOM_AUDIO_FORMAT_ENABLED + case AUDIO_FORMAT_EVRC: + case AUDIO_FORMAT_EVRCB: + case AUDIO_FORMAT_EVRCWB: #endif iformat = *format; break; - case AudioSystem::PCM_8_BIT: + case AUDIO_FORMAT_PCM_8_BIT: iformat = SNDRV_PCM_FORMAT_S8; break; @@ -172,10 +182,10 @@ status_t ALSAStreamOps::set(int *format, switch(iformat) { case SNDRV_PCM_FORMAT_S16_LE: - *format = AudioSystem::PCM_16_BIT; + *format = AUDIO_FORMAT_PCM_16_BIT; break; case SNDRV_PCM_FORMAT_S8: - *format = AudioSystem::PCM_8_BIT; + *format = AUDIO_FORMAT_PCM_8_BIT; break; default: break; @@ -188,8 +198,10 @@ status_t ALSAStreamOps::set(int *format, status_t ALSAStreamOps::setParameters(const String8& keyValuePairs) { AudioParameter param = AudioParameter(keyValuePairs); - String8 key = String8(AudioParameter::keyRouting); - int device; + String8 key = String8(AudioParameter::keyRouting),value; + int device, camcorder_enabled; + status_t err = NO_ERROR; + int mMode = mParent->mode(); #ifdef SEPERATED_AUDIO_INPUT String8 key_input = String8(AudioParameter::keyInputSource); @@ -205,17 +217,40 @@ status_t ALSAStreamOps::setParameters(const String8& keyValuePairs) if (param.getInt(key, device) == NO_ERROR) { // Ignore routing if device is 0. ALOGD("setParameters(): keyRouting with device 0x%x", device); - // reset to speaker when disconnecting HDMI to avoid timeout due to write errors - if ((device == 0) && (mDevices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) { - device = AudioSystem::DEVICE_OUT_SPEAKER; - } - if (device) - mDevices = device; - else - ALOGV("must not change mDevices to 0"); - if(device) { - mParent->doRouting(device); + //checking for camcorder_mode and in call more to select appropriate input device + key = String8("camcorder_mode"); + if (param.getInt(key, camcorder_enabled) == NO_ERROR) { + if (camcorder_enabled == 1) { + if ((mMode == AudioSystem::MODE_IN_CALL) || (mMode == AudioSystem::MODE_IN_COMMUNICATION)) { + if (device & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else if (device & AudioSystem::DEVICE_IN_WIRED_HEADSET) { + device = AudioSystem::DEVICE_IN_WIRED_HEADSET; + } else if (device & AudioSystem::DEVICE_IN_AUX_DIGITAL) { + device = AudioSystem::DEVICE_IN_AUX_DIGITAL; + } else { + device = AudioSystem::DEVICE_IN_BUILTIN_MIC; + } + } else { + device = AudioSystem::DEVICE_IN_BUILTIN_MIC; + } + } + } + ALOGD("setParameters(): keyRouting with device %#x", device); + if (mParent->isExtOutDevice(device)) { + mParent->mRouteAudioToExtOut = true; + ALOGD("setParameters(): device %#x", device); + } + err = mParent->doRouting(device); + if(err) { + ALOGE("doRouting failed = %d",err); + } + else { + mDevices = device; + } + } else { + ALOGE("must not change mDevices to 0"); } param.remove(key); } @@ -223,17 +258,19 @@ status_t ALSAStreamOps::setParameters(const String8& keyValuePairs) else { key = String8(AudioParameter::keyHandleFm); if (param.getInt(key, device) == NO_ERROR) { - ALOGD("setParameters(): handleFm with device %d", device); - mDevices = device; + ALOGD("setParameters(): handleFm with device %d", device); if(device) { + mDevices = device; mParent->handleFm(device); } param.remove(key); + } else { + mParent->setParameters(keyValuePairs); } } #endif - return NO_ERROR; + return err; } String8 ALSAStreamOps::getParameters(const String8& keys) @@ -246,8 +283,7 @@ String8 ALSAStreamOps::getParameters(const String8& keys) param.addInt(key, (int)mDevices); } else { -#ifdef QCOM_VOIP_ENABLED - key = String8(AudioParameter::keyVoipCheck); + key = String8(VOIPCHECK_KEY); if (param.get(key, value) == NO_ERROR) { if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) @@ -255,13 +291,41 @@ String8 ALSAStreamOps::getParameters(const String8& keys) else param.addInt(key, false); } -#endif } key = String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS); if (param.get(key, value) == NO_ERROR) { EDID_AUDIO_INFO info = { 0 }; bool first = true; value = String8(); +#ifdef TARGET_8974 + char hdmiEDIDData[MAX_SHORT_AUDIO_DESC_CNT+1]; + if(!mParent->mALSADevice->getEDIDData(hdmiEDIDData)) { + if (AudioUtil::getHDMIAudioSinkCaps(&info, hdmiEDIDData)) { + for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) { + String8 append; + switch (info.AudioBlocksArray[i].nChannels) { + //Do not handle stereo output in Multi-channel cases + //Stereo case is handled in normal playback path + case 6: + ENUM_TO_STRING(append, AUDIO_CHANNEL_OUT_5POINT1); + break; + case 8: + ENUM_TO_STRING(append, AUDIO_CHANNEL_OUT_7POINT1); + break; + default: + ALOGD("Unsupported number of channels %d", info.AudioBlocksArray[i].nChannels); + break; + } + if (!append.isEmpty()) { + value += (first ? append : String8("|") + append); + first = false; + } + } + } else { + ALOGE("Failed to get HDMI sink capabilities"); + } + } +#else if (AudioUtil::getHDMIAudioSinkCaps(&info)) { for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) { String8 append; @@ -286,6 +350,7 @@ String8 ALSAStreamOps::getParameters(const String8& keys) } else { ALOGE("Failed to get HDMI sink capabilities"); } +#endif param.add(key, value); } ALOGV("getParameters() %s", param.toString().string()); @@ -314,25 +379,25 @@ int ALSAStreamOps::format() const switch(ALSAFormat) { case SNDRV_PCM_FORMAT_S8: - audioSystemFormat = AudioSystem::PCM_8_BIT; + audioSystemFormat = AUDIO_FORMAT_PCM_8_BIT; break; - case AudioSystem::AMR_NB: - case AudioSystem::AMR_WB: -#ifdef QCOM_QCHAT_ENABLED - case AudioSystem::EVRC: - case AudioSystem::EVRCB: - case AudioSystem::EVRCWB: + case AUDIO_FORMAT_AMR_NB: + case AUDIO_FORMAT_AMR_WB: +#ifdef QCOM_AUDIO_FORMAT_ENABLED + case AUDIO_FORMAT_EVRC: + case AUDIO_FORMAT_EVRCB: + case AUDIO_FORMAT_EVRCWB: #endif audioSystemFormat = mHandle->format; break; case SNDRV_PCM_FORMAT_S16_LE: - audioSystemFormat = AudioSystem::PCM_16_BIT; + audioSystemFormat = AUDIO_FORMAT_PCM_16_BIT; break; default: LOG_FATAL("Unknown AudioSystem bit width %d!", audioSystemFormat); - audioSystemFormat = AudioSystem::PCM_16_BIT; + audioSystemFormat = AUDIO_FORMAT_PCM_16_BIT; break; } @@ -342,16 +407,76 @@ int ALSAStreamOps::format() const uint32_t ALSAStreamOps::channels() const { - return mHandle->channelMask; + unsigned int count = mHandle->channels; + uint32_t channels = 0; + + if (mDevices & AudioSystem::DEVICE_OUT_ALL) + switch(count) { + case 8: + case 7: + case 6: + case 5: + channels |=audio_channel_out_mask_from_count(count); + break; + // Do not fall through + case 4: + channels |= AUDIO_CHANNEL_OUT_BACK_LEFT; + channels |= AUDIO_CHANNEL_OUT_BACK_RIGHT; + // Fall through... + default: + case 2: + channels |= AUDIO_CHANNEL_OUT_FRONT_RIGHT; + // Fall through... + case 1: + channels |= AUDIO_CHANNEL_OUT_FRONT_LEFT; + break; + } + else + switch(count) { +#ifdef QCOM_SSR_ENABLED + // For 5.1 recording + case 6 : + channels |= AUDIO_CHANNEL_IN_5POINT1; + break; + // Do not fall through... +#endif + default: + case 2: + channels |= AUDIO_CHANNEL_IN_RIGHT; + // Fall through... + case 1: + channels |= AUDIO_CHANNEL_IN_LEFT; + break; + } + + return channels; } void ALSAStreamOps::close() { ALOGD("close"); + + bool found = false; + for(ALSAHandleList::iterator it = mParent->mDeviceList.begin(); + it != mParent->mDeviceList.end(); ++it) { + if (mHandle == &(*it)) { + found = true; + ALOGD("close() : Found mHandle %p, proceeding to close", mHandle); + break; + } + } + + if(!found) { + ALOGW("close() : mHandle NOT found %p, exiting close", mHandle); + return; + } + if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { + mParent->mVoipMicMute = false; mParent->mVoipBitRate = 0; - mParent->mVoipStreamCount = 0; + mParent->mVoipInStreamCount = 0; + mParent->mVoipOutStreamCount = 0; } mParent->mALSADevice->close(mHandle); } diff --git a/legacy/alsa_sound/Android.mk b/legacy/alsa_sound/Android.mk index 534dd6a42..33741cab0 100644 --- a/legacy/alsa_sound/Android.mk +++ b/legacy/alsa_sound/Android.mk @@ -9,27 +9,82 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) + LOCAL_ARM_MODE := arm LOCAL_CFLAGS := -D_POSIX_SOURCE -LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED -LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED +ifeq ($(strip $(QCOM_ACDB_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED +endif +ifeq ($(strip $(QCOM_ANC_HEADSET_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_ANC_HEADSET_ENABLED +endif +ifeq ($(strip $(QCOM_AUDIO_FORMAT_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_AUDIO_FORMAT_ENABLED +endif +ifeq ($(strip $(QCOM_CSDCLIENT_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED +endif +#LOCAL_CFLAGS += -DQCOM_FM_ENABLED +ifeq ($(strip $(QCOM_PROXY_DEVICE_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED +endif +ifeq ($(strip $(QCOM_OUTPUT_FLAGS_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_OUTPUT_FLAGS_ENABLED +endif +ifeq ($(strip $(QCOM_SSR_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_SSR_ENABLED +endif +ifeq ($(strip $(QCOM_USBAUDIO_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED +endif +ifeq ($(strip $(QCOM_ADSP_SSR_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_ADSP_SSR_ENABLED +endif +ifeq ($(strip $(QCOM_FLUENCE_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_FLUENCE_ENABLED +endif +ifeq ($(strip $(QCOM_TUNNEL_LPA_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_TUNNEL_LPA_ENABLED +endif -ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true) -LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL +ifeq ($(call is-board-platform,msm8974),true) + LOCAL_CFLAGS += -DTARGET_8974 endif -ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true) -LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT +ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),) + LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE) endif +#Do not use Dual MIC scenario in call feature +#Dual MIC solution(Fluence) feature in Built-in MIC used scenarioes. +# 1. Handset +# 2. 3-Pole Headphones +#ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true) +#LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL +#endif + +#Do not use separate audio Input path feature +#Separate audio input path can be set using input source of audio parameter +# 1. Voice Recognition +# 2. Camcording +# 3. etc. +#ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true) +#LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT +#endif + LOCAL_SRC_FILES := \ - AudioHardwareALSA.cpp \ - AudioStreamOutALSA.cpp \ - AudioStreamInALSA.cpp \ - ALSAStreamOps.cpp \ - audio_hw_hal.cpp \ - AudioUsbALSA.cpp \ - AudioUtil.cpp + AudioHardwareALSA.cpp \ + AudioStreamOutALSA.cpp \ + AudioStreamInALSA.cpp \ + ALSAStreamOps.cpp \ + audio_hw_hal.cpp \ + AudioUsbALSA.cpp \ + AudioUtil.cpp \ + ALSADevice.cpp + +ifeq ($(strip $(QCOM_TUNNEL_LPA_ENABLED)),true) + LOCAL_SRC_FILES +=AudioSessionOut.cpp +endif LOCAL_STATIC_LIBRARIES := \ libmedia_helper \ @@ -43,7 +98,9 @@ LOCAL_SHARED_LIBRARIES := \ libhardware \ libc \ libpower \ - libalsa-intf + libalsa-intf \ + libsurround_proc\ + libaudioutils ifeq ($(TARGET_SIMULATOR),true) LOCAL_LDLIBS += -ldl @@ -58,84 +115,84 @@ LOCAL_C_INCLUDES += hardware/libhardware/include LOCAL_C_INCLUDES += hardware/libhardware_legacy/include LOCAL_C_INCLUDES += frameworks/base/include LOCAL_C_INCLUDES += system/core/include +LOCAL_C_INCLUDES += system/media/audio_utils/include + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +ifeq ($(call is-board-platform,msm8974),true) + LOCAL_MODULE := audio.primary.msm8974 +endif + +ifeq ($(call is-board-platform,msm8960),true) + LOCAL_MODULE := audio.primary.msm8960 +endif + +ifeq ($(call is-board-platform,msm8610),true) + LOCAL_MODULE := audio.primary.msm8610 +endif -LOCAL_MODULE := audio.primary.msm8960 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) -# This is the ALSA audio policy manager - include $(CLEAR_VARS) LOCAL_CFLAGS := -D_POSIX_SOURCE -LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED +ifeq ($(strip $(QCOM_ACDB_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED +endif +ifeq ($(strip $(QCOM_ANC_HEADSET_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_ANC_HEADSET_ENABLED +endif +ifeq ($(strip $(QCOM_AUDIO_FORMAT_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_AUDIO_FORMAT_ENABLED +endif +ifeq ($(strip $(QCOM_CSDCLIENT_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED +endif +#LOCAL_CFLAGS += -DQCOM_FM_ENABLED +ifeq ($(strip $(QCOM_PROXY_DEVICE_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED +endif +ifeq ($(strip $(QCOM_SSR_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_SSR_ENABLED +endif +ifeq ($(strip $(QCOM_USBAUDIO_ENABLED)),true) + LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED +endif LOCAL_SRC_FILES := \ audio_policy_hal.cpp \ AudioPolicyManagerALSA.cpp -LOCAL_MODULE := audio_policy.msm8960 -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_LIBRARIES := \ - libmedia_helper \ - libaudiopolicy_legacy - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils - -LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio - -include $(BUILD_SHARED_LIBRARY) - -# This is the ALSA module which behaves closely like the original - -include $(CLEAR_VARS) - -LOCAL_PRELINK_MODULE := false - -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw - -LOCAL_CFLAGS := -D_POSIX_SOURCE -Wno-multichar -LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED - -ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true) -LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL +ifeq ($(call is-board-platform,msm8974),true) + LOCAL_MODULE := audio_policy.msm8974 endif -ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true) -LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT +ifeq ($(call is-board-platform,msm8960),true) + LOCAL_MODULE := audio_policy.msm8960 endif -ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),) - LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE) +ifeq ($(call is-board-platform,msm8610),true) + LOCAL_MODULE := audio_policy.msm8610 endif -LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/libalsa-intf +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES:= \ - alsa_default.cpp \ - ALSAControl.cpp \ - AudioUtil.cpp +LOCAL_STATIC_LIBRARIES := \ + libmedia_helper \ + libaudiopolicy_legacy LOCAL_SHARED_LIBRARIES := \ libcutils \ - liblog \ - libalsa-intf + libutils \ -ifeq ($(TARGET_SIMULATOR),true) - LOCAL_LDLIBS += -ldl -else - LOCAL_SHARED_LIBRARIES += libdl -endif +LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio -LOCAL_MODULE:= alsa.msm8960 -LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) - include $(BUILD_SHARED_LIBRARY) endif diff --git a/legacy/alsa_sound/AudioHardwareALSA.cpp b/legacy/alsa_sound/AudioHardwareALSA.cpp index 508418ccd..a3f73472b 100644 --- a/legacy/alsa_sound/AudioHardwareALSA.cpp +++ b/legacy/alsa_sound/AudioHardwareALSA.cpp @@ -1,7 +1,8 @@ /* AudioHardwareALSA.cpp ** ** Copyright 2008-2010 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** 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. @@ -26,7 +27,7 @@ #include #define LOG_TAG "AudioHardwareALSA" -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #define LOG_NDDEBUG 0 #include #include @@ -37,6 +38,8 @@ #include #include #include +#include +#include #include "AudioHardwareALSA.h" #ifdef QCOM_USBAUDIO_ENABLED @@ -44,6 +47,13 @@ #endif #include "AudioUtil.h" +//#define OUTPUT_BUFFER_LOG +#ifdef OUTPUT_BUFFER_LOG + FILE *outputBufferFile1; + char outputfilename [50] = "/data/output_proxy"; + static int number = 0; +#endif + extern "C" { // @@ -55,12 +65,15 @@ extern "C" #ifdef QCOM_ACDB_ENABLED static int (*acdb_init)(); static void (*acdb_deallocate)(); + static void (*acdb_send_audio_cal)(int, int); #endif #ifdef QCOM_CSDCLIENT_ENABLED static int (*csd_client_init)(); static int (*csd_client_deinit)(); - static int (*csd_start_playback)(); - static int (*csd_stop_playback)(); + static int (*csd_start_playback)(uint32_t); + static int (*csd_stop_playback)(uint32_t); + static int (*csd_standby_voice)(uint32_t); + static int (*csd_resume_voice)(uint32_t); #endif } // extern "C" @@ -70,138 +83,296 @@ namespace android_audio_legacy // ---------------------------------------------------------------------------- AudioHardwareInterface *AudioHardwareALSA::create() { - return new AudioHardwareALSA(); + + AudioHardwareInterface * hardwareInterface = new AudioHardwareALSA(); + if(hardwareInterface->initCheck() != OK) { + ALOGE("NULL - AHAL creation failed"); + delete hardwareInterface; + hardwareInterface = NULL; + } + return hardwareInterface; } AudioHardwareALSA::AudioHardwareALSA() : - mALSADevice(0),mVoipStreamCount(0),mVoipBitRate(0) - ,mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL),mMicMute(0) + mALSADevice(0),mVoipInStreamCount(0),mVoipOutStreamCount(0),mVoipMicMute(false), + mVoipBitRate(0),mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL),mMicMute(0) { FILE *fp; char soundCardInfo[200]; - hw_module_t *module; - char platform[128], baseband[128]; - int err = hw_get_module(ALSA_HARDWARE_MODULE_ID, - (hw_module_t const**)&module); - int codec_rev = 2; - ALOGD("hw_get_module(ALSA_HARDWARE_MODULE_ID) returned err %d", err); - if (err == 0) { - hw_device_t* device; - err = module->methods->open(module, ALSA_HARDWARE_NAME, &device); - if (err == 0) { - mALSADevice = (alsa_device_t *)device; - mALSADevice->init(mALSADevice, mDeviceList); - mCSCallActive = 0; - mVolteCallActive = 0; - mIsFmActive = 0; - mDevSettingsFlag = 0; + char platform[128], baseband[128], audio_init[128], platformVer[128]; + int codec_rev = 2, verNum = 0; + + mDeviceList.clear(); + mCSCallActive = 0; + mVolteCallActive = 0; + mVoice2CallActive = 0; + mIsFmActive = 0; + mDevSettingsFlag = 0; + bool audio_init_done = false; + int sleep_retry = 0; #ifdef QCOM_USBAUDIO_ENABLED - mAudioUsbALSA = new AudioUsbALSA(); - musbPlaybackState = 0; - musbRecordingState = 0; + mAudioUsbALSA = new AudioUsbALSA(); + musbPlaybackState = 0; + musbRecordingState = 0; #endif #ifdef USES_FLUENCE_INCALL - mDevSettingsFlag |= TTY_OFF | DMIC_FLAG; + mDevSettingsFlag |= TTY_OFF | DMIC_FLAG; #else - mDevSettingsFlag |= TTY_OFF; + mDevSettingsFlag |= TTY_OFF; #endif - mBluetoothVGS = false; - mFusion3Platform = false; + mBluetoothVGS = false; + mFusion3Platform = false; + + mRouteAudioToExtOut = false; + mA2dpDevice = NULL; + mA2dpStream = NULL; + mUsbDevice = NULL; + mUsbStream = NULL; + mExtOutStream = NULL; + mResampler = NULL; + mExtOutActiveUseCases = USECASE_NONE; + mIsExtOutEnabled = false; + mKillExtOutThread = false; + mExtOutThreadAlive = false; + mExtOutThread = NULL; + mUcMgr = NULL; + mCanOpenProxy=1; #ifdef QCOM_ACDB_ENABLED - mAcdbHandle = ::dlopen("/system/lib/libacdbloader.so", RTLD_NOW); - if (mAcdbHandle == NULL) { - ALOGE("AudioHardware: DLOPEN not successful for ACDBLOADER"); - } else { - ALOGD("AudioHardware: DLOPEN successful for ACDBLOADER"); - acdb_init = (int (*)())::dlsym(mAcdbHandle,"acdb_loader_init_ACDB"); - if (acdb_init == NULL) { - ALOGE("dlsym:Error:%s Loading acdb_loader_init_ACDB", dlerror()); - }else { - acdb_init(); - acdb_deallocate = (void (*)())::dlsym(mAcdbHandle,"acdb_loader_deallocate_ACDB"); - } - } + acdb_deallocate = NULL; #endif -#ifdef QCOM_CSDCLIENT_ENABLED - mCsdHandle = ::dlopen("/system/lib/libcsd-client.so", RTLD_NOW); - if (mCsdHandle == NULL) { - ALOGE("AudioHardware: DLOPEN not successful for CSD CLIENT"); - } else { - ALOGD("AudioHardware: DLOPEN successful for CSD CLIENT"); - csd_client_init = (int (*)())::dlsym(mCsdHandle,"csd_client_init"); - csd_client_deinit = (int (*)())::dlsym(mCsdHandle,"csd_client_deinit"); - csd_start_playback = (int (*)())::dlsym(mCsdHandle,"csd_client_start_playback"); - csd_stop_playback = (int (*)())::dlsym(mCsdHandle,"csd_client_stop_playback"); - - if (csd_client_init == NULL) { - ALOGE("dlsym: Error:%s Loading csd_client_init", dlerror()); - } else { - csd_client_init(); - } - } - mALSADevice->setCsdHandle(mCsdHandle); + mALSADevice = new ALSADevice(); + if (!mALSADevice) { + mStatus = NO_INIT; + return; + } +#ifdef QCOM_ACDB_ENABLED + mAcdbHandle = ::dlopen("/system/lib/libacdbloader.so", RTLD_NOW); + if (mAcdbHandle == NULL) { + ALOGE("AudioHardware: DLOPEN not successful for ACDBLOADER"); + } else { + ALOGD("AudioHardware: DLOPEN successful for ACDBLOADER"); + acdb_init = (int (*)())::dlsym(mAcdbHandle,"acdb_loader_init_ACDB"); + if (acdb_init == NULL) { + ALOGE("dlsym:Error:%s Loading acdb_loader_init_ACDB"); + }else { + acdb_init(); + acdb_deallocate = (void (*)())::dlsym(mAcdbHandle,"acdb_loader_deallocate_ACDB"); + } + } + mALSADevice->setACDBHandle(mAcdbHandle); #endif - if((fp = fopen("/proc/asound/cards","r")) == NULL) { - ALOGE("Cannot open /proc/asound/cards file to get sound card info"); - } else { - while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) { - ALOGV("SoundCardInfo %s", soundCardInfo); - if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) { - codec_rev = 1; - break; - } else if (strstr(soundCardInfo, "msm-snd-card")) { - codec_rev = 2; - break; - } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) { - codec_rev = 3; - break; - } + + if((fp = fopen("/proc/asound/cards","r")) == NULL) { + ALOGE("Cannot open /proc/asound/cards file to get sound card info"); + mStatus = NO_INIT; + return; + } else { + while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) { + ALOGV("SoundCardInfo %s", soundCardInfo); + if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) { + codec_rev = 1; + break; + } else if (strstr(soundCardInfo, "msm-snd-card")) { + codec_rev = 2; + break; + } else if (strstr(soundCardInfo, "apq8064-tabla-snd-card")) { + codec_rev = 2; + break; + } else if (strstr(soundCardInfo, "msm8960-snd-card")) { + codec_rev = 2; + break; + } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) { + codec_rev = 3; + property_get("ro.baseband", baseband, ""); + if (!strcmp("sglte", baseband)) + codec_rev = 31; + break; + } else if (strstr(soundCardInfo, "msm8974-taiko-mtp-snd-card")) { + codec_rev = 40; + break; + } else if (strstr(soundCardInfo, "msm8974-taiko-cdp-snd-card")) { + codec_rev = 41; + break; + } else if (strstr(soundCardInfo, "msm8974-taiko-fluid-snd-card")) { + codec_rev = 42; + break; + } else if (strstr(soundCardInfo, "msm8974-taiko-liquid-snd-card")) { + codec_rev = 43; + break; + } else if(strstr(soundCardInfo, "no soundcards")) { + ALOGE("NO SOUND CARD DETECTED"); + if(sleep_retry < SOUND_CARD_SLEEP_RETRY) { + ALOGD("Sleeping for 100 ms"); + usleep(SOUND_CARD_SLEEP_WAIT * 1000); + sleep_retry++; + fseek(fp, 0, SEEK_SET); + continue; } + else { + ALOGE("Failed %d attempts for sound card detection", sleep_retry); + fclose(fp); + mStatus = NO_INIT; + return; + } + } else { + ALOGE("ERROR - Sound card detection"); fclose(fp); + mStatus = NO_INIT; + return; } + } + fclose(fp); + } + + sleep_retry = 0; + while (audio_init_done == false && sleep_retry < MAX_SLEEP_RETRY) { + property_get("qcom.audio.init", audio_init, NULL); + ALOGD("qcom.audio.init is set to %s\n",audio_init); + if(!strncmp(audio_init, "complete", sizeof("complete"))) { + audio_init_done = true; + } else { + ALOGD("Sleeping for 50 ms"); + usleep(AUDIO_INIT_SLEEP_WAIT*1000); + sleep_retry++; + } + } - if (codec_rev == 1) { - ALOGV("Detected tabla 1.x sound card"); - snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm"); - } else if (codec_rev == 3) { - ALOGV("Detected sitar 1.x sound card"); - snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar"); + if (codec_rev == 1) { + ALOGV("Detected tabla 1.x sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm"); + } else if (codec_rev == 3) { + ALOGV("Detected sitar 1.x sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar"); + } else if (codec_rev == 31) { + ALOGV("Detected sitar 1.x sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar_Sglte"); + } else if (codec_rev == 40) { + ALOGV("Detected taiko sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko"); + } else if (codec_rev == 41) { + ALOGV("Detected taiko sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_CDP"); + } else if (codec_rev == 42) { + ALOGV("Detected taiko sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_Fluid"); + } else if (codec_rev == 43) { + ALOGV("Detected taiko liquid sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_liquid"); + } else { + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strcmp("msm8960", platform) && + (!strcmp("mdm", baseband) || !strcmp("sglte2", baseband))) { + ALOGV("Detected Fusion tabla 2.x"); + mFusion3Platform = true; + if((fp = fopen("/sys/devices/system/soc/soc0/platform_version","r")) == NULL) { + ALOGE("Cannot open /sys/devices/system/soc/soc0/platform_version file"); + + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3"); } else { - property_get("ro.board.platform", platform, ""); - property_get("ro.baseband", baseband, ""); - if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) { - ALOGV("Detected Fusion tabla 2.x"); - mFusion3Platform = true; - snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3"); + while((fgets(platformVer, sizeof(platformVer), fp) != NULL)) { + ALOGV("platformVer %s", platformVer); + + verNum = atoi(platformVer); + if (verNum == 0x10001) { + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_I2SFusion"); + break; } else { - ALOGV("Detected tabla 2.x sound card"); - snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3"); + break; } + } } + fclose(fp); + } else { + ALOGV("Detected tabla 2.x sound card"); + snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x"); + } + } - if (mUcMgr < 0) { - ALOGE("Failed to open ucm instance: %d", errno); +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + mCsdHandle = ::dlopen("/system/lib/libcsd-client.so", RTLD_NOW); + if (mCsdHandle == NULL) { + ALOGE("AudioHardware: DLOPEN not successful for CSD CLIENT"); + } else { + ALOGD("AudioHardware: DLOPEN successful for CSD CLIENT"); + csd_client_init = (int (*)())::dlsym(mCsdHandle, "csd_client_init"); + csd_client_deinit = (int (*)())::dlsym(mCsdHandle, + "csd_client_deinit"); + csd_start_playback = (int (*)(uint32_t))::dlsym(mCsdHandle, + "csd_client_start_playback"); + csd_stop_playback = (int (*)(uint32_t))::dlsym(mCsdHandle, + "csd_client_stop_playback"); + csd_standby_voice = (int (*)(uint32_t))::dlsym(mCsdHandle, + "csd_client_standby_voice"); + csd_resume_voice = (int (*)(uint32_t))::dlsym(mCsdHandle, + "csd_client_resume_voice"); + + if (csd_client_init == NULL) { + ALOGE("csd_client_init is NULL"); } else { - ALOGI("ucm instance opened: %u", (unsigned)mUcMgr); - mUcMgr->acdb_handle = NULL; -#ifdef QCOM_ACDB_ENABLED - if (mAcdbHandle) { - mUcMgr->acdb_handle = static_cast (mAcdbHandle); - if (mFusion3Platform) - mUcMgr->isFusion3Platform = true; - else - mUcMgr->isFusion3Platform = false; - } -#endif + csd_client_init(); } - } else { - ALOGE("ALSA Module could not be opened!!!"); + } + mALSADevice->setCsdHandle(mCsdHandle); + } +#endif + + if (mUcMgr < 0) { + ALOGE("Failed to open ucm instance: %d", errno); + mStatus = NO_INIT; + return; + } else { + ALOGI("ucm instance opened: %u", (unsigned)mUcMgr); + mUcMgr->isFusion3Platform = mFusion3Platform; + } + + //set default AudioParameters + AudioParameter param; + String8 key; + String8 value; +#ifdef QCOM_FLUENCE_ENABLED + //Set default AudioParameter for fluencetype + key = String8(AudioParameter::keyFluenceType); + property_get("ro.qc.sdk.audio.fluencetype",mFluenceKey,"0"); + if (0 == strncmp("fluencepro", mFluenceKey, sizeof("fluencepro"))) { + mDevSettingsFlag |= QMIC_FLAG; + mDevSettingsFlag &= (~DMIC_FLAG); + value = String8("fluencepro"); + ALOGD("FluencePro quadMic feature Enabled"); + } else if (0 == strncmp("fluence", mFluenceKey, sizeof("fluence"))) { + mDevSettingsFlag |= DMIC_FLAG; + mDevSettingsFlag &= (~QMIC_FLAG); + value = String8("fluence"); + ALOGD("Fluence dualmic feature Enabled"); + } else if (0 == strncmp("none", mFluenceKey, sizeof("none"))) { + mDevSettingsFlag &= (~DMIC_FLAG); + mDevSettingsFlag &= (~QMIC_FLAG); + value = String8("none"); + ALOGD("Fluence feature Disabled"); + } + param.add(key, value); + mALSADevice->setFlags(mDevSettingsFlag); +#endif + +#ifdef QCOM_SSR_ENABLED + //set default AudioParameters for surround sound recording + char ssr_enabled[6] = "false"; + property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0"); + if (!strncmp("true", ssr_enabled, 4)) { + ALOGD("surround sound recording is supported"); + param.add(String8(AudioParameter::keySSR), String8("true")); } else { - ALOGE("ALSA Module not found!!!"); + ALOGD("surround sound recording is not supported"); + param.add(String8(AudioParameter::keySSR), String8("false")); } +#endif + + mStatus = OK; } AudioHardwareALSA::~AudioHardwareALSA() @@ -211,16 +382,20 @@ AudioHardwareALSA::~AudioHardwareALSA() snd_use_case_mgr_close(mUcMgr); } if (mALSADevice) { - mALSADevice->common.close(&mALSADevice->common); + delete mALSADevice; } for(ALSAHandleList::iterator it = mDeviceList.begin(); it != mDeviceList.end(); ++it) { it->useCase[0] = 0; mDeviceList.erase(it); } + if (mResampler) { + release_resampler(mResampler); + mResampler = NULL; + } #ifdef QCOM_ACDB_ENABLED if (acdb_deallocate == NULL) { - ALOGE("dlsym: Error:%s Loading acdb_deallocate_ACDB", dlerror()); + ALOGE("acdb_deallocate_ACDB is NULL"); } else { acdb_deallocate(); } @@ -234,24 +409,23 @@ AudioHardwareALSA::~AudioHardwareALSA() #endif #ifdef QCOM_CSDCLEINT_ENABLED - if (mCsdHandle) { - if (csd_client_deinit == NULL) { - ALOGE("dlsym: Error:%s Loading csd_client_deinit", dlerror()); - } else { - csd_client_deinit(); - } - ::dlclose(mCsdHandle); - mCsdHandle = NULL; - } + if (mFusion3Platform) { + if (mCsdHandle) { + if (csd_client_deinit == NULL) { + ALOGE("csd_client_deinit is NULL"); + } else { + csd_client_deinit(); + } + ::dlclose(mCsdHandle); + mCsdHandle = NULL; + } + } #endif } status_t AudioHardwareALSA::initCheck() { - if (!mALSADevice) - return NO_INIT; - - return NO_ERROR; + return mStatus; } status_t AudioHardwareALSA::setVoiceVolume(float v) @@ -275,11 +449,13 @@ status_t AudioHardwareALSA::setVoiceVolume(float v) vol = 100 - vol; if (mALSADevice) { - if(newMode == AudioSystem::MODE_IN_COMMUNICATION) { + if(newMode == AUDIO_MODE_IN_COMMUNICATION) { mALSADevice->setVoipVolume(vol); - } else if (newMode == AudioSystem::MODE_IN_CALL){ + } else if (newMode == AUDIO_MODE_IN_CALL){ if (mCSCallActive == CS_ACTIVE) mALSADevice->setVoiceVolume(vol); + else if (mVoice2CallActive == CS_ACTIVE_SESSION2) + mALSADevice->setVoice2Volume(vol); if (mVolteCallActive == IMS_ACTIVE) mALSADevice->setVoLTEVolume(vol); } @@ -291,6 +467,7 @@ status_t AudioHardwareALSA::setVoiceVolume(float v) #ifdef QCOM_FM_ENABLED status_t AudioHardwareALSA::setFmVolume(float value) { + Mutex::Autolock autoLock(mLock); status_t status = NO_ERROR; int vol; @@ -325,10 +502,10 @@ status_t AudioHardwareALSA::setMode(int mode) if (mode != mMode) { status = AudioHardwareBase::setMode(mode); } - - if (mode == AudioSystem::MODE_IN_CALL) { - mCallState = CS_ACTIVE; - }else if (mode == AudioSystem::MODE_NORMAL) { + if (mode == AUDIO_MODE_IN_CALL) { + if (mCallState == CS_INACTIVE) + mCallState = CS_ACTIVE; + }else if (mode == AUDIO_MODE_NORMAL) { mCallState = 0; } @@ -344,38 +521,68 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) int device; int btRate; int state; + ALOGV("setParameters() %s", keyValuePairs.string()); +#ifdef QCOM_ADSP_SSR_ENABLED + key = String8(AudioParameter::keyADSPStatus); + if (param.get(key, value) == NO_ERROR) { + if (value == "ONLINE") { + ALOGV("ADSP online set SSRcomplete"); + mALSADevice->mSSRComplete = true; + return status; + } + else if (value == "OFFLINE") { + ALOGV("ADSP online re-set SSRcomplete"); + mALSADevice->mSSRComplete = false; + if ( mRouteAudioToExtOut==true) { + ALOGV("ADSP offline close EXT output"); + uint32_t activeUsecase = getExtOutActiveUseCases_l(); + stopPlaybackOnExtOut_l(activeUsecase); + } + return status; + } + } +#endif + key = String8(TTY_MODE_KEY); if (param.get(key, value) == NO_ERROR) { mDevSettingsFlag &= TTY_CLEAR; - if (value == "tty_full") { + if (value == "full" || value == "tty_full") { mDevSettingsFlag |= TTY_FULL; - } else if (value == "tty_hco") { + } else if (value == "hco" || value == "tty_hco") { mDevSettingsFlag |= TTY_HCO; - } else if (value == "tty_vco") { + } else if (value == "vco" || value == "tty_vco") { mDevSettingsFlag |= TTY_VCO; } else { mDevSettingsFlag |= TTY_OFF; } ALOGI("Changed TTY Mode=%s", value.string()); mALSADevice->setFlags(mDevSettingsFlag); - if(mMode != AudioSystem::MODE_IN_CALL){ + if(mMode != AUDIO_MODE_IN_CALL){ return NO_ERROR; } doRouting(0); + param.remove(key); } - - key = String8(FLUENCE_KEY); +#ifdef QCOM_FLUENCE_ENABLED + key = String8(AudioParameter::keyFluenceType); if (param.get(key, value) == NO_ERROR) { if (value == "quadmic") { - mDevSettingsFlag |= QMIC_FLAG; - mDevSettingsFlag &= (~DMIC_FLAG); - ALOGV("Fluence quadMic feature Enabled"); + //Allow changing fluence type to "quadmic" only when fluence type is fluencepro + if (0 == strncmp("fluencepro", mFluenceKey, sizeof("fluencepro"))) { + mDevSettingsFlag |= QMIC_FLAG; + mDevSettingsFlag &= (~DMIC_FLAG); + ALOGV("Fluence quadMic feature Enabled"); + } } else if (value == "dualmic") { - mDevSettingsFlag |= DMIC_FLAG; - mDevSettingsFlag &= (~QMIC_FLAG); - ALOGV("Fluence dualmic feature Enabled"); + //Allow changing fluence type to "dualmic" only when fluence type is fluencepro or fluence + if (0 == strncmp("fluencepro", mFluenceKey, sizeof("fluencepro")) || + 0 == strncmp("fluence", mFluenceKey, sizeof("fluence"))) { + mDevSettingsFlag |= DMIC_FLAG; + mDevSettingsFlag &= (~QMIC_FLAG); + ALOGV("Fluence dualmic feature Enabled"); + } } else if (value == "none") { mDevSettingsFlag &= (~DMIC_FLAG); mDevSettingsFlag &= (~QMIC_FLAG); @@ -383,7 +590,9 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) } mALSADevice->setFlags(mDevSettingsFlag); doRouting(0); + param.remove(key); } +#endif #ifdef QCOM_CSDCLIENT_ENABLED if (mFusion3Platform) { @@ -392,22 +601,24 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) if (value == "true") { ALOGV("Enabling Incall Music setting in the setparameter\n"); if (csd_start_playback == NULL) { - ALOGE("dlsym: Error:%s Loading csd_client_start_playback", dlerror()); - } else { - csd_start_playback(); - } + ALOGE("csd_client_start_playback is NULL"); + } else { + csd_start_playback(ALL_SESSION_VSID); + } } else { ALOGV("Disabling Incall Music setting in the setparameter\n"); if (csd_stop_playback == NULL) { - ALOGE("dlsym: Error:%s Loading csd_client_stop_playback", dlerror()); + ALOGE("csd_client_stop_playback is NULL"); } else { - csd_stop_playback(); + csd_stop_playback(ALL_SESSION_VSID); } } + param.remove(key); } } #endif +#ifdef QCOM_ANC_HEADSET_ENABLED key = String8(ANC_KEY); if (param.get(key, value) == NO_ERROR) { if (value == "true") { @@ -419,7 +630,9 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) } mALSADevice->setFlags(mDevSettingsFlag); doRouting(0); + param.remove(key); } +#endif key = String8(AudioParameter::keyRouting); if (param.getInt(key, device) == NO_ERROR) { @@ -443,6 +656,7 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) } else { mBluetoothVGS = false; } + param.remove(key); } key = String8(WIDEVOICE_KEY); @@ -451,8 +665,58 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) if (value == "true") { flag = true; } + if(mALSADevice) { - mALSADevice->enableWideVoice(flag); + mALSADevice->enableWideVoice(flag, ALL_SESSION_VSID); + } + param.remove(key); + } + + key = String8("a2dp_connected"); + if (param.get(key, value) == NO_ERROR) { + if (value == "true") { + status_t err = openExtOutput(AudioSystem::DEVICE_OUT_ALL_A2DP); + } else { + status_t err = closeExtOutput(AudioSystem::DEVICE_OUT_ALL_A2DP); + } + param.remove(key); + } + + key = String8("A2dpSuspended"); + if (param.get(key, value) == NO_ERROR) { + if (mA2dpDevice != NULL) { + mA2dpDevice->set_parameters(mA2dpDevice,keyValuePairs); + if(value=="true"){ + uint32_t activeUsecase = getExtOutActiveUseCases_l(); + status_t err = suspendPlaybackOnExtOut_l(activeUsecase); + } + } + param.remove(key); + } + + key = String8("a2dp_sink_address"); + if (param.get(key, value) == NO_ERROR) { + if (mA2dpStream != NULL) { + mA2dpStream->common.set_parameters(&mA2dpStream->common,keyValuePairs); + } + param.remove(key); + } + + key = String8("usb_connected"); + if (param.get(key, value) == NO_ERROR) { + if (value == "true") { + status_t err = openExtOutput(AUDIO_DEVICE_OUT_ALL_USB); + } else { + status_t err = closeExtOutput(AUDIO_DEVICE_OUT_ALL_USB); + } + param.remove(key); + } + + key = String8("card"); + if (param.get(key, value) == NO_ERROR) { + if (mUsbStream != NULL) { + ALOGV("mUsbStream->common.set_parameters"); + mUsbStream->common.set_parameters(&mUsbStream->common,keyValuePairs); } param.remove(key); } @@ -470,7 +734,7 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) flag = true; } if(mALSADevice) { - mALSADevice->enableFENS(flag); + mALSADevice->enableFENS(flag, ALL_SESSION_VSID); } param.remove(key); } @@ -493,7 +757,7 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) flag = true; } if(mALSADevice) { - mALSADevice->enableSlowTalk(flag); + mALSADevice->enableSlowTalk(flag, ALL_SESSION_VSID); } param.remove(key); } @@ -501,9 +765,11 @@ status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs) if (param.getInt(key,state) == NO_ERROR) { if (mCallState != state) { mCallState = state; - doRouting(0); + if (isAnyCallActive()) { + doRouting(0); + } } - mCallState = state; + param.remove(key); } if (param.size()) { status = BAD_VALUE; @@ -515,14 +781,16 @@ String8 AudioHardwareALSA::getParameters(const String8& keys) { AudioParameter param = AudioParameter(keys); String8 value; - - String8 key = String8(DUALMIC_KEY); + String8 key; + int device; +#ifdef QCOM_FLUENCE_ENABLED + key = String8(DUALMIC_KEY); if (param.get(key, value) == NO_ERROR) { value = String8("false"); param.add(key, value); } - key = String8(FLUENCE_KEY); + key = String8(AudioParameter::keyFluenceType); if (param.get(key, value) == NO_ERROR) { if ((mDevSettingsFlag & QMIC_FLAG) && (mDevSettingsFlag & ~DMIC_FLAG)) @@ -535,8 +803,15 @@ String8 AudioHardwareALSA::getParameters(const String8& keys) value = String8("none"); param.add(key, value); } +#endif #ifdef QCOM_FM_ENABLED + + key = String8(AudioParameter::keyHandleA2dpDevice); + if ( param.get(key,value) == NO_ERROR ) { + param.add(key, String8("true")); + } + key = String8("Fm-radio"); if ( param.get(key,value) == NO_ERROR ) { if ( mIsFmActive ) { @@ -550,7 +825,49 @@ String8 AudioHardwareALSA::getParameters(const String8& keys) if(mBluetoothVGS) param.addInt(String8("isVGS"), true); } +#ifdef QCOM_SSR_ENABLED + key = String8(AudioParameter::keySSR); + if (param.get(key, value) == NO_ERROR) { + char ssr_enabled[6] = "false"; + property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0"); + if (!strncmp("true", ssr_enabled, 4)) { + value = String8("true"); + } + param.add(key, value); + } +#endif + + key = String8("A2dpSuspended"); + if (param.get(key, value) == NO_ERROR) { + if (mA2dpDevice != NULL) { + value = mA2dpDevice->get_parameters(mA2dpDevice,key); + } + param.add(key, value); + } + + key = String8("a2dp_sink_address"); + if (param.get(key, value) == NO_ERROR) { + if (mA2dpStream != NULL) { + value = mA2dpStream->common.get_parameters(&mA2dpStream->common,key); + } + param.add(key, value); + } + + key = String8("tunneled-input-formats"); + if ( param.get(key,value) == NO_ERROR ) { + ALOGD("Add tunnel AWB to audio parameter"); + param.addInt(String8("AWB"), true ); + } + + key = String8(AudioParameter::keyRouting); + if (param.getInt(key, device) == NO_ERROR) { + param.addInt(key, mCurDevice); + } + key = String8(AudioParameter::keyCanOpenProxy); + if(param.get(key, value) == NO_ERROR) { + param.addInt(key, mCanOpenProxy); + } ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string()); return param.toString(); } @@ -573,7 +890,8 @@ void AudioHardwareALSA::closeUSBRecording() void AudioHardwareALSA::closeUsbPlaybackIfNothingActive(){ ALOGV("closeUsbPlaybackIfNothingActive, musbPlaybackState: %d", musbPlaybackState); if(!musbPlaybackState && mAudioUsbALSA != NULL) { - mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_TIMEOUT); + setProxyProperty(1); + mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_KILLTHREAD); } } @@ -581,7 +899,7 @@ void AudioHardwareALSA::closeUsbRecordingIfNothingActive(){ ALOGV("closeUsbRecordingIfNothingActive, musbRecordingState: %d", musbRecordingState); if(!musbRecordingState && mAudioUsbALSA != NULL) { ALOGD("Closing USB Recording Session as no stream is active"); - mAudioUsbALSA->setkillUsbRecordingThread(true); + mAudioUsbALSA->exitRecordingThread(SIGNAL_EVENT_KILLTHREAD); } } @@ -589,7 +907,8 @@ void AudioHardwareALSA::startUsbPlaybackIfNotStarted(){ ALOGV("Starting the USB playback %d kill %d", musbPlaybackState, mAudioUsbALSA->getkillUsbPlaybackThread()); if((!musbPlaybackState) || (mAudioUsbALSA->getkillUsbPlaybackThread() == true)) { - mAudioUsbALSA->startPlayback(); + setProxyProperty(0); + mAudioUsbALSA->startPlayback(); } } @@ -602,56 +921,83 @@ void AudioHardwareALSA::startUsbRecordingIfNotStarted(){ } #endif -void AudioHardwareALSA::doRouting(int device) +status_t AudioHardwareALSA::doRouting(int device) { Mutex::Autolock autoLock(mLock); int newMode = mode(); bool isRouted = false; + if(device) + mALSADevice->mCurDevice = device; if ((device == AudioSystem::DEVICE_IN_VOICE_CALL) #ifdef QCOM_FM_ENABLED || (device == AudioSystem::DEVICE_IN_FM_RX) - || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP) #endif || (device == AudioSystem::DEVICE_IN_COMMUNICATION) ) { ALOGV("Ignoring routing for FM/INCALL/VOIP recording"); - return; + return NO_ERROR; } + ALOGV("device = 0x%x,mCurDevice 0x%x", device, mCurDevice); if (device == 0) device = mCurDevice; - ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d" - "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive, - mIsFmActive); - + ALOGV("doRouting: device %#x newMode %d mCSCallActive %d mVolteCallActive %d" + "mVoice2CallActive %d mIsFmActive %d", device, newMode, mCSCallActive, + mVolteCallActive, mVoice2CallActive, mIsFmActive); isRouted = routeVoLTECall(device, newMode); isRouted |= routeVoiceCall(device, newMode); - + isRouted |= routeVoice2Call(device, newMode); + + if(((mCSCallActive == CS_ACTIVE) || + (mVolteCallActive == CS_ACTIVE) || + (mVoice2CallActive == CS_ACTIVE_SESSION2))&& + (mFusion3Platform == true) && + (newMode == AudioSystem::MODE_RINGTONE)){ + /* 1st voice call on hold but still the call state will be active as + * hold state is not propagated to audio stack, now if there is a MT + * call, then consider the MODE_IN_RINGTONE as MODE_IN_CALL + * */ + ALOGE(" CS call active %d on fusion", mCSCallActive); + newMode = AudioSystem::MODE_IN_CALL; + } if(!isRouted) { #ifdef QCOM_USBAUDIO_ENABLED if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) && !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) && !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) && - (musbPlaybackState)){ - //USB unplugged - device &= ~ AudioSystem::DEVICE_OUT_PROXY; - device &= ~ AudioSystem::DEVICE_IN_PROXY; + (musbPlaybackState || musbRecordingState)){ + // mExtOutStream should be initialized before calling route + // when switching form USB headset to ExtOut device + if( mRouteAudioToExtOut == true ) { + switchExtOut(device); + } ALSAHandleList::iterator it = mDeviceList.end(); it--; mALSADevice->route(&(*it), (uint32_t)device, newMode); ALOGD("USB UNPLUGGED, setting musbPlaybackState to 0"); - musbPlaybackState = 0; - musbRecordingState = 0; closeUSBRecording(); closeUSBPlayback(); } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ ALOGD("Routing everything to prox now"); + // stopPlaybackOnExtOut should be called to close + // ExtOutthread when switching from ExtOut device to USB headset + if( mRouteAudioToExtOut == true ) { + uint32_t activeUsecase = getExtOutActiveUseCases_l(); + status_t err = stopPlaybackOnExtOut_l(activeUsecase); + if(err) { + ALOGW("stopPlaybackOnExtOut_l failed = %d", err); + return err; + } + } ALSAHandleList::iterator it = mDeviceList.end(); it--; - mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY, - newMode); + if (device != mCurDevice) { + if(musbPlaybackState) + closeUSBPlayback(); + } + mALSADevice->route(&(*it), device, newMode); for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) { if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) { @@ -659,8 +1005,16 @@ void AudioHardwareALSA::doRouting(int device) startUsbPlaybackIfNotStarted(); musbPlaybackState |= USBPLAYBACKBIT_LPA; break; + } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || + (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { + ALOGD("doRouting: Tunnel Player device switch to proxy"); + startUsbPlaybackIfNotStarted(); + musbPlaybackState |= USBPLAYBACKBIT_TUNNEL; + break; } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) || - (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) { + (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) || + (!strcmp(it->useCase, SND_USE_CASE_VERB_VOLTE)) || + (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) { ALOGV("doRouting: VOICE device switch to proxy"); startUsbRecordingIfNotStarted(); startUsbPlaybackIfNotStarted(); @@ -677,41 +1031,126 @@ void AudioHardwareALSA::doRouting(int device) } } else #endif - { + if ((isExtOutDevice(device)) && mRouteAudioToExtOut == true) { + ALOGV(" External Output Enabled - Routing everything to proxy now"); + switchExtOut(device); + ALSAHandleList::iterator it = mDeviceList.end(); + it--; + status_t err = NO_ERROR; + uint32_t activeUsecase = useCaseStringToEnum(it->useCase); + if (!((device & AudioSystem::DEVICE_OUT_ALL_A2DP) && + (mCurRxDevice & AUDIO_DEVICE_OUT_ALL_USB))) { + if ((activeUsecase == USECASE_HIFI_LOW_POWER) || + (activeUsecase == USECASE_HIFI_TUNNEL)) { + if (device != mCurRxDevice) { + if((isExtOutDevice(mCurRxDevice)) && + (isExtOutDevice(device))) { + activeUsecase = getExtOutActiveUseCases_l(); + stopPlaybackOnExtOut_l(activeUsecase); + mRouteAudioToExtOut = true; + } + mALSADevice->route(&(*it),(uint32_t)device, newMode); + } + err = startPlaybackOnExtOut_l(activeUsecase); + } else { + //WHY NO check for prev device here? + if (device != mCurRxDevice) { + if((isExtOutDevice(mCurRxDevice)) && + (isExtOutDevice(device))) { + activeUsecase = getExtOutActiveUseCases_l(); + stopPlaybackOnExtOut_l(activeUsecase); + mALSADevice->route(&(*it),(uint32_t)device, newMode); + mRouteAudioToExtOut = true; + startPlaybackOnExtOut_l(activeUsecase); + } else { + mALSADevice->route(&(*it),(uint32_t)device, newMode); + } + } + if (activeUsecase == USECASE_FM){ + err = startPlaybackOnExtOut_l(activeUsecase); + } + } + if(err) { + ALOGW("startPlaybackOnExtOut_l for hardware output failed err = %d", err); + stopPlaybackOnExtOut_l(activeUsecase); + mALSADevice->route(&(*it),(uint32_t)mCurRxDevice, newMode); + return err; + } + } + } else if((device & AudioSystem::DEVICE_OUT_ALL) && + (!isExtOutDevice(device)) && + mRouteAudioToExtOut == true ) { + ALOGV(" ExtOut Disable on hardware output"); + ALSAHandleList::iterator it = mDeviceList.end(); + it--; + status_t err; + uint32_t activeUsecase = getExtOutActiveUseCases_l(); + err = stopPlaybackOnExtOut_l(activeUsecase); + if(err) { + ALOGW("stopPlaybackOnExtOut_l failed = %d", err); + return err; + } + if (device != mCurDevice) { + mALSADevice->route(&(*it),(uint32_t)device, newMode); + } + } else { + setInChannels(device); ALSAHandleList::iterator it = mDeviceList.end(); it--; mALSADevice->route(&(*it), (uint32_t)device, newMode); } } mCurDevice = device; + if (device & AudioSystem::DEVICE_OUT_ALL) { + mCurRxDevice = device; + } + return NO_ERROR; +} + +void AudioHardwareALSA::setInChannels(int device) +{ + ALSAHandleList::iterator it; + + if (device & AudioSystem::DEVICE_IN_BUILTIN_MIC) { + for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) { + if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, + strlen(SND_USE_CASE_VERB_HIFI_REC)) || + !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, + strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { + mALSADevice->setInChannels(it->channels); + return; + } + } + } + + mALSADevice->setInChannels(1); } uint32_t AudioHardwareALSA::getVoipMode(int format) { switch(format) { - case AudioSystem::PCM_16_BIT: + case AUDIO_FORMAT_PCM_16_BIT: return MODE_PCM; break; - case AudioSystem::AMR_NB: + case AUDIO_FORMAT_AMR_NB: return MODE_AMR; break; - case AudioSystem::AMR_WB: + case AUDIO_FORMAT_AMR_WB: return MODE_AMR_WB; break; -#ifdef QCOM_QCHAT_ENABLED - case AudioSystem::EVRC: +#ifdef QCOM_AUDIO_FORMAT_ENABLED + case AUDIO_FORMAT_EVRC: return MODE_IS127; break; - case AudioSystem::EVRCB: + case AUDIO_FORMAT_EVRCB: return MODE_4GV_NB; break; - case AudioSystem::EVRCWB: + case AUDIO_FORMAT_EVRCWB: return MODE_4GV_WB; break; #endif - default: return MODE_PCM; } @@ -725,13 +1164,28 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, status_t *status) { Mutex::Autolock autoLock(mLock); - ALOGV("openOutputStream: devices 0x%x channels %d sampleRate %d", - devices, *channels, *sampleRate); - audio_output_flags_t flag = static_cast (*status); + audio_output_flags_t flags = static_cast (*status); + + ALOGV("openOutputStream: devices 0x%x channels %d sampleRate %d flags %x", + devices, *channels, *sampleRate, flags); status_t err = BAD_VALUE; - *status = NO_ERROR; +#ifdef QCOM_OUTPUT_FLAGS_ENABLED + if (flags & (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_TUNNEL)) { + int type = !(flags & AUDIO_OUTPUT_FLAG_LPA); //0 for LPA, 1 for tunnel + AudioSessionOutALSA *out = new AudioSessionOutALSA(this, devices, *format, *channels, + *sampleRate, type, &err); + if(err != NO_ERROR) { + mLock.unlock(); + delete out; + out = NULL; + mLock.lock(); + } + if (status) *status = err; + return out; + } +#endif AudioStreamOutALSA *out = 0; ALSAHandleList::iterator it; @@ -741,9 +1195,13 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, return out; } + if(isExtOutDevice(devices)) { + ALOGV("Set Capture from proxy true"); + mRouteAudioToExtOut = true; + } -# if 0 - if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) && +#ifdef QCOM_OUTPUT_FLAGS_ENABLED + if((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)&& ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) { bool voipstream_active = false; for(it = mDeviceList.begin(); @@ -756,7 +1214,8 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, } } if(voipstream_active == false) { - mVoipStreamCount = 0; + mVoipOutStreamCount = 0; + mVoipMicMute = false; alsa_handle_t alsa_handle; unsigned long bufferSize; if(*sampleRate == VOIP_SAMPLING_RATE_8K) { @@ -774,12 +1233,11 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, alsa_handle.bufferSize = bufferSize; alsa_handle.devices = devices; alsa_handle.handle = 0; - if(*format == AudioSystem::PCM_16_BIT) + if(*format == AUDIO_FORMAT_PCM_16_BIT) alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; else alsa_handle.format = *format; alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO; alsa_handle.sampleRate = *sampleRate; alsa_handle.latency = VOIP_PLAYBACK_LATENCY; alsa_handle.rxHandle = 0; @@ -796,22 +1254,25 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, mDeviceList.push_back(alsa_handle); it = mDeviceList.end(); it--; - ALOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipStreamCount %d mode %d", it->useCase,mCurDevice,mVoipStreamCount, mode()); + ALOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipOutStreamCount %d mode %d", it->useCase,mCurDevice,mVoipOutStreamCount, mode()); if((mCurDevice & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| - (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| - (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){ + (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) +#ifdef QCOM_PROXY_DEVICE_ENABLED + ||(mCurDevice & AudioSystem::DEVICE_OUT_PROXY) +#endif + ){ ALOGD("Routing to proxy for normal voip call in openOutputStream"); - mCurDevice |= AudioSystem::DEVICE_OUT_PROXY; - alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY; - mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION); - ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState); + mALSADevice->route(&(*it), mCurDevice, AUDIO_MODE_IN_COMMUNICATION); +#ifdef QCOM_USBAUDIO_ENABLED + ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState); startUsbPlaybackIfNotStarted(); musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState); startUsbRecordingIfNotStarted(); musbRecordingState |= USBRECBIT_VOIPCALL; - } else{ - mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION); +#endif + } else{ + mALSADevice->route(&(*it), mCurDevice, AUDIO_MODE_IN_COMMUNICATION); } if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) { snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL); @@ -824,18 +1285,28 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, return NULL; } } + if(mVoipOutStreamCount>=1) { + ALOGE("Trying to OPen Multiple Output streams: Not Supported %d",mVoipOutStreamCount); + return out; + } out = new AudioStreamOutALSA(this, &(*it)); err = out->set(format, channels, sampleRate, devices); if(err == NO_ERROR) { - mVoipStreamCount++; //increment VoipstreamCount only if success - ALOGD("openoutput mVoipStreamCount %d",mVoipStreamCount); + mVoipOutStreamCount++; //increment VoipOutputstreamCount only if success + ALOGD("openoutput mVoipOutStreamCount %d",mVoipOutStreamCount); + } else { + mLock.unlock(); + delete out; + out = NULL; + ALOGE("AudioStreamOutALSA->set() failed, return NULL"); + mLock.lock(); } if (status) *status = err; return out; } else #endif - if ((flag & AUDIO_OUTPUT_FLAG_DIRECT) && - (devices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) { + if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && + (devices == AUDIO_DEVICE_OUT_AUX_DIGITAL)) { ALOGD("Multi channel PCM"); alsa_handle_t alsa_handle; EDID_AUDIO_INFO info = { 0 }; @@ -845,22 +1316,31 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, alsa_handle.handle = 0; alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; +#ifdef TARGET_8974 + char hdmiEDIDData[MAX_SHORT_AUDIO_DESC_CNT + 1]; + // additional 1 byte for length of the EDID + if (mALSADevice->getEDIDData(hdmiEDIDData) == NO_ERROR) { + if (!AudioUtil::getHDMIAudioSinkCaps(&info, hdmiEDIDData)) { + ALOGE("openOutputStream: Failed to get HDMI sink capabilities"); + return NULL; + } + } +#else if (!AudioUtil::getHDMIAudioSinkCaps(&info)) { ALOGE("openOutputStream: Failed to get HDMI sink capabilities"); return NULL; } +#endif if (0 == *channels) { alsa_handle.channels = info.AudioBlocksArray[info.nAudioBlocks-1].nChannels; - if (alsa_handle.channels > 6) { - alsa_handle.channels = 6; + if (alsa_handle.channels > 8) { + alsa_handle.channels = 8; } *channels = audio_channel_out_mask_from_count(alsa_handle.channels); } else { alsa_handle.channels = AudioSystem::popCount(*channels); } - alsa_handle.channelMask = *channels; - - if (6 == alsa_handle.channels) { + if (alsa_handle.channels > 2) { alsa_handle.bufferSize = DEFAULT_MULTI_CHANNEL_BUF_SIZE; } else { alsa_handle.bufferSize = DEFAULT_BUFFER_SIZE; @@ -887,26 +1367,11 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, mDeviceList.push_back(alsa_handle); ALSAHandleList::iterator it = mDeviceList.end(); it--; - ALOGD("it->useCase %s", it->useCase); - mALSADevice->route(&(*it), devices, mode()); - if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI2)) { - snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI2 ); - } else { - snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC2); - } - ALOGD("channels: %d", AudioSystem::popCount(*channels)); - err = mALSADevice->open(&(*it)); - - if (err) { - ALOGE("Device open failed err:%d",err); - } else { - out = new AudioStreamOutALSA(this, &(*it)); - err = out->set(format, channels, sampleRate, devices); - } + out = new AudioStreamOutALSA(this, &(*it)); + err = out->set(format, channels, sampleRate, devices); if (status) *status = err; return out; } else { - alsa_handle_t alsa_handle; unsigned long bufferSize = DEFAULT_BUFFER_SIZE; @@ -919,59 +1384,58 @@ AudioHardwareALSA::openOutputStream(uint32_t devices, alsa_handle.handle = 0; alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; alsa_handle.channels = DEFAULT_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_OUT_STEREO; alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE; alsa_handle.latency = PLAYBACK_LATENCY; alsa_handle.rxHandle = 0; alsa_handle.ucMgr = mUcMgr; - alsa_handle.isDeepbufferOutput = false; +#ifdef QCOM_TUNNEL_LPA_ENABLED + alsa_handle.session = NULL; +#endif + alsa_handle.isFastOutput = false; char *use_case; snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case); - if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { - ALOGD("openOutputStream: DeepBuffer Output"); - alsa_handle.isDeepbufferOutput = true; - if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { - strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase)); - } else { - strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase)); - } - } else { - ALOGD("openOutputStream: Lowlatency Output"); +#ifdef QCOM_OUTPUT_FLAGS_ENABLED + if (flags & AUDIO_OUTPUT_FLAG_FAST) { alsa_handle.bufferSize = PLAYBACK_LOW_LATENCY_BUFFER_SIZE; - alsa_handle.latency = PLAYBACK_LOW_LATENCY_MEASURED; + alsa_handle.latency = PLAYBACK_LOW_LATENCY; + alsa_handle.isFastOutput = true; if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase)); } else { strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase)); } + } else +#endif + { + if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { + strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase)); + } else { + strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase)); + } } free(use_case); mDeviceList.push_back(alsa_handle); ALSAHandleList::iterator it = mDeviceList.end(); it--; - ALOGV("useCase %s", it->useCase); -#ifdef QCOM_USBAUDIO_ENABLED - if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| - (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ - ALOGD("Routing to proxy for normal playback in openOutputStream"); - devices |= AudioSystem::DEVICE_OUT_PROXY; - } -#endif + ALOGD("useCase %s", it->useCase); mALSADevice->route(&(*it), devices, mode()); - if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { - if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) { - snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI); - } else { - snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC); - } - } else { +#ifdef QCOM_OUTPUT_FLAGS_ENABLED + if (flags & AUDIO_OUTPUT_FLAG_FAST) { if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) { snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC); } else { snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC); } + } else +#endif + { + if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) { + snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI); + } else { + snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC); + } } err = mALSADevice->open(&(*it)); if (err) { @@ -1018,7 +1482,6 @@ AudioHardwareALSA::openOutputSession(uint32_t devices, alsa_handle.handle = 0; alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; alsa_handle.channels = DEFAULT_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_OUT_STEREO; alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE; alsa_handle.latency = VOICE_LATENCY; alsa_handle.rxHandle = 0; @@ -1048,8 +1511,7 @@ AudioHardwareALSA::openOutputSession(uint32_t devices, #ifdef QCOM_USBAUDIO_ENABLED if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ - ALOGD("Routing to proxy for LPA in openOutputSession"); - devices |= AudioSystem::DEVICE_OUT_PROXY; + ALOGE("Routing to proxy for LPA in openOutputSession"); mALSADevice->route(&(*it), devices, mode()); devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET; ALOGD("Starting USBPlayback for LPA"); @@ -1105,9 +1567,10 @@ AudioHardwareALSA::openInputStream(uint32_t devices, AudioStreamInALSA *in = 0; ALSAHandleList::iterator it; - ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate); + ALOGD("openInputStream: devices 0x%x format 0x%x channels %d sampleRate %d", devices, *format, *channels, *sampleRate); if (devices & (devices - 1)) { if (status) *status = err; + ALOGE("openInputStream failed error:0x%x devices:%x",err,devices); return in; } @@ -1124,7 +1587,8 @@ AudioHardwareALSA::openInputStream(uint32_t devices, } } if(voipstream_active == false) { - mVoipStreamCount = 0; + mVoipInStreamCount = 0; + mVoipMicMute = false; alsa_handle_t alsa_handle; unsigned long bufferSize; if(*sampleRate == VOIP_SAMPLING_RATE_8K) { @@ -1142,12 +1606,11 @@ AudioHardwareALSA::openInputStream(uint32_t devices, alsa_handle.bufferSize = bufferSize; alsa_handle.devices = devices; alsa_handle.handle = 0; - if(*format == AudioSystem::PCM_16_BIT) + if(*format == AUDIO_FORMAT_PCM_16_BIT) alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; else alsa_handle.format = *format; alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO; alsa_handle.sampleRate = *sampleRate; alsa_handle.latency = VOIP_RECORD_LATENCY; alsa_handle.rxHandle = 0; @@ -1168,7 +1631,7 @@ AudioHardwareALSA::openInputStream(uint32_t devices, if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ ALOGD("Routing everything from proxy for voipcall"); - mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION); + mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AUDIO_MODE_IN_COMMUNICATION); ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState); startUsbPlaybackIfNotStarted(); musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; @@ -1178,7 +1641,7 @@ AudioHardwareALSA::openInputStream(uint32_t devices, } else #endif { - mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION); + mALSADevice->route(&(*it),mCurDevice, AUDIO_MODE_IN_COMMUNICATION); } if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) { snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL); @@ -1188,19 +1651,31 @@ AudioHardwareALSA::openInputStream(uint32_t devices, if(sampleRate) { it->sampleRate = *sampleRate; } - if(channels) + if(channels) { it->channels = AudioSystem::popCount(*channels); + setInChannels(devices); + } err = mALSADevice->startVoipCall(&(*it)); if (err) { ALOGE("Error opening pcm input device"); return NULL; } } + if(mVoipInStreamCount>=1){ + ALOGE("Trying to Open Multiple inpust Stream: Not supported %d",mVoipInStreamCount); + return in; + } in = new AudioStreamInALSA(this, &(*it), acoustics); err = in->set(format, channels, sampleRate, devices); if(err == NO_ERROR) { - mVoipStreamCount++; //increment VoipstreamCount only if success - ALOGD("OpenInput mVoipStreamCount %d",mVoipStreamCount); + mVoipInStreamCount++; //increment VoipInputstreamCount only if success + ALOGD("OpenInput mVoipInStreamCount %d",mVoipInStreamCount); + } else { + mLock.unlock(); + delete in; + in = NULL; + ALOGE("AudioStreamInALSA->set() failed, return NULL"); + mLock.lock(); } ALOGD("openInput: After Get alsahandle"); if (status) *status = err; @@ -1213,9 +1688,11 @@ AudioHardwareALSA::openInputStream(uint32_t devices, alsa_handle.bufferSize = bufferSize; alsa_handle.devices = devices; alsa_handle.handle = 0; - alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; + if(*format == AUDIO_FORMAT_PCM_16_BIT) + alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; + else + alsa_handle.format = *format; alsa_handle.channels = VOICE_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO; alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE; alsa_handle.latency = RECORD_LATENCY; alsa_handle.rxHandle = 0; @@ -1223,27 +1700,37 @@ AudioHardwareALSA::openInputStream(uint32_t devices, snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case); if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) && - (newMode == AudioSystem::MODE_IN_CALL)) { + (newMode == AUDIO_MODE_IN_CALL)) { ALOGD("openInputStream: into incall recording, channels %d", *channels); mIncallMode = *channels; - if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) && - (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) { + if ((*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) && + (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK)) { if (mFusion3Platform) { mALSADevice->setVocRecMode(INCALL_REC_STEREO); strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, sizeof(alsa_handle.useCase)); } else { - strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, - sizeof(alsa_handle.useCase)); + if (*format == AUDIO_FORMAT_AMR_WB) { + strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL, + sizeof(alsa_handle.useCase)); + } else { + strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, + sizeof(alsa_handle.useCase)); + } } - } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) { + } else if (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK) { if (mFusion3Platform) { mALSADevice->setVocRecMode(INCALL_REC_MONO); strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, sizeof(alsa_handle.useCase)); } else { - strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, - sizeof(alsa_handle.useCase)); + if (*format == AUDIO_FORMAT_AMR_WB) { + strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL, + sizeof(alsa_handle.useCase)); + } else { + strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, + sizeof(alsa_handle.useCase)); + } } } #ifdef QCOM_FM_ENABLED @@ -1253,37 +1740,50 @@ AudioHardwareALSA::openInputStream(uint32_t devices, strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase)); #endif } else { - char value[128]; - property_get("persist.audio.lowlatency.rec",value,"0"); + char value[128]; + property_get("persist.audio.lowlatency.rec",value,"0"); if (!strcmp("true", value)) { strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase)); + } else if (*format == AUDIO_FORMAT_AMR_WB) { + ALOGV("Format AMR_WB, open compressed capture"); + strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, sizeof(alsa_handle.useCase)); } else { strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(alsa_handle.useCase)); } } } else { if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) && - (newMode == AudioSystem::MODE_IN_CALL)) { + (newMode == AUDIO_MODE_IN_CALL)) { ALOGD("openInputStream: incall recording, channels %d", *channels); mIncallMode = *channels; - if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) && - (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) { + if ((*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) && + (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK)) { if (mFusion3Platform) { mALSADevice->setVocRecMode(INCALL_REC_STEREO); strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC, sizeof(alsa_handle.useCase)); } else { - strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC, - sizeof(alsa_handle.useCase)); + if (*format == AUDIO_FORMAT_AMR_WB) { + strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL, + sizeof(alsa_handle.useCase)); + } else { + strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC, + sizeof(alsa_handle.useCase)); + } } - } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) { + } else if (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK) { if (mFusion3Platform) { mALSADevice->setVocRecMode(INCALL_REC_MONO); strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC, sizeof(alsa_handle.useCase)); } else { - strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC, - sizeof(alsa_handle.useCase)); + if (*format == AUDIO_FORMAT_AMR_WB) { + strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL, + sizeof(alsa_handle.useCase)); + } else { + strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC, + sizeof(alsa_handle.useCase)); + } } } #ifdef QCOM_FM_ENABLED @@ -1297,6 +1797,8 @@ AudioHardwareALSA::openInputStream(uint32_t devices, property_get("persist.audio.lowlatency.rec",value,"0"); if (!strcmp("true", value)) { strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(alsa_handle.useCase)); + } else if (*format == AUDIO_FORMAT_AMR_WB) { + strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, sizeof(alsa_handle.useCase)); } else { strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase)); } @@ -1309,15 +1811,14 @@ AudioHardwareALSA::openInputStream(uint32_t devices, //update channel info before do routing if(channels) { it->channels = AudioSystem::popCount((*channels) & - (AudioSystem::CHANNEL_IN_STEREO - | AudioSystem::CHANNEL_IN_MONO + (AUDIO_CHANNEL_IN_STEREO + | AUDIO_CHANNEL_IN_MONO #ifdef QCOM_SSR_ENABLED - | AudioSystem::CHANNEL_IN_5POINT1 + | AUDIO_CHANNEL_IN_5POINT1 #endif - | AUDIO_CHANNEL_IN_FRONT_BACK)); - it->channelMask = *channels; - ALOGV("updated channel info: channels=%d channelMask %08x", - it->channels, it->channelMask); + )); + ALOGV("updated channel info: channels=%d", it->channels); + setInChannels(devices); } if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){ /* Add current devices info to devices to do route */ @@ -1345,14 +1846,18 @@ AudioHardwareALSA::openInputStream(uint32_t devices, mALSADevice->route(&(*it), devices, mode()); } } + if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) || !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) || + !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) || #ifdef QCOM_FM_ENABLED !strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) || !strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) || #endif !strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) || !strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) || + !strcmp(it->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL) || + !strcmp(it->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL) || !strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) { snd_use_case_set(mUcMgr, "_verb", it->useCase); } else { @@ -1363,12 +1868,34 @@ AudioHardwareALSA::openInputStream(uint32_t devices, } if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { - ALOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase); + ALOGV("OpenInoutStream: getInputBufferSize sampleRate:%d format:%d, channels:%d", it->sampleRate,*format,it->channels); it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels); } + +#ifdef QCOM_SSR_ENABLED + if (6 == it->channels) { + if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) + || !strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) + || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) + || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { + //Check if SSR is supported by reading system property + char ssr_enabled[6] = "false"; + property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0"); + if (strncmp("true", ssr_enabled, 4)) { + if (status) *status = err; + ALOGE("openInputStream: FAILED:%d. Surround sound recording is not supported",*status); + } + } + } +#endif err = mALSADevice->open(&(*it)); + if (*format == AUDIO_FORMAT_AMR_WB) { + ALOGV("### Setting bufsize to 61"); + it->bufferSize = 61; + } if (err) { ALOGE("Error opening pcm input device"); + mDeviceList.erase(it); } else { in = new AudioStreamInALSA(this, &(*it), acoustics); err = in->set(format, channels, sampleRate, devices); @@ -1386,11 +1913,28 @@ AudioHardwareALSA::closeInputStream(AudioStreamIn* in) status_t AudioHardwareALSA::setMicMute(bool state) { - if (mMicMute != state) { - mMicMute = state; - ALOGD("setMicMute: mMicMute %d", mMicMute); - if(mALSADevice) { - mALSADevice->setMicMute(state); + int newMode = mode(); + ALOGD("setMicMute newMode %d state:%d",newMode,state); + if(newMode == AUDIO_MODE_IN_COMMUNICATION) { + if (mVoipMicMute != state) { + mVoipMicMute = state; + ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute); + if(mALSADevice) { + mALSADevice->setVoipMicMute(state); + } + } + } else { + if (mMicMute != state) { + mMicMute = state; + ALOGD("setMicMute: mMicMute %d", mMicMute); + if(mALSADevice) { + if(mCSCallActive == CS_ACTIVE) + mALSADevice->setMicMute(state); + else if(mVoice2CallActive == CS_ACTIVE_SESSION2) + mALSADevice->setVoice2MicMute(state); + if(mVolteCallActive == IMS_ACTIVE) + mALSADevice->setVoLTEMicMute(state); + } } } return NO_ERROR; @@ -1398,7 +1942,12 @@ status_t AudioHardwareALSA::setMicMute(bool state) status_t AudioHardwareALSA::getMicMute(bool *state) { - *state = mMicMute; + int newMode = mode(); + if(newMode == AUDIO_MODE_IN_COMMUNICATION) { + *state = mVoipMicMute; + } else { + *state = mMicMute; + } return NO_ERROR; } @@ -1410,9 +1959,20 @@ status_t AudioHardwareALSA::dump(int fd, const Vector& args) size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) { size_t bufferSize = 0; - if (format == AudioSystem::PCM_16_BIT) { + if (format == AUDIO_FORMAT_PCM_16_BIT +#ifdef QCOM_AUDIO_FORMAT_ENABLED + || format == AUDIO_FORMAT_EVRC + || format == AUDIO_FORMAT_EVRCB + || format == AUDIO_FORMAT_EVRCWB +#endif + || format == AUDIO_FORMAT_AMR_NB + || format == AUDIO_FORMAT_AMR_WB) { if(sampleRate == 8000 || sampleRate == 16000 || sampleRate == 32000) { +#ifdef TARGET_8974 + bufferSize = DEFAULT_IN_BUFFER_SIZE; +#else bufferSize = (sampleRate * channelCount * 20 * sizeof(int16_t)) / 1000; +#endif } else if (sampleRate == 11025 || sampleRate == 12000) { bufferSize = 256 * sizeof(int16_t) * channelCount; } else if (sampleRate == 22050 || sampleRate == 24000) { @@ -1421,7 +1981,8 @@ size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, in bufferSize = 1024 * sizeof(int16_t) * channelCount; } } else { - ALOGE("getInputBufferSize bad format: %d", format); + bufferSize = DEFAULT_IN_BUFFER_SIZE * channelCount; + ALOGE("getInputBufferSize bad format: %x use default input buffersize:%d", format, bufferSize); } return bufferSize; } @@ -1429,8 +1990,12 @@ size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, in #ifdef QCOM_FM_ENABLED void AudioHardwareALSA::handleFm(int device) { -int newMode = mode(); - if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) { + int newMode = mode(); + uint32_t activeUsecase = USECASE_NONE; + char ident[70]; + int tx_dev_id, capability; + + if(device & AUDIO_DEVICE_OUT_FM && mIsFmActive == 0) { // Start FM Radio on current active device unsigned long bufferSize = FM_BUFFER_SIZE; alsa_handle_t alsa_handle; @@ -1452,7 +2017,6 @@ int newMode = mode(); alsa_handle.handle = 0; alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; alsa_handle.channels = DEFAULT_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_OUT_STEREO; alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE; alsa_handle.latency = VOICE_LATENCY; alsa_handle.rxHandle = 0; @@ -1461,11 +2025,32 @@ int newMode = mode(); mDeviceList.push_back(alsa_handle); ALSAHandleList::iterator it = mDeviceList.end(); it--; - if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| - (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ - device |= AudioSystem::DEVICE_OUT_PROXY; - alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY; - ALOGD("Routing to proxy for FM case"); + + // Get the FM device ACDB ID and capability + memset(&ident,0,sizeof(ident)); + strlcpy(ident, "ACDBID/", sizeof(ident)); + strlcat(ident, "FM TX PREPROC", sizeof(ident)); + tx_dev_id = snd_use_case_get(alsa_handle.ucMgr, ident, NULL); + + memset(&ident,0,sizeof(ident)); + strlcpy(ident, "CAPABILITY/", sizeof(ident)); + strlcat(ident, "FM TX PREPROC", sizeof(ident)); + capability = snd_use_case_get(alsa_handle.ucMgr, ident, NULL); + + if ((tx_dev_id < 0) || (capability < 0)) { + ALOGD("No pre-proc calibration applied on receiving FM stream\n"); + } else { + if (mAcdbHandle == NULL) { + ALOGE("mAcdbHandle is NULL\n"); + } else { + acdb_send_audio_cal = + (void (*)(int, int))::dlsym(mAcdbHandle,"acdb_loader_send_audio_cal"); + if (acdb_send_audio_cal == NULL) { + ALOGE("acdb_send_audio_cal is NULL\n"); + } else { + acdb_send_audio_cal(tx_dev_id, capability); + } + } } mALSADevice->route(&(*it), (uint32_t)device, newMode); if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) { @@ -1474,13 +2059,26 @@ int newMode = mode(); snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM); } mALSADevice->startFm(&(*it)); + activeUsecase = useCaseStringToEnum(it->useCase); +#ifdef QCOM_USBAUDIO_ENABLED if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ ALOGD("Starting FM, musbPlaybackState %d", musbPlaybackState); startUsbPlaybackIfNotStarted(); musbPlaybackState |= USBPLAYBACKBIT_FM; } - } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) { +#endif + if(isExtOutDevice(device)) { + status_t err = NO_ERROR; + mRouteAudioToExtOut = true; + err = startPlaybackOnExtOut_l(activeUsecase); + if(err) { + ALOGE("startPlaybackOnExtOut_l for hardware output failed err = %d", err); + stopPlaybackOnExtOut_l(activeUsecase); + } + } + + } else if (!(device & AUDIO_DEVICE_OUT_FM) && mIsFmActive == 1) { //i Stop FM Radio ALOGV("Stop FM"); for(ALSAHandleList::iterator it = mDeviceList.begin(); @@ -1488,34 +2086,47 @@ int newMode = mode(); if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) || (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) { mALSADevice->close(&(*it)); + activeUsecase = useCaseStringToEnum(it->useCase); //mALSADevice->route(&(*it), (uint32_t)device, newMode); mDeviceList.erase(it); break; } } mIsFmActive = 0; +#ifdef QCOM_USBAUDIO_ENABLED musbPlaybackState &= ~USBPLAYBACKBIT_FM; if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ closeUsbPlaybackIfNothingActive(); } +#endif + if(mRouteAudioToExtOut == true) { + status_t err = NO_ERROR; + err = stopPlaybackOnExtOut_l(activeUsecase); + if(err) + ALOGE("stopPlaybackOnExtOut_l for hardware output failed err = %d", err); + } + } } #endif -void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, int device) +void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, + int device, uint32_t vsid) { for(ALSAHandleList::iterator it = mDeviceList.begin(); it != mDeviceList.end(); ++it) { if((!strcmp(it->useCase, verb)) || (!strcmp(it->useCase, modifier))) { - ALOGV("Disabling voice call"); - mALSADevice->close(&(*it)); + ALOGV("Disabling voice call vsid:%d", vsid); + mALSADevice->setInChannels(0); + mALSADevice->close(&(*it), vsid); mALSADevice->route(&(*it), (uint32_t)device, mode); mDeviceList.erase(it); break; } } + #ifdef QCOM_USBAUDIO_ENABLED if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) { ALOGD("Voice call ended on USB"); @@ -1526,12 +2137,15 @@ void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, i } #endif } -void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, int device) + +void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, + int device, uint32_t vsid) { -// Start voice call -unsigned long bufferSize = DEFAULT_VOICE_BUFFER_SIZE; -alsa_handle_t alsa_handle; -char *use_case; + // Start voice call + unsigned long bufferSize = DEFAULT_VOICE_BUFFER_SIZE; + alsa_handle_t alsa_handle; + char *use_case; + snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case); if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { strlcpy(alsa_handle.useCase, verb, sizeof(alsa_handle.useCase)); @@ -1548,7 +2162,6 @@ char *use_case; alsa_handle.handle = 0; alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE; alsa_handle.channels = VOICE_CHANNEL_MODE; - alsa_handle.channelMask = AUDIO_CHANNEL_IN_MONO; alsa_handle.sampleRate = VOICE_SAMPLING_RATE; alsa_handle.latency = VOICE_LATENCY; alsa_handle.rxHandle = 0; @@ -1556,20 +2169,17 @@ char *use_case; mDeviceList.push_back(alsa_handle); ALSAHandleList::iterator it = mDeviceList.end(); it--; -#ifdef QCOM_USBAUDIO_ENABLED - if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| - (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ - device |= AudioSystem::DEVICE_OUT_PROXY; - alsa_handle.devices = device; - } -#endif + setInChannels(device); + ALOGV("AudioHardware: enable Voice call voice_vsid:%d", vsid); + mALSADevice->route(&(*it), (uint32_t)device, mode); if (!strcmp(it->useCase, verb)) { snd_use_case_set(mUcMgr, "_verb", verb); } else { snd_use_case_set(mUcMgr, "_enamod", modifier); } - mALSADevice->startVoiceCall(&(*it)); + mALSADevice->startVoiceCall(&(*it), vsid); + #ifdef QCOM_USBAUDIO_ENABLED if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ @@ -1581,43 +2191,81 @@ char *use_case; #endif } +bool AudioHardwareALSA::isAnyCallActive() { + + bool ret = false; + + if ((mCSCallActive == CS_ACTIVE) || + (mVoice2CallActive == CS_ACTIVE_SESSION2) || + (mVolteCallActive == IMS_ACTIVE)) { + ret = true; + } + + return ret; +} + bool AudioHardwareALSA::routeVoiceCall(int device, int newMode) { -int csCallState = mCallState&0xF; - bool isRouted = false; + int csCallState = mCallState&0xF; + bool isRouted = false; + int err = 0; + switch (csCallState) { case CS_INACTIVE: if (mCSCallActive != CS_INACTIVE) { - ALOGD("doRouting: Disabling voice call"); + ALOGD("doRouting: Disabling voice call,voice_vsid:%d", + VOICE_SESSION_VSID); + disableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL, - (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device); + (char *)SND_USE_CASE_MOD_PLAY_VOICE, + newMode, device, VOICE_SESSION_VSID); isRouted = true; mCSCallActive = CS_INACTIVE; } break; case CS_ACTIVE: if (mCSCallActive == CS_INACTIVE) { - ALOGD("doRouting: Enabling CS voice call "); + ALOGD("doRouting: Enabling CS voice call voice_vsid:%d ", + VOICE_SESSION_VSID); + enableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL, - (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device); + (char *)SND_USE_CASE_MOD_PLAY_VOICE, + newMode, device, VOICE_SESSION_VSID); isRouted = true; mCSCallActive = CS_ACTIVE; } else if (mCSCallActive == CS_HOLD) { - ALOGD("doRouting: Resume voice call from hold state"); - ALSAHandleList::iterator vt_it; - for(vt_it = mDeviceList.begin(); - vt_it != mDeviceList.end(); ++vt_it) { - if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL, - strlen(SND_USE_CASE_VERB_VOICECALL))) || - (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE, - strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) { - alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); - mCSCallActive = CS_ACTIVE; - if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0) - ALOGE("VoLTE resume failed"); - break; - } - } + ALOGD("doRouting: Resume voice call from hold state"); + + ALSAHandleList::iterator vt_it; + for(vt_it = mDeviceList.begin(); + vt_it != mDeviceList.end(); ++vt_it) { + if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL, + strlen(SND_USE_CASE_VERB_VOICECALL))) || + (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE, + strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) { + alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); + mCSCallActive = CS_ACTIVE; + +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + if (csd_resume_voice == NULL) + ALOGE("csd_client_resume_voice is NULL"); + else { + err = csd_resume_voice(VOICE_SESSION_VSID); + if (err < 0) + ALOGE("routeVoiceCall: resume_voice err:%d"\ + "voice_vsid:%d", + err, VOICE_SESSION_VSID); + } + } else +#endif + { + if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0) + ALOGE("VoLTE resume failed"); + break; + } + } + } } break; case CS_HOLD: @@ -1632,9 +2280,123 @@ int csCallState = mCallState&0xF; strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) { mCSCallActive = CS_HOLD; alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); - if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0) +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + if (csd_standby_voice == NULL) + ALOGE("csd_standby_voice is NULL"); + else { + csd_standby_voice(VOICE_SESSION_VSID); + if (err < 0) + ALOGE("routeVoiceCall: standby_voice err:%d"\ + "voice_vsid:%d", + err, VOICE_SESSION_VSID); + } + } else +#endif + { + if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0) ALOGE("Voice pause failed"); + break; + } + } + } + } + break; + } + return isRouted; +} + +bool AudioHardwareALSA::routeVoice2Call(int device, int newMode) +{ + int Voice2CallState = mCallState&0xF00; + bool isRouted = false; + int err = 0; + + switch (Voice2CallState) { + case CS_INACTIVE_SESSION2: + if (mVoice2CallActive != CS_INACTIVE_SESSION2) { + ALOGV("doRouting: Disabling voice call session2"); + disableVoiceCall((char *)SND_USE_CASE_VERB_VOICE2, + (char *)SND_USE_CASE_MOD_PLAY_VOICE2, + newMode, device, VOICE2_SESSION_VSID); + isRouted = true; + mVoice2CallActive = CS_INACTIVE_SESSION2; + } + break; + case CS_ACTIVE_SESSION2: + if (mVoice2CallActive == CS_INACTIVE_SESSION2) { + ALOGD("doRouting: Enabling CS voice call session2"\ + "voice2_vsid:%d",VOICE2_SESSION_VSID); + + enableVoiceCall((char *)SND_USE_CASE_VERB_VOICE2, + (char *)SND_USE_CASE_MOD_PLAY_VOICE2, + newMode, device, VOICE2_SESSION_VSID); + isRouted = true; + mVoice2CallActive = CS_ACTIVE_SESSION2; + } else if (mVoice2CallActive == CS_HOLD_SESSION2) { + ALOGV("doRouting: Resume voice call session2 from hold state"); + ALSAHandleList::iterator vt_it; + for(vt_it = mDeviceList.begin(); + vt_it != mDeviceList.end(); ++vt_it) { + if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICE2, + strlen(SND_USE_CASE_VERB_VOICE2))) || + (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE2, + strlen(SND_USE_CASE_MOD_PLAY_VOICE2)))) { + alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); + mVoice2CallActive = CS_ACTIVE_SESSION2; +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + if (csd_resume_voice == NULL) + ALOGE("csd_client_resume_voice is NULL"); + else { + err = csd_resume_voice(VOICE2_SESSION_VSID); + if (err < 0) + ALOGE("routeVoiceCall: resume_voice err:%d"\ + "voice2_vsid:%d", + err, VOICE2_SESSION_VSID); + } + } + else +#endif + { + if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0) + ALOGE("Voice2 resume failed"); break; + } + } + } + } + break; + case CS_HOLD_SESSION2: + if (mCSCallActive == CS_ACTIVE_SESSION2) { + ALOGD("doRouting: Voice call session2 going to Hold"); + ALSAHandleList::iterator vt_it; + for(vt_it = mDeviceList.begin(); + vt_it != mDeviceList.end(); ++vt_it) { + if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICE2, + strlen(SND_USE_CASE_VERB_VOICE2))) || + (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE2, + strlen(SND_USE_CASE_MOD_PLAY_VOICE2)))) { + mCSCallActive = CS_HOLD_SESSION2; + alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + if (csd_standby_voice == NULL) + ALOGE("csd_standby_voice is NULL"); + else { + csd_standby_voice(VOICE2_SESSION_VSID); + if (err < 0) + ALOGE("routeVoice2Call: standby_voice err:%d"\ + "voice2_vsid:%d", + err, VOICE2_SESSION_VSID); + } + } else +#endif + { + if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0) + ALOGE("Voice session2 pause failed"); + break; + } } } } @@ -1642,25 +2404,32 @@ int csCallState = mCallState&0xF; } return isRouted; } + bool AudioHardwareALSA::routeVoLTECall(int device, int newMode) { -int volteCallState = mCallState&0xF0; -bool isRouted = false; -switch (volteCallState) { + int volteCallState = mCallState&0xF0; + bool isRouted = false; + int err = 0; + + switch (volteCallState) { case IMS_INACTIVE: if (mVolteCallActive != IMS_INACTIVE) { - ALOGD("doRouting: Disabling IMS call"); + ALOGD("doRouting: Disabling IMS call voice_vsid:%d", + VOLTE_SESSION_VSID); disableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE, - (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device); + (char *)SND_USE_CASE_MOD_PLAY_VOLTE, + newMode, device, VOLTE_SESSION_VSID); isRouted = true; mVolteCallActive = IMS_INACTIVE; } break; case IMS_ACTIVE: if (mVolteCallActive == IMS_INACTIVE) { - ALOGD("doRouting: Enabling IMS voice call "); + ALOGD("doRouting: Enabling IMS voice call, volte_vsid:%d ", + VOLTE_SESSION_VSID); enableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE, - (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device); + (char *)SND_USE_CASE_MOD_PLAY_VOLTE, + newMode, device, VOLTE_SESSION_VSID); isRouted = true; mVolteCallActive = IMS_ACTIVE; } else if (mVolteCallActive == IMS_HOLD) { @@ -1674,9 +2443,23 @@ switch (volteCallState) { strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) { alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); mVolteCallActive = IMS_ACTIVE; - if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0) +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + if (csd_resume_voice == NULL) + ALOGE("csd_client_resume_voice is NULL"); + else { + err = csd_resume_voice(VOLTE_SESSION_VSID); + if (err < 0) + ALOGE("routeVoLTECall: resume_voice err:%d"\ + "volte_vsid:%d", err, VOLTE_SESSION_VSID); + } + } else +#endif + { + if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0) ALOGE("VoLTE resume failed"); - break; + break; + } } } } @@ -1693,9 +2476,25 @@ switch (volteCallState) { strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) { mVolteCallActive = IMS_HOLD; alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it)); - if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0) +#ifdef QCOM_CSDCLIENT_ENABLED + if (mFusion3Platform) { + if (csd_standby_voice == NULL) + ALOGE("csd_standby_voice is NULL"); + else { + csd_standby_voice(VOLTE_SESSION_VSID); + if (err < 0) + ALOGE("routeVoLTECall:"\ + "standby_voice err:%d"\ + "volte_vsid:%d", + err, VOLTE_SESSION_VSID); + } + } else +#endif + { + if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0) ALOGE("VoLTE Pause failed"); - break; + break; + } } } } @@ -1704,4 +2503,590 @@ switch (volteCallState) { return isRouted; } +#ifdef QCOM_TUNNEL_LPA_ENABLED +void AudioHardwareALSA::pauseIfUseCaseTunnelOrLPA() { + for (ALSAHandleList::iterator it = mDeviceList.begin(); + it != mDeviceList.end(); it++) { + if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, + strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) || + (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, + strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) || + (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, + strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) || + (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA, + strlen(SND_USE_CASE_MOD_PLAY_LPA)))) { + it->session->pause_l(); + } + } +} + +void AudioHardwareALSA::resumeIfUseCaseTunnelOrLPA() { + for (ALSAHandleList::iterator it = mDeviceList.begin(); + it != mDeviceList.end(); it++) { + if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, + strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) || + (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, + strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) || + (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, + strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) || + (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA, + strlen(SND_USE_CASE_MOD_PLAY_LPA)))) { + it->session->resume_l(); + } + } +} +#endif + +status_t AudioHardwareALSA::startPlaybackOnExtOut(uint32_t activeUsecase) { + + Mutex::Autolock autoLock(mLock); + status_t err = startPlaybackOnExtOut_l(activeUsecase); + if(err) { + ALOGE("startPlaybackOnExtOut_l = %d", err); + } + return err; +} +status_t AudioHardwareALSA::startPlaybackOnExtOut_l(uint32_t activeUsecase) { + + ALOGV("startPlaybackOnExtOut_l::usecase = %d ", activeUsecase); + status_t err = NO_ERROR; + if (!mExtOutStream) { + ALOGE("Unable to open ExtOut stream"); + return err; + } + if (activeUsecase != USECASE_NONE && !mIsExtOutEnabled) { + Mutex::Autolock autolock1(mExtOutMutex); + err = setProxyProperty(0); + if(err) { + ALOGE("Proxy Property Set Failedd"); + } + int ProxyOpenRetryCount=PROXY_OPEN_RETRY_COUNT; + while(ProxyOpenRetryCount){ + err = mALSADevice->openProxyDevice(); + if(err) { + ProxyOpenRetryCount --; + usleep(PROXY_OPEN_WAIT_TIME * 1000); + ALOGV("openProxyDevice failed retrying = %d", ProxyOpenRetryCount); + } + else + break; + } + if(err) { + ALOGE("openProxyDevice failed = %d", err); + } + + mKillExtOutThread = false; + err = pthread_create(&mExtOutThread, (const pthread_attr_t *) NULL, + extOutThreadWrapper, + this); + if(err) { + ALOGE("thread create failed = %d", err); + return err; + } + mExtOutThreadAlive = true; + mIsExtOutEnabled = true; + +#ifdef OUTPUT_BUFFER_LOG + sprintf(outputfilename, "%s%d%s", outputfilename, number,".pcm"); + outputBufferFile1 = fopen (outputfilename, "ab"); + number++; +#endif + } + + setExtOutActiveUseCases_l(activeUsecase); + mALSADevice->resumeProxy(); + + Mutex::Autolock autolock1(mExtOutMutex); + ALOGV("ExtOut signal"); + mExtOutCv.signal(); + return err; +} + +status_t AudioHardwareALSA::setProxyProperty(uint32_t value) { + status_t err=NO_ERROR; + if(value){ + //property_set("proxy.can.open", "true"); + mCanOpenProxy = 1; + } + else{ + //property_set("proxy.can.open", "false"); + mCanOpenProxy = 0; + } + return err; +} + + +status_t AudioHardwareALSA::stopPlaybackOnExtOut(uint32_t activeUsecase) { + Mutex::Autolock autoLock(mLock); + status_t err = stopPlaybackOnExtOut_l(activeUsecase); + if(err) { + ALOGE("stopPlaybackOnExtOut = %d", err); + } + return err; +} + +status_t AudioHardwareALSA::stopPlaybackOnExtOut_l(uint32_t activeUsecase) { + + ALOGV("stopPlaybackOnExtOut = %d", activeUsecase); + status_t err = NO_ERROR; + suspendPlaybackOnExtOut_l(activeUsecase); + { + Mutex::Autolock autolock1(mExtOutMutex); + ALOGV("stopPlaybackOnExtOut getExtOutActiveUseCases_l = %d", + getExtOutActiveUseCases_l()); + + if(!getExtOutActiveUseCases_l()) { + mIsExtOutEnabled = false; + + mExtOutMutex.unlock(); + err = stopExtOutThread(); + if(err) { + ALOGE("stopExtOutThread Failed :: err = %d" ,err); + } + mExtOutMutex.lock(); + + if (mExtOutStream != NULL) { + ALOGV(" External Output Stream Standby called"); + mExtOutStream->common.standby(&mExtOutStream->common); + } + + err = mALSADevice->closeProxyDevice(); + if(err) { + ALOGE("closeProxyDevice failed = %d", err); + } + err = setProxyProperty(1); + mExtOutActiveUseCases = 0x0; + mRouteAudioToExtOut = false; + +#ifdef OUTPUT_BUFFER_LOG + ALOGV("close file output"); + fclose (outputBufferFile1); +#endif + } + } + return err; +} + +status_t AudioHardwareALSA::openExtOutput(int device) { + + ALOGV("openExtOutput"); + status_t err = NO_ERROR; + Mutex::Autolock autolock1(mExtOutMutex); + if (device & AudioSystem::DEVICE_OUT_ALL_A2DP) { + err= openA2dpOutput(); + if(err) { + ALOGE("openA2DPOutput failed = %d",err); + return err; + } + if(!mExtOutStream) { + mExtOutStream = mA2dpStream; + } +#ifdef QCOM_USBAUDIO_ENABLED + } else if (device & AudioSystem::DEVICE_OUT_ALL_USB) { + err= openUsbOutput(); + if(err) { + ALOGE("openUsbPOutput failed = %d",err); + return err; + } + if(!mExtOutStream) { + mExtOutStream = mUsbStream; + } +#endif + } + return err; +} + +status_t AudioHardwareALSA::closeExtOutput(int device) { + + ALOGV("closeExtOutput"); + status_t err = NO_ERROR; + Mutex::Autolock autolock1(mExtOutMutex); + if (device & AudioSystem::DEVICE_OUT_ALL_A2DP) { + if(mExtOutStream == mA2dpStream) + mExtOutStream = NULL; + err= closeA2dpOutput(); + if(err) { + ALOGE("closeA2DPOutput failed = %d",err); + return err; + } + } else if (device & AUDIO_DEVICE_OUT_ALL_USB) { + if(mExtOutStream == mUsbStream) + mExtOutStream = NULL; + err= closeUsbOutput(); + if(err) { + ALOGE("closeUsbPOutput failed = %d",err); + return err; + } + } + return err; +} + +status_t AudioHardwareALSA::openA2dpOutput() +{ + hw_module_t *mod; + int format = AUDIO_FORMAT_PCM_16_BIT; + uint32_t channels = AUDIO_CHANNEL_OUT_STEREO; + uint32_t sampleRate = AFE_PROXY_SAMPLE_RATE; + status_t status; + ALOGV("openA2dpOutput"); + struct audio_config config; + config.sample_rate = AFE_PROXY_SAMPLE_RATE; + config.channel_mask = AUDIO_CHANNEL_OUT_STEREO; + config.format = AUDIO_FORMAT_PCM_16_BIT; + + //TODO : Confirm AUDIO_HARDWARE_MODULE_ID_A2DP ??? + int rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID/*_A2DP*/, (const char*)"a2dp", + (const hw_module_t**)&mod); + if (rc) { + ALOGE("Could not get a2dp hardware module"); + return NO_INIT; + } + + rc = audio_hw_device_open(mod, &mA2dpDevice); + if(rc) { + ALOGE("couldn't open a2dp audio hw device"); + return NO_INIT; + } + //TODO: unique id 0? + status = mA2dpDevice->open_output_stream(mA2dpDevice, 0,((audio_devices_t)(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP)), + (audio_output_flags_t)AUDIO_OUTPUT_FLAG_NONE, &config, &mA2dpStream); + if(status != NO_ERROR) { + ALOGE("Failed to open output stream for a2dp: status %d", status); + } + return status; +} + +status_t AudioHardwareALSA::closeA2dpOutput() +{ + ALOGV("closeA2dpOutput"); + if(!mA2dpDevice){ + ALOGE("No Aactive A2dp output found"); + return NO_ERROR; + } + + mA2dpDevice->close_output_stream(mA2dpDevice, mA2dpStream); + mA2dpStream = NULL; + + audio_hw_device_close(mA2dpDevice); + mA2dpDevice = NULL; + return NO_ERROR; +} + +status_t AudioHardwareALSA::openUsbOutput() +{ + hw_module_t *mod; + int format = AUDIO_FORMAT_PCM_16_BIT; + uint32_t channels = AUDIO_CHANNEL_OUT_STEREO; + uint32_t sampleRate = AFE_PROXY_SAMPLE_RATE; + status_t status; + ALOGV("openUsbOutput"); + struct audio_config config; + config.sample_rate = AFE_PROXY_SAMPLE_RATE; + config.channel_mask = AUDIO_CHANNEL_OUT_STEREO; + config.format = AUDIO_FORMAT_PCM_16_BIT; + + int rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID/*_USB*/, (const char*)"usb", + (const hw_module_t**)&mod); + if (rc) { + ALOGE("Could not get usb hardware module"); + return NO_INIT; + } + + rc = audio_hw_device_open(mod, &mUsbDevice); + if(rc) { + ALOGE("couldn't open Usb audio hw device"); + return NO_INIT; + } + + status = mUsbDevice->open_output_stream(mUsbDevice, 0,((audio_devices_t)(AUDIO_DEVICE_OUT_USB_ACCESSORY)), + (audio_output_flags_t)AUDIO_OUTPUT_FLAG_NONE, &config, &mUsbStream); + if(status != NO_ERROR) { + ALOGE("Failed to open output stream for USB: status %d", status); + } + + return status; +} + +status_t AudioHardwareALSA::closeUsbOutput() +{ + ALOGV("closeUsbOutput"); + if(!mUsbDevice){ + ALOGE("No Aactive Usb output found"); + return NO_ERROR; + } + + mUsbDevice->close_output_stream(mUsbDevice, mUsbStream); + mUsbStream = NULL; + + audio_hw_device_close(mUsbDevice); + mUsbDevice = NULL; + return NO_ERROR; +} + +status_t AudioHardwareALSA::stopExtOutThread() +{ + ALOGV("stopExtOutThread"); + status_t err = NO_ERROR; + if (!mExtOutThreadAlive) { + ALOGD("Return - thread not live"); + return NO_ERROR; + } + mExtOutMutex.lock(); + mKillExtOutThread = true; + err = mALSADevice->exitReadFromProxy(); + if(err) { + ALOGE("exitReadFromProxy failed = %d", err); + } + mExtOutCv.signal(); + mExtOutMutex.unlock(); + int ret = pthread_join(mExtOutThread,NULL); + ALOGD("ExtOut thread killed = %d", ret); + return err; +} + +void AudioHardwareALSA::switchExtOut(int device) { + + ALOGV("switchExtOut"); + uint32_t sampleRate; + Mutex::Autolock autolock1(mExtOutMutex); + if (device & AudioSystem::DEVICE_OUT_ALL_A2DP) { + mExtOutStream = mA2dpStream; + } else if (device & AUDIO_DEVICE_OUT_ALL_USB) { + mExtOutStream = mUsbStream; + } else { + mExtOutStream = NULL; + } + if ((mExtOutStream == mUsbStream) && mExtOutStream != NULL) { + sampleRate = mExtOutStream->common.get_sample_rate(&mExtOutStream->common); + if (sampleRate > AFE_PROXY_SAMPLE_RATE) { + ALOGW(" Requested samplerate %d is greater than supported so fall back to %d ", + sampleRate,AFE_PROXY_SAMPLE_RATE); + sampleRate = AFE_PROXY_SAMPLE_RATE; + } + if (mResampler != NULL) { + release_resampler(mResampler); + mResampler = NULL; + } + if (sampleRate != AFE_PROXY_SAMPLE_RATE) { + mResampler = (struct resampler_itfe *)calloc(1, sizeof(struct resampler_itfe)); + if (mResampler != NULL ) { + status_t err = create_resampler(AFE_PROXY_SAMPLE_RATE, + sampleRate, + 2, //channel count + RESAMPLER_QUALITY_DEFAULT, + NULL, + &mResampler); + ALOGV(" sampleRate %d mResampler %p",sampleRate,mResampler); + if (err) { + ALOGE(" Failed to create resampler"); + free(mResampler); + mResampler = NULL; + } + } else{ + ALOGE(" Failed to allocate memory for mResampler = %p",mResampler); + } + } + } +} + +status_t AudioHardwareALSA::isExtOutDevice(int device) { + return ((device & AudioSystem::DEVICE_OUT_ALL_A2DP) || + (device & AUDIO_DEVICE_OUT_ALL_USB)) ; +} + +void *AudioHardwareALSA::extOutThreadWrapper(void *me) { + static_cast(me)->extOutThreadFunc(); + return NULL; +} + +void AudioHardwareALSA::extOutThreadFunc() { + if(!mExtOutStream) { + ALOGE("No valid External output stream found"); + return; + } + if(!mALSADevice->isProxyDeviceOpened()) { + ALOGE("No valid mProxyPcmHandle found"); + return; + } + + pid_t tid = gettid(); + androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO); + prctl(PR_SET_NAME, (unsigned long)"ExtOutThread", 0, 0, 0); + + int ionBufCount = 0; + int32_t bytesWritten = 0; + uint32_t numBytesRemaining = 0; + uint32_t bytesAvailInBuffer = 0; + uint32_t proxyBufferTime = 0; + void *data; + int err = NO_ERROR; + ssize_t size = 0; + void * outbuffer= malloc(AFE_PROXY_PERIOD_SIZE); + + mALSADevice->resetProxyVariables(); + + ALOGV("mKillExtOutThread = %d", mKillExtOutThread); + while(!mKillExtOutThread) { + { + Mutex::Autolock autolock1(mExtOutMutex); + if (mKillExtOutThread) { + break; + } + if (!mExtOutStream || !mIsExtOutEnabled || + !mALSADevice->isProxyDeviceOpened() || + (mALSADevice->isProxyDeviceSuspended()) || + (err != NO_ERROR)) { + ALOGD("ExtOutThreadEntry:: proxy opened = %d,\ + proxy suspended = %d,err =%d,\ + mExtOutStream = %p mIsExtOutEnabled = %d",\ + mALSADevice->isProxyDeviceOpened(),\ + mALSADevice->isProxyDeviceSuspended(),err,mExtOutStream, mIsExtOutEnabled); + ALOGD("ExtOutThreadEntry:: Waiting on mExtOutCv"); + mExtOutCv.wait(mExtOutMutex); + ALOGD("ExtOutThreadEntry:: received signal to wake up"); + mExtOutMutex.unlock(); + continue; + } + } + err = mALSADevice->readFromProxy(&data, &size); + if(err < 0) { + ALOGE("ALSADevice readFromProxy returned err = %d,data = %p,\ + size = %ld", err, data, size); + continue; + } + +#ifdef OUTPUT_BUFFER_LOG + if (outputBufferFile1) + { + fwrite (data,1,size,outputBufferFile1); + } +#endif + void *copyBuffer = data; + numBytesRemaining = size; + proxyBufferTime = mALSADevice->mProxyParams.mBufferTime; + { + Mutex::Autolock autolock1(mExtOutMutex); + if (mResampler != NULL) { + uint32_t inFrames = size/(AFE_PROXY_CHANNEL_COUNT*2); + uint32_t outFrames = inFrames; + mResampler->resample_from_input(mResampler, + (int16_t *)data, + &inFrames, + (int16_t *)outbuffer, + &outFrames); + copyBuffer = outbuffer; + numBytesRemaining = outFrames*(AFE_PROXY_CHANNEL_COUNT*2); + ALOGV("inFrames %d outFrames %d",inFrames,outFrames); + } + } + while (err == OK && (numBytesRemaining > 0) && !mKillExtOutThread + && mIsExtOutEnabled ) { + { + Mutex::Autolock autolock1(mExtOutMutex); + if(mExtOutStream != NULL ) { + bytesAvailInBuffer = mExtOutStream->common.get_buffer_size(&mExtOutStream->common); + uint32_t writeLen = bytesAvailInBuffer > numBytesRemaining ? + numBytesRemaining : bytesAvailInBuffer; + ALOGV("Writing %d bytes to External Output ", writeLen); + bytesWritten = mExtOutStream->write(mExtOutStream,copyBuffer, writeLen); + } else { + ALOGV(" No External output to write "); + usleep(proxyBufferTime*1000); + bytesWritten = numBytesRemaining; + } + } + //If the write fails make this thread sleep and let other + //thread (eg: stopA2DP) to acquire lock to prevent a deadlock. + if(bytesWritten == -1) { + ALOGV("bytesWritten = %d",bytesWritten); + usleep(10000); + break; + } + //Need to check warning here - void used in arithmetic + copyBuffer = (char *)copyBuffer + bytesWritten; + numBytesRemaining -= bytesWritten; + ALOGV("@_@bytes To write2:%d",numBytesRemaining); + } + } + + mALSADevice->resetProxyVariables(); + mExtOutThreadAlive = false; + ALOGD("ExtOut Thread is dying"); +} + +void AudioHardwareALSA::setExtOutActiveUseCases_l(uint32_t activeUsecase) +{ + mExtOutActiveUseCases |= activeUsecase; + ALOGD("mExtOutActiveUseCases = %u, activeUsecase = %u", mExtOutActiveUseCases, activeUsecase); +} + +uint32_t AudioHardwareALSA::getExtOutActiveUseCases_l() +{ + ALOGD("getExtOutActiveUseCases_l: mExtOutActiveUseCases = %u", mExtOutActiveUseCases); + return mExtOutActiveUseCases; +} + +void AudioHardwareALSA::clearExtOutActiveUseCases_l(uint32_t activeUsecase) { + + mExtOutActiveUseCases &= ~activeUsecase; + ALOGD("clear - mExtOutActiveUseCases = %u, activeUsecase = %u", mExtOutActiveUseCases, activeUsecase); + +} + +uint32_t AudioHardwareALSA::useCaseStringToEnum(const char *usecase) +{ + ALOGV("useCaseStringToEnum usecase:%s",usecase); + uint32_t activeUsecase = USECASE_NONE; + + if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_LOW_POWER, + strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) || + (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_LPA, + strlen(SND_USE_CASE_MOD_PLAY_LPA)))) { + activeUsecase = USECASE_HIFI_LOW_POWER; + } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_TUNNEL, + strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) || + (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_TUNNEL, + strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) { + activeUsecase = USECASE_HIFI_TUNNEL; + } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, + strlen(SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC )))|| + (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, + strlen(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)))) { + activeUsecase = USECASE_HIFI_LOWLATENCY; + } else if ((!strncmp(usecase, SND_USE_CASE_VERB_DIGITAL_RADIO, + strlen(SND_USE_CASE_VERB_DIGITAL_RADIO))) || + (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_FM, + strlen(SND_USE_CASE_MOD_PLAY_FM)))|| + (!strncmp(usecase, SND_USE_CASE_VERB_FM_REC, + strlen(SND_USE_CASE_VERB_FM_REC)))|| + (!strncmp(usecase, SND_USE_CASE_MOD_CAPTURE_FM, + strlen(SND_USE_CASE_MOD_CAPTURE_FM)))){ + activeUsecase = USECASE_FM; + } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI, + strlen(SND_USE_CASE_VERB_HIFI)))|| + (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_MUSIC, + strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) { + activeUsecase = USECASE_HIFI; + } + return activeUsecase; +} + +bool AudioHardwareALSA::suspendPlaybackOnExtOut(uint32_t activeUsecase) { + + Mutex::Autolock autoLock(mLock); + suspendPlaybackOnExtOut_l(activeUsecase); + return NO_ERROR; +} + +bool AudioHardwareALSA::suspendPlaybackOnExtOut_l(uint32_t activeUsecase) { + + Mutex::Autolock autolock1(mExtOutMutex); + ALOGD("suspendPlaybackOnExtOut_l activeUsecase = %d, mRouteAudioToExtOut = %d",\ + activeUsecase, mRouteAudioToExtOut); + clearExtOutActiveUseCases_l(activeUsecase); + if((!getExtOutActiveUseCases_l()) && mIsExtOutEnabled ) + return mALSADevice->suspendProxy(); + return NO_ERROR; +} + } // namespace android_audio_legacy diff --git a/legacy/alsa_sound/AudioHardwareALSA.h b/legacy/alsa_sound/AudioHardwareALSA.h index 4ef878b55..fecf8c056 100644 --- a/legacy/alsa_sound/AudioHardwareALSA.h +++ b/legacy/alsa_sound/AudioHardwareALSA.h @@ -1,7 +1,7 @@ /* AudioHardwareALSA.h ** ** Copyright 2008-2010, Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -19,8 +19,6 @@ #ifndef ANDROID_AUDIO_HARDWARE_ALSA_H #define ANDROID_AUDIO_HARDWARE_ALSA_H -#define QCOM_CSDCLIENT_ENABLED 1 - #include #include @@ -30,15 +28,18 @@ #include #include #include - #ifdef QCOM_USBAUDIO_ENABLED #include #endif +#include +#include extern "C" { - #include - #include "alsa_audio.h" - #include "msm8960_use_cases.h" + #include + #include + #include + #include "alsa_audio.h" + #include "msm8960_use_cases.h" } #include @@ -47,6 +48,7 @@ namespace android_audio_legacy { using android::List; using android::Mutex; +using android::Condition; class AudioHardwareALSA; /** @@ -59,26 +61,36 @@ class AudioHardwareALSA; #define DEFAULT_CHANNEL_MODE 2 #define VOICE_SAMPLING_RATE 8000 #define VOICE_CHANNEL_MODE 1 -#define PLAYBACK_LATENCY 170000 +#define PLAYBACK_LATENCY 96000 #define RECORD_LATENCY 96000 #define VOICE_LATENCY 85333 -#define DEFAULT_BUFFER_SIZE 4096 +#define DEFAULT_BUFFER_SIZE 2048 +#ifdef TARGET_8974 +#define DEFAULT_MULTI_CHANNEL_BUF_SIZE 6144 +#else //4032 = 336(kernel buffer size) * 2(bytes pcm_16) * 6(number of channels) #define DEFAULT_MULTI_CHANNEL_BUF_SIZE 4032 +#endif + #define DEFAULT_VOICE_BUFFER_SIZE 2048 #define PLAYBACK_LOW_LATENCY_BUFFER_SIZE 1024 #define PLAYBACK_LOW_LATENCY 22000 #define PLAYBACK_LOW_LATENCY_MEASURED 42000 +#ifdef TARGET_8974 +#define DEFAULT_IN_BUFFER_SIZE 512 +#define MIN_CAPTURE_BUFFER_SIZE_PER_CH 512 +#else #define DEFAULT_IN_BUFFER_SIZE 320 #define MIN_CAPTURE_BUFFER_SIZE_PER_CH 320 +#endif +#define VOIP_BUFFER_SIZE_8K 320 +#define VOIP_BUFFER_SIZE_16K 640 #define MAX_CAPTURE_BUFFER_SIZE_PER_CH 2048 #define FM_BUFFER_SIZE 1024 #define VOIP_SAMPLING_RATE_8K 8000 #define VOIP_SAMPLING_RATE_16K 16000 #define VOIP_DEFAULT_CHANNEL_MODE 1 -#define VOIP_BUFFER_SIZE_8K 320 -#define VOIP_BUFFER_SIZE_16K 640 #define VOIP_BUFFER_MAX_SIZE VOIP_BUFFER_SIZE_16K #define VOIP_PLAYBACK_LATENCY 6400 #define VOIP_RECORD_LATENCY 6400 @@ -92,6 +104,7 @@ class AudioHardwareALSA; #define DUALMIC_KEY "dualmic_enabled" #define FLUENCE_KEY "fluence" +#define VOIPCHECK_KEY "voip_flag" #define ANC_KEY "anc_enabled" #define TTY_MODE_KEY "tty_mode" #define BT_SAMPLERATE_KEY "bt_samplerate" @@ -118,11 +131,15 @@ class AudioHardwareALSA; #define LPA_SESSION_ID 1 #define TUNNEL_SESSION_ID 2 #ifdef QCOM_USBAUDIO_ENABLED +#define PROXY_OPEN_WAIT_TIME 20 +#define PROXY_OPEN_RETRY_COUNT 100 + static int USBPLAYBACKBIT_MUSIC = (1 << 0); static int USBPLAYBACKBIT_VOICECALL = (1 << 1); static int USBPLAYBACKBIT_VOIPCALL = (1 << 2); static int USBPLAYBACKBIT_FM = (1 << 3); static int USBPLAYBACKBIT_LPA = (1 << 4); +static int USBPLAYBACKBIT_TUNNEL = (1 << 5); static int USBRECBIT_REC = (1 << 0); static int USBRECBIT_VOICECALL = (1 << 1); @@ -143,10 +160,62 @@ static int USBRECBIT_FM = (1 << 3); #endif #define MODE_CALL_KEY "CALL_KEY" +#ifndef ALSA_DEFAULT_SAMPLE_RATE +#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz +#endif + +#define NUM_FDS 2 +#define AFE_PROXY_SAMPLE_RATE 48000 +#define AFE_PROXY_CHANNEL_COUNT 2 +#define AFE_PROXY_PERIOD_SIZE 3072 + +#define MAX_SLEEP_RETRY 100 /* Will check 100 times before continuing */ +#define AUDIO_INIT_SLEEP_WAIT 50 /* 50 ms */ + +/* Front left channel. */ +#define PCM_CHANNEL_FL 1 +/* Front right channel. */ +#define PCM_CHANNEL_FR 2 +/* Front center channel. */ +#define PCM_CHANNEL_FC 3 +/* Left surround channel.*/ +#define PCM_CHANNEL_LS 4 +/* Right surround channel.*/ +#define PCM_CHANNEL_RS 5 +/* Low frequency effect channel. */ +#define PCM_CHANNEL_LFE 6 +/* Center surround channel; Rear center channel. */ +#define PCM_CHANNEL_CS 7 +/* Left back channel; Rear left channel. */ +#define PCM_CHANNEL_LB 8 +/* Right back channel; Rear right channel. */ +#define PCM_CHANNEL_RB 9 +/* Top surround channel. */ +#define PCM_CHANNEL_TS 10 +/* Center vertical height channel.*/ +#define PCM_CHANNEL_CVH 11 +/* Mono surround channel.*/ +#define PCM_CHANNEL_MS 12 +/* Front left of center. */ +#define PCM_CHANNEL_FLC 13 +/* Front right of center. */ +#define PCM_CHANNEL_FRC 14 +/* Rear left of center. */ +#define PCM_CHANNEL_RLC 15 +/* Rear right of center. */ +#define PCM_CHANNEL_RRC 16 + +#define SOUND_CARD_SLEEP_RETRY 5 /* Will check 5 times before continuing */ +#define SOUND_CARD_SLEEP_WAIT 100 /* 100 ms */ + +#define VOICE_SESSION_VSID 0x01 +#define VOLTE_SESSION_VSID 0x02 +#define VOICE2_SESSION_VSID 0x03 +#define ALL_SESSION_VSID 0x04 -struct alsa_device_t; static uint32_t FLUENCE_MODE_ENDFIRE = 0; static uint32_t FLUENCE_MODE_BROADSIDE = 1; +class ALSADevice; enum { INCALL_REC_MONO, @@ -157,27 +226,40 @@ enum audio_call_mode { CS_INACTIVE = 0x0, CS_ACTIVE = 0x1, CS_HOLD = 0x2, + CS_INACTIVE_SESSION2 = 0x0, + CS_ACTIVE_SESSION2 = 0x100, + CS_HOLD_SESSION2 = 0x200, IMS_INACTIVE = 0x0, IMS_ACTIVE = 0x10, IMS_HOLD = 0x20 }; - +class AudioSessionOutALSA; struct alsa_handle_t { - alsa_device_t * module; + ALSADevice* module; uint32_t devices; char useCase[MAX_STR_LEN]; struct pcm * handle; snd_pcm_format_t format; uint32_t channels; - audio_channel_mask_t channelMask; uint32_t sampleRate; + int mode; unsigned int latency; // Delay in usec unsigned int bufferSize; // Size of sample buffer unsigned int periodSize; - bool isDeepbufferOutput; + bool isFastOutput; struct pcm * rxHandle; snd_use_case_mgr_t *ucMgr; +#ifdef QCOM_TUNNEL_LPA_ENABLED + AudioSessionOutALSA *session; +#endif +}; + +struct output_metadata_handle_t { + uint32_t metadataLength; + uint32_t bufferLength; + uint64_t timestamp; + uint32_t reserved[12]; }; typedef List < alsa_handle_t > ALSAHandleList; @@ -188,39 +270,131 @@ struct use_case_t { typedef List < use_case_t > ALSAUseCaseList; -struct alsa_device_t { - hw_device_t common; - - status_t (*init)(alsa_device_t *, ALSAHandleList &); - status_t (*open)(alsa_handle_t *); - status_t (*close)(alsa_handle_t *); - status_t (*standby)(alsa_handle_t *); - status_t (*route)(alsa_handle_t *, uint32_t, int); - status_t (*startVoiceCall)(alsa_handle_t *); - status_t (*startVoipCall)(alsa_handle_t *); - status_t (*startFm)(alsa_handle_t *); - void (*setVoiceVolume)(int); - void (*setVoipVolume)(int); - void (*setMicMute)(int); - void (*setVoipMicMute)(int); - void (*setVoipConfig)(int, int); - status_t (*setFmVolume)(int); - void (*setBtscoRate)(int); - status_t (*setLpaVolume)(int); - void (*enableWideVoice)(bool); - void (*enableFENS)(bool); - void (*setFlags)(uint32_t); - status_t (*setCompressedVolume)(int); - void (*enableSlowTalk)(bool); - void (*setVocRecMode)(uint8_t); - void (*setVoLTEMicMute)(int); - void (*setVoLTEVolume)(int); +class ALSADevice +{ + +public: + + ALSADevice(); + virtual ~ALSADevice(); +// status_t init(alsa_device_t *module, ALSAHandleList &list); + status_t open(alsa_handle_t *handle); + status_t close(alsa_handle_t *handle, uint32_t vsid = 0); + status_t standby(alsa_handle_t *handle); + status_t route(alsa_handle_t *handle, uint32_t devices, int mode); + status_t startVoiceCall(alsa_handle_t *handle, uint32_t vsid = 0); + status_t startVoipCall(alsa_handle_t *handle); + status_t startFm(alsa_handle_t *handle); + void setVoiceVolume(int volume); + void setVoipVolume(int volume); + void setMicMute(int state); + void setVoipMicMute(int state); + void setVoipConfig(int mode, int rate); + status_t setFmVolume(int vol); + void setBtscoRate(int rate); + status_t setLpaVolume(int vol); + void enableWideVoice(bool flag, uint32_t vsid = 0); + void enableFENS(bool flag, uint32_t vsid = 0); + void setFlags(uint32_t flag); + status_t setCompressedVolume(int vol); + status_t setChannelMap(alsa_handle_t *handle, int maxChannels); + void enableSlowTalk(bool flag, uint32_t vsid = 0); + void setVocRecMode(uint8_t mode); + void setVoLTEMicMute(int state); + void setVoLTEVolume(int vol); + void setVoice2MicMute(int state); + void setVoice2Volume(int vol); + status_t setEcrxDevice(char *device); + void setInChannels(int); + //TODO:check if this needs to be public + void disableDevice(alsa_handle_t *handle); + char *getUCMDeviceFromAcdbId(int acdb_id); + status_t getEDIDData(char *hdmiEDIDData); #ifdef SEPERATED_AUDIO_INPUT - void (*setInput)(int); + void setInput(int); #endif #ifdef QCOM_CSDCLIENT_ENABLED - void (*setCsdHandle)(void*); + void setCsdHandle(void*); +#endif +#ifdef QCOM_ACDB_ENABLED + void setACDBHandle(void*); +#endif + + bool mSSRComplete; + int mCurDevice; +protected: + friend class AudioHardwareALSA; +private: + void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode); + int getUseCaseType(const char *useCase); + status_t setHDMIChannelCount(); + void setChannelAlloc(int channelAlloc); + status_t setHardwareParams(alsa_handle_t *handle); + int deviceName(alsa_handle_t *handle, unsigned flags, char **value); + status_t setSoftwareParams(alsa_handle_t *handle); + status_t getMixerControl(const char *name, unsigned int &value, int index = 0); + status_t getMixerControlExt(const char *name, unsigned **getValues, unsigned *count); + status_t setMixerControl(const char *name, unsigned int value, int index = -1); + status_t setMixerControl(const char *name, const char *); + status_t setMixerControlExt(const char *name, int count, char **setValues); + char * getUCMDevice(uint32_t devices, int input, char *rxDevice); + status_t start(alsa_handle_t *handle); + + status_t openProxyDevice(); + status_t closeProxyDevice(); + bool isProxyDeviceOpened(); + bool isProxyDeviceSuspended(); + bool suspendProxy(); + bool resumeProxy(); + void resetProxyVariables(); + ssize_t readFromProxy(void **captureBuffer , ssize_t *bufferSize); + status_t exitReadFromProxy(); + void initProxyParams(); + status_t startProxy(); + +private: + char mMicType[25]; + char mCurRxUCMDevice[50]; + char mCurTxUCMDevice[50]; + //fluence mode value: FLUENCE_MODE_BROADSIDE or FLUENCE_MODE_ENDFIRE + uint32_t mFluenceMode; + int mFmVolume; + uint32_t mDevSettingsFlag; + int mBtscoSamplerate; + ALSAUseCaseList mUseCaseList; + void *mcsd_handle; + void *macdb_handle; + int mCallMode; + struct mixer* mMixer; + int mInChannels; + bool mIsSglte; + bool mIsFmEnabled; +#ifdef SEPERATED_AUDIO_INPUT + int mInput_source #endif +// ALSAHandleList *mDeviceList; + + struct proxy_params { + bool mExitRead; + struct pcm *mProxyPcmHandle; + uint32_t mCaptureBufferSize; + void *mCaptureBuffer; + enum { + EProxyClosed = 0, + EProxyOpened = 1, + EProxySuspended = 2, + EProxyCapture = 3, + }; + + uint32_t mProxyState; + struct snd_xferi mX; + unsigned mAvail; + struct pollfd mPfdProxy[NUM_FDS]; + long mFrames; + long mBufferTime; + }; + struct proxy_params mProxyParams; + }; // ---------------------------------------------------------------------------- @@ -245,21 +419,6 @@ public: }; -class ALSAControl -{ -public: - ALSAControl(const char *device = "/dev/snd/controlC0"); - virtual ~ALSAControl(); - - status_t get(const char *name, unsigned int &value, int index = 0); - status_t set(const char *name, unsigned int value, int index = -1); - status_t set(const char *name, const char *); - status_t setext(const char *name, int count, char **setValues); - -private: - struct mixer* mHandle; -}; - class ALSAStreamOps { public: @@ -338,11 +497,162 @@ public: private: uint32_t mFrameCount; + uint32_t mUseCase; protected: AudioHardwareALSA * mParent; }; +// ---------------------------------------------------------------------------- +#ifdef QCOM_TUNNEL_LPA_ENABLED +class AudioSessionOutALSA : public AudioStreamOut +{ +public: + AudioSessionOutALSA(AudioHardwareALSA *parent, + uint32_t devices, + int format, + uint32_t channels, + uint32_t samplingRate, + int type, + status_t *status); + virtual ~AudioSessionOutALSA(); + + virtual uint32_t sampleRate() const + { + return mSampleRate; + } + + virtual size_t bufferSize() const + { + return mBufferSize; + } + + virtual uint32_t channels() const + { + return mChannels; + } + + virtual int format() const + { + return mFormat; + } + + virtual uint32_t latency() const; + + virtual ssize_t write(const void *buffer, size_t bytes); + + virtual status_t start(); + virtual status_t pause(); + virtual status_t flush(); + virtual status_t stop(); + + virtual status_t dump(int fd, const Vector& args); + + status_t setVolume(float left, float right); + + virtual status_t standby(); + + virtual status_t setParameters(const String8& keyValuePairs); + + virtual String8 getParameters(const String8& keys); + + + // return the number of audio frames written by the audio dsp to DAC since + // the output has exited standby + virtual status_t getRenderPosition(uint32_t *dspFrames); + + virtual status_t getNextWriteTimestamp(int64_t *timestamp); + + virtual status_t setObserver(void *observer); + + virtual status_t getBufferInfo(buf_info **buf); + virtual status_t isBufferAvailable(int *isAvail); + status_t pause_l(); + status_t resume_l(); + + void updateMetaData(size_t bytes); + status_t setMetaDataMode(); + +private: + Mutex mLock; + uint32_t mFrameCount; + uint32_t mSampleRate; + uint32_t mChannels; + size_t mBufferSize; + int mFormat; + uint32_t mStreamVol; + + bool mPaused; + bool mSkipEOS; + bool mSeeking; + bool mReachedEOS; + bool mSkipWrite; + bool mEosEventReceived; + AudioHardwareALSA *mParent; + alsa_handle_t * mAlsaHandle; + ALSADevice * mAlsaDevice; + snd_use_case_mgr_t *mUcMgr; + AudioEventObserver *mObserver; + output_metadata_handle_t mOutputMetadataTunnel; + uint32_t mOutputMetadataLength; + uint32_t mUseCase; + status_t openDevice(char *pUseCase, bool bIsUseCase, int devices); + + status_t closeDevice(alsa_handle_t *pDevice); + void createEventThread(); + void bufferAlloc(alsa_handle_t *handle); + void bufferDeAlloc(); + bool isReadyToPostEOS(int errPoll, void *fd); + status_t drain(); + status_t openAudioSessionDevice(int type, int devices); + // make sure the event thread also exited + void requestAndWaitForEventThreadExit(); + int32_t writeToDriver(char *buffer, int bytes); + static void * eventThreadWrapper(void *me); + void eventThreadEntry(); + void reset(); + status_t drainAndPostEOS_l(); + + //Structure to hold mem buffer information + class BuffersAllocated { + public: + BuffersAllocated(void *buf1, int32_t nSize) : + memBuf(buf1), memBufsize(nSize), bytesToWrite(0) + {} + void* memBuf; + int32_t memBufsize; + uint32_t bytesToWrite; + }; + List mEmptyQueue; + List mFilledQueue; + List mBufPool; + + //Declare all the threads + pthread_t mEventThread; + + //Declare the condition Variables and Mutex + Mutex mEmptyQueueMutex; + Mutex mFilledQueueMutex; + + //Mutex for sync between decoderthread and control thread + Mutex mDecoderLock; + + Condition mWriteCv; + Condition mEventCv; + bool mKillEventThread; + bool mEventThreadAlive; + int mInputBufferSize; + int mInputBufferCount; + + //event fd to signal the EOS and Kill from the userspace + int mEfd; + bool mTunnelMode; + +public: + bool mRouteAudioToA2dp; +}; +#endif //QCOM_TUNNEL_LPA_ENABLED + class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps { public: @@ -398,7 +708,7 @@ public: { return BAD_VALUE; } - + virtual status_t removeAudioEffect(effect_handle_t effect) { return BAD_VALUE; @@ -415,11 +725,6 @@ public: private: void resetFramesLost(); -#ifdef QCOM_CSDCLIENT_ENABLED - int start_csd_record(int); - int stop_csd_record(void); -#endif - unsigned int mFramesLost; AudioSystem::audio_in_acoustics mAcoustics; @@ -518,6 +823,16 @@ public: AudioSystem::audio_in_acoustics acoustics); virtual void closeInputStream(AudioStreamIn* in); + status_t startPlaybackOnExtOut(uint32_t activeUsecase); + status_t stopPlaybackOnExtOut(uint32_t activeUsecase); + status_t setProxyProperty(uint32_t value); + bool suspendPlaybackOnExtOut(uint32_t activeUsecase); + + status_t startPlaybackOnExtOut_l(uint32_t activeUsecase); + status_t stopPlaybackOnExtOut_l(uint32_t activeUsecase); + bool suspendPlaybackOnExtOut_l(uint32_t activeUsecase); + status_t isExtOutDevice(int device); + /**This method dumps the state of the audio hardware */ //virtual status_t dumpState(int fd, const Vector& args); @@ -528,10 +843,29 @@ public: return mMode; } + void pauseIfUseCaseTunnelOrLPA(); + void resumeIfUseCaseTunnelOrLPA(); + +private: + status_t openExtOutput(int device); + status_t closeExtOutput(int device); + status_t openA2dpOutput(); + status_t closeA2dpOutput(); + status_t openUsbOutput(); + status_t closeUsbOutput(); + status_t stopExtOutThread(); + void extOutThreadFunc(); + static void* extOutThreadWrapper(void *context); + void setExtOutActiveUseCases_l(uint32_t activeUsecase); + uint32_t getExtOutActiveUseCases_l(); + void clearExtOutActiveUseCases_l(uint32_t activeUsecase); + uint32_t useCaseStringToEnum(const char *usecase); + void switchExtOut(int device); + protected: virtual status_t dump(int fd, const Vector& args); virtual uint32_t getVoipMode(int format); - void doRouting(int device); + status_t doRouting(int device); #ifdef QCOM_FM_ENABLED void handleFm(int device); #endif @@ -543,16 +877,22 @@ protected: void startUsbPlaybackIfNotStarted(); void startUsbRecordingIfNotStarted(); #endif - - void disableVoiceCall(char* verb, char* modifier, int mode, int device); - void enableVoiceCall(char* verb, char* modifier, int mode, int device); - bool routeVoiceCall(int device, int newMode); + void setInChannels(int device); + + void disableVoiceCall(char* verb, char* modifier, int mode, int device, + uint32_t vsid = 0); + void enableVoiceCall(char* verb, char* modifier, int mode, int device, + uint32_t vsid = 0); + bool isAnyCallActive(); + bool routeVoiceCall(int device, int newMode); bool routeVoLTECall(int device, int newMode); + bool routeVoice2Call(int device, int newMode); + friend class AudioSessionOutALSA; friend class AudioStreamOutALSA; friend class AudioStreamInALSA; friend class ALSAStreamOps; - alsa_device_t * mALSADevice; + ALSADevice* mALSADevice; ALSAHandleList mDeviceList; @@ -564,17 +904,22 @@ protected: snd_use_case_mgr_t *mUcMgr; - uint32_t mCurDevice; + int32_t mCurRxDevice; + int32_t mCurDevice; + int32_t mCanOpenProxy; /* The flag holds all the audio related device settings from * Settings and Qualcomm Settings applications */ uint32_t mDevSettingsFlag; - uint32_t mVoipStreamCount; + uint32_t mVoipInStreamCount; + uint32_t mVoipOutStreamCount; + bool mVoipMicMute; uint32_t mVoipBitRate; uint32_t mIncallMode; bool mMicMute; int mCSCallActive; int mVolteCallActive; + int mVoice2CallActive; int mCallState; int mIsFmActive; bool mBluetoothVGS; @@ -583,8 +928,42 @@ protected: int musbPlaybackState; int musbRecordingState; #endif + void *mAcdbHandle; void *mCsdHandle; + + //fluence key value: fluencepro, fluence, or none + char mFluenceKey[20]; + //A2DP variables + audio_stream_out *mA2dpStream; + audio_hw_device_t *mA2dpDevice; + + audio_stream_out *mUsbStream; + audio_hw_device_t *mUsbDevice; + audio_stream_out *mExtOutStream; + struct resampler_itfe *mResampler; + + + volatile bool mKillExtOutThread; + volatile bool mExtOutThreadAlive; + pthread_t mExtOutThread; + Mutex mExtOutMutex; + Condition mExtOutCv; + volatile bool mIsExtOutEnabled; + + enum { + USECASE_NONE = 0x0, + USECASE_HIFI = 0x1, + USECASE_HIFI_LOWLATENCY = 0x2, + USECASE_HIFI_LOW_POWER = 0x4, + USECASE_HIFI_TUNNEL = 0x8, + USECASE_FM = 0x10, + }; + uint32_t mExtOutActiveUseCases; + status_t mStatus; + +public: + bool mRouteAudioToExtOut; }; // ---------------------------------------------------------------------------- diff --git a/legacy/alsa_sound/AudioPolicyManagerALSA.cpp b/legacy/alsa_sound/AudioPolicyManagerALSA.cpp index 93c9b01a3..17e2c51cd 100644 --- a/legacy/alsa_sound/AudioPolicyManagerALSA.cpp +++ b/legacy/alsa_sound/AudioPolicyManagerALSA.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * 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. @@ -17,11 +18,29 @@ #define LOG_TAG "AudioPolicyManagerALSA" //#define LOG_NDEBUG 0 -#define LOG_NDDEBUG 0 +//#define LOG_NDDEBUG 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 + #include #include "AudioPolicyManagerALSA.h" +#include +#include +#include +#include #include +#include +#include namespace android_audio_legacy { @@ -29,24 +48,415 @@ namespace android_audio_legacy { // AudioPolicyManagerALSA // ---------------------------------------------------------------------------- -//Compiling error seen if AudioParamer doesn't exist in this file - AudioParameter param; -// --- class factory +void AudioPolicyManager::releaseOutput(audio_io_handle_t output) +{ + ALOGV("releaseOutput() %d", output); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("releaseOutput() releasing unknown output %d", output); + return; + } +#ifdef AUDIO_POLICY_TEST + int testIndex = testOutputIndex(output); + if (testIndex != 0) { + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + if (outputDesc->isActive()) { + mpClientInterface->closeOutput(output); + delete mOutputs.valueAt(index); + mOutputs.removeItem(output); + mTestOutputs[testIndex] = 0; + } + return; + } +#endif //AUDIO_POLICY_TEST -extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) + AudioOutputDescriptor *desc = mOutputs.valueAt(index); + if (desc->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) { + if ((desc->mDirectOpenCount <= 0) && !(desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL || + desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)) { + ALOGW("releaseOutput() invalid open count %d for output %d", + desc->mDirectOpenCount, output); + return; + } + if ((--desc->mDirectOpenCount == 0) || ((desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL || + desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX))) { + ALOGV("releaseOutput() closing output"); + closeOutput(output); + } + } + +} + +uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc, + audio_devices_t prevDevice, + uint32_t delayMs) { - return new AudioPolicyManager(clientInterface); + // mute/unmute strategies using an incompatible device combination + // if muting, wait for the audio in pcm buffer to be drained before proceeding + // if unmuting, unmute only after the specified delay + if (outputDesc->isDuplicated()) { + return 0; + } + + uint32_t muteWaitMs = 0; + audio_devices_t device = outputDesc->device(); + bool shouldMute = outputDesc->isActive() && (AudioSystem::popCount(device) >= 2); + // temporary mute output if device selection changes to avoid volume bursts due to + // different per device volumes + bool tempMute = outputDesc->isActive() && (device != prevDevice); + + for (size_t i = 0; i < NUM_STRATEGIES; i++) { + audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); + bool mute = shouldMute && (curDevice & device) && (curDevice != device); + bool doMute = false; + + if (mute && !outputDesc->mStrategyMutedByDevice[i]) { + doMute = true; + outputDesc->mStrategyMutedByDevice[i] = true; + } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){ + doMute = true; + outputDesc->mStrategyMutedByDevice[i] = false; + } + if (doMute || tempMute) { + for (size_t j = 0; j < mOutputs.size(); j++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(j); + // skip output if it does not share any device with current output + if ((desc->supportedDevices() & outputDesc->supportedDevices()) + == AUDIO_DEVICE_NONE) { + continue; + } + audio_io_handle_t curOutput = mOutputs.keyAt(j); + ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d", + mute ? "muting" : "unmuting", i, curDevice, curOutput); + setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs); + if (desc->isStrategyActive((routing_strategy)i)) { + // do tempMute only for current output + if (tempMute && (desc == outputDesc)) { + setStrategyMute((routing_strategy)i, true, curOutput); + setStrategyMute((routing_strategy)i, false, curOutput, + desc->latency() * 2, device); + } + if ((tempMute && (desc == outputDesc)) || mute) { + if (muteWaitMs < desc->latency()) { + muteWaitMs = desc->latency(); + } + } + } + } + } + } + + // FIXME: should not need to double latency if volume could be applied immediately by the + // audioflinger mixer. We must account for the delay between now and the next time + // the audioflinger thread for this output will process a buffer (which corresponds to + // one buffer size, usually 1/2 or 1/4 of the latency). + muteWaitMs *= 2; + // wait for the PCM output buffers to empty before proceeding with the rest of the command + if (muteWaitMs > delayMs) { + muteWaitMs -= delayMs; + usleep(muteWaitMs * 1000); + return muteWaitMs; + } + return 0; } -extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) + +status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address) { - delete interface; + SortedVector 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)) { + + //Use QCOM's a2dp and usb audio solution, no need to check here + /*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 (audio_is_a2dp_device(device)) { + AudioParameter param; + param.add(String8("a2dp_connected"), String8("true")); + mpClientInterface->setParameters(0, param.toString()); + } + if ( audio_is_usb_device(device)) { + AudioParameter param; + param.add(String8("usb_connected"), String8("true")); + mpClientInterface->setParameters(0, param.toString()); + } + if (!outputs.isEmpty()) { + String8 paramStr; + if (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 (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 (audio_is_a2dp_device(device)) { + // handle A2DP device disconnection + mA2dpDeviceAddress = ""; + mA2dpSuspended = false; + + AudioParameter param; + param.add(String8("a2dp_connected"), String8("false")); + mpClientInterface->setParameters(0, param.toString()); + + } else if (audio_is_bluetooth_sco_device(device)) { + // handle SCO device disconnection + mScoDeviceAddress = ""; + } else if (audio_is_usb_device(device)) { + // handle USB device disconnection + mUsbCardAndDevice = ""; + + AudioParameter param; + param.add(String8("usb_connected"), String8("false")); + mpClientInterface->setParameters(0, param.toString()); + } + // 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++) { + // 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) { + closeOutput(outputs[i]); + } + } + } + + updateDevicesAndOutputs(); +#ifdef QCOM_PROXY_DEVICE_ENABLED + if (state == AudioSystem::DEVICE_STATE_AVAILABLE && + audio_is_a2dp_device(device) && + (mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY)) { + ALOGV("Delay the proxy device open"); + return NO_ERROR; + } +#endif + + audio_devices_t newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); +#ifdef QCOM_FM_ENABLED + if(device == AUDIO_DEVICE_OUT_FM) { + if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { + ALOGV("setDeviceConnectionState() changeRefCount Inc"); + mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1); + newDevice = (audio_devices_t)(AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false) | AUDIO_DEVICE_OUT_FM); + } + else { + ALOGV("setDeviceConnectionState() changeRefCount Dec"); + mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1); + } + + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyHandleFm), (int)newDevice); + ALOGV("setDeviceConnectionState() setParameters handle_fm"); + mpClientInterface->setParameters(mPrimaryOutput, param.toString()); + } +#endif + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_devices_t newDevice = getNewDevice(mOutputs.keyAt(i), true /*fromCache*/); +#ifdef QCOM_ANC_HEADSET_ENABLED + if(device == AUDIO_DEVICE_OUT_ANC_HEADPHONE || + device == AUDIO_DEVICE_OUT_ANC_HEADSET) { + if(newDevice == 0){ + newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false); + } + } +#endif + setOutputDevice(mOutputs.keyAt(i), + getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), + true, + 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; +#ifdef QCOM_ANC_HEADSET_ENABLED + } else if(device == AUDIO_DEVICE_OUT_ANC_HEADSET){ + device = AUDIO_DEVICE_IN_ANC_HEADSET; //wait for actual ANC device +#endif + } 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::setPhoneState(int state) { + +AudioSystem::device_connection_state AudioPolicyManager::getDeviceConnectionState(audio_devices_t device, + const char *device_address) +{ + AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE; + String8 address = String8(device_address); + if (audio_is_output_device(device)) { + if (device & mAvailableOutputDevices) { + if (audio_is_a2dp_device(device) && + ((address != "" && mA2dpDeviceAddress != address))) { + return state; + } + if (audio_is_bluetooth_sco_device(device) && + address != "" && mScoDeviceAddress != address) { + return state; + } + if (audio_is_usb_device(device) && + ((address != "" && mUsbCardAndDevice != address))) { + ALOGE("getDeviceConnectionState() invalid device: %x", device); + return state; + } + if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) { + return state; + } + state = AudioSystem::DEVICE_STATE_AVAILABLE; + } + } else if (audio_is_input_device(device)) { + if (device & mAvailableInputDevices) { + state = AudioSystem::DEVICE_STATE_AVAILABLE; + } + } + + return state; +} + + +void AudioPolicyManager::setPhoneState(int state) +{ ALOGV("setPhoneState() state %d", state); audio_devices_t newDevice = AUDIO_DEVICE_NONE; if (state < 0 || state >= AudioSystem::NUM_MODES) { @@ -54,7 +464,7 @@ void AudioPolicyManager::setPhoneState(int state) { return; } - if (state == mPhoneState) { + if (state == mPhoneState ) { ALOGW("setPhoneState() setting same state %d", state); return; } @@ -92,10 +502,11 @@ void AudioPolicyManager::setPhoneState(int state) { } // check for device and output changes triggered by new phone state - newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); + // Need to update A2DP suspend first then getNewDevice(from cache) checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); + newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); @@ -105,53 +516,56 @@ void AudioPolicyManager::setPhoneState(int state) { newDevice = hwOutputDesc->device(); } - // when changing from ring tone to in call mode, mute the ringing tone - // immediately and delay the route change to avoid sending the ring tone - // tail into the earpiece or headset. int delayMs = 0; - if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) { - // delay the device change command by twice the output latency to have some margin - // and be sure that audio buffers not yet affected by the mute are out when - // we actually apply the route change - delayMs = hwOutputDesc->mLatency*2; - setStreamMute(AudioSystem::RING, true, mPrimaryOutput); + if (state == AUDIO_MODE_IN_CALL && +#ifdef QCOM_CSDCLIENT_ENABLED + platform_is_Fusion3() && +#endif + oldState == AUDIO_MODE_RINGTONE) { + delayMs = 40; } if (isStateInCall(state)) { + nsecs_t sysTime = systemTime(); for (size_t i = 0; i < mOutputs.size(); i++) { AudioOutputDescriptor *desc = mOutputs.valueAt(i); - //take the biggest latency for all outputs - if (delayMs < desc->mLatency*2) { + // mute media and sonification strategies and delay device switch by the largest + // latency of any output where either strategy is active. + // This avoid sending the ring tone or music tail into the earpiece or headset. + if ((desc->isStrategyActive(STRATEGY_MEDIA, + SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime) || + desc->isStrategyActive(STRATEGY_SONIFICATION, + SONIFICATION_HEADSET_MUSIC_DELAY, + sysTime)) && + (delayMs < (int)desc->mLatency*2)) { delayMs = desc->mLatency*2; } - //mute STRATEGY_MEDIA on all outputs - if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) { - setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); - setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, - getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); - } + setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); + setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, + getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); + setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i)); + setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS, + getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/)); } } - // Ignore the delay to enable voice call on this target as the enabling the - // voice call has enough delay to make sure the ringtone audio completely - // played out - if (state == AudioSystem::MODE_IN_CALL && oldState == AudioSystem::MODE_RINGTONE) { - delayMs = 40; - } - // change routing is necessary setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); + //update device for all non-primary outputs + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t output = mOutputs.keyAt(i); + if (output != mPrimaryOutput) { + newDevice = getNewDevice(output, false /*fromCache*/); + setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + } + } + // if entering in call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() if (isStateInCall(state)) { ALOGV("setPhoneState() in call state management: new state is %d", state); - // unmute the ringing tone after a sufficient delay if it was muted before - // setting output device above - if (oldState == AudioSystem::MODE_RINGTONE) { - setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS); - } for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { handleIncallSonification(stream, true, true); } @@ -166,4 +580,1529 @@ void AudioPolicyManager::setPhoneState(int state) { } } -}; // namespace androidi_audio_legacy + +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 && + 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 && config != AudioSystem::FORCE_SPEAKER) { + 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 (size_t i = 0; i < mOutputs.size(); 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::getOutput(AudioSystem::stream_type stream, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + AudioSystem::output_flags flags) +{ + audio_io_handle_t output = 0; + uint32_t latency = 0; + routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); + audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); + ALOGV("getOutput() stream %d, samplingRate %d, format %d, channelMask %x, flags %x", + stream, samplingRate, format, channelMask, flags); + +#ifdef AUDIO_POLICY_TEST + if (mCurOutput != 0) { + ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d", + mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput); + + if (mTestOutputs[mCurOutput] == 0) { + ALOGV("getOutput() opening test output"); + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL); + outputDesc->mDevice = mTestDevice; + outputDesc->mSamplingRate = mTestSamplingRate; + outputDesc->mFormat = mTestFormat; + outputDesc->mChannelMask = mTestChannels; + outputDesc->mLatency = mTestLatencyMs; + outputDesc->mFlags = (audio_output_flags_t)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0); + outputDesc->mRefCount[stream] = 0; + mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannelMask, + &outputDesc->mLatency, + outputDesc->mFlags); + if (mTestOutputs[mCurOutput]) { + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"),mCurOutput); + mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString()); + addOutput(mTestOutputs[mCurOutput], outputDesc); + } + } + return mTestOutputs[mCurOutput]; + } +#endif //AUDIO_POLICY_TEST + + IOProfile *profile = getProfileForDirectOutput(device, + samplingRate, + format, + channelMask, + (audio_output_flags_t)flags); + + if (profile != NULL) { + AudioOutputDescriptor *outputDesc = NULL; + + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (!desc->isDuplicated() && (profile == desc->mProfile)) { + outputDesc = desc; + // reuse direct output if currently open and configured with same parameters + if ((samplingRate == outputDesc->mSamplingRate) && + (format == outputDesc->mFormat) && + (channelMask == outputDesc->mChannelMask)) { + outputDesc->mDirectOpenCount++; + ALOGV("getOutput() reusing direct output %d", output); + return mOutputs.keyAt(i); + } + } + } + // close direct output if currently open and configured with different parameters + if (outputDesc != NULL) { + closeOutput(outputDesc->mId); + } + outputDesc = new AudioOutputDescriptor(profile); + outputDesc->mDevice = device; + outputDesc->mSamplingRate = samplingRate; + outputDesc->mFormat = (audio_format_t)format; + outputDesc->mChannelMask = (audio_channel_mask_t)channelMask; + outputDesc->mLatency = 0; + outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);; + outputDesc->mRefCount[stream] = 0; + outputDesc->mStopTime[stream] = 0; + outputDesc->mDirectOpenCount = 1; + output = mpClientInterface->openOutput(profile->mModule->mHandle, + &outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannelMask, + &outputDesc->mLatency, + outputDesc->mFlags); + + // only accept an output with the requested parameters + if (output == 0 || + (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) || + (format != 0 && format != outputDesc->mFormat) || + (channelMask != 0 && channelMask != outputDesc->mChannelMask)) { + ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d," + "format %d %d, channelMask %04x %04x", output, samplingRate, + outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask, + outputDesc->mChannelMask); + if (output != 0) { + mpClientInterface->closeOutput(output); + } + delete outputDesc; + return 0; + } + addOutput(output, outputDesc); + mPreviousOutputs = mOutputs; + ALOGV("getOutput() returns new direct output %d", output); + return output; + } + + // ignoring channel mask due to downmix capability in mixer + + // open a non direct output + + // get which output is suitable for the specified stream. The actual routing change will happen + // when startOutput() will be called + SortedVector outputs = getOutputsForDevice(device, mOutputs); + + output = selectOutput(outputs, flags); + + ALOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d," + "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags); + + ALOGV("getOutput() returns output %d", output); + + return output; +} +status_t AudioPolicyManager::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) +{ + ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("startOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + + // increment usage count for this stream on the requested output: + // NOTE that the usage count is the same for duplicated output and hardware output which is + // necessary for a correct control of hardware output routing by startOutput() and stopOutput() + outputDesc->changeRefCount(stream, 1); + + if (outputDesc->mRefCount[stream] == 1) { + audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + routing_strategy strategy = getStrategy(stream); + bool shouldWait = (strategy == STRATEGY_SONIFICATION) || + (strategy == STRATEGY_SONIFICATION_RESPECTFUL); + uint32_t waitMs = 0; + uint32_t muteWaitMs = 0; + bool force = false; + for (size_t i = 0; i < mOutputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (desc != outputDesc) { + // force a device change if any other output is managed by the same hw + // module and has a current device selection that differs from selected device. + // In this case, the audio HAL must receive the new device selection so that it can + // change the device currently selected by the other active output. + if (outputDesc->sharesHwModuleWith(desc) && + desc->device() != newDevice) { + force = true; + } + // wait for audio on other active outputs to be presented when starting + // a notification so that audio focus effect can propagate. + uint32_t latency = desc->latency(); + if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) { + waitMs = latency; + } + } + } + +#ifdef QCOM_FM_ENABLED + if(stream == AudioSystem::FM && output == getA2dpOutput()) { + muteWaitMs = setOutputDevice(output, newDevice, true); + } else +#endif + { + muteWaitMs = setOutputDevice(output, newDevice, force); + } + + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, true, false); + } + + // apply volume rules for current stream and device if necessary + checkAndSetVolume(stream, + mStreams[stream].getVolumeIndex(newDevice), + output, + newDevice); + + // update the outputs if starting an output with a stream that can affect notification + // routing + handleNotificationRoutingForStream(stream); + if (waitMs > muteWaitMs) { + usleep((waitMs - muteWaitMs) * 2 * 1000); + } + } + return NO_ERROR; +} + +status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) +{ + ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + ALOGW("stopOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + + // handle special case for sonification while in call + if (isInCall()) { + handleIncallSonification(stream, false, false); + } + + if (outputDesc->mRefCount[stream] > 0) { + // decrement usage count of this stream on the output + outputDesc->changeRefCount(stream, -1); + // store time at which the stream was stopped - see isStreamActive() + if (outputDesc->mRefCount[stream] == 0) { + outputDesc->mStopTime[stream] = systemTime(); + audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + // delay the device switch by twice the latency because stopOutput() is executed when + // the track stop() command is received and at that time the audio track buffer can + // still contain data that needs to be drained. The latency only covers the audio HAL + // and kernel buffers. Also the latency does not always include additional delay in the + // audio path (audio DSP, CODEC ...) + setOutputDevice(output, newDevice, false, outputDesc->mLatency*2); + + // force restoring the device selection on other active outputs if it differs from the + // one being selected for this output + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_io_handle_t curOutput = mOutputs.keyAt(i); + AudioOutputDescriptor *desc = mOutputs.valueAt(i); + if (curOutput != output && + desc->isActive() && + outputDesc->sharesHwModuleWith(desc) && + newDevice != desc->device()) { + setOutputDevice(curOutput, + getNewDevice(curOutput, false /*fromCache*/), + true, + outputDesc->mLatency*2); + } + } + // update the outputs if stopping one with a stream that can affect notification routing + handleNotificationRoutingForStream(stream); + } + return NO_ERROR; + } else { + ALOGW("stopOutput() refcount is already 0 for output %d", output); + return INVALID_OPERATION; + } +} + + +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; + } + + // adapt channel selection to input source + switch(inputSource) { + case AUDIO_SOURCE_VOICE_UPLINK: + channelMask |= AudioSystem::CHANNEL_IN_VOICE_UPLINK; + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + channelMask |= AudioSystem::CHANNEL_IN_VOICE_DNLINK; + break; + case AUDIO_SOURCE_VOICE_CALL: + channelMask |= (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK); + break; + default: + break; + } + + 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; +} + +/* +Overwriting this function from base class to allow 2 acitve AudioRecord clients in case of FM. +One for FM A2DP playbck and other for FM recording. +*/ +status_t AudioPolicyManager::startInput(audio_io_handle_t input) +{ + ALOGV("startInput() input %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + ALOGW("startInput() unknow input %d", input); + return BAD_VALUE; + } + AudioInputDescriptor *inputDesc = mInputs.valueAt(index); + +/* +#ifdef AUDIO_POLICY_TEST + if (mTestInput == 0) +#endif //AUDIO_POLICY_TEST + { + // refuse 2 active AudioRecord clients at the same time + if (getActiveInput() != 0) { + ALOGW("startInput() input %d failed: other input already started", input); + return INVALID_OPERATION; + } + } +*/ + audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); + if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { + inputDesc->mDevice = newDevice; + } + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); + + param.addInt(String8(AudioParameter::keyInputSource), (int)inputDesc->mInputSource); + + // use Voice Recognition mode or not for this input based on input source + int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0; + param.addInt(String8("vr_mode"), vr_enabled); + ALOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled); + + //to pass on if camcorder mode is enabled to HAL + int camcorder_enabled = inputDesc->mInputSource == AUDIO_SOURCE_CAMCORDER ? 1 : 0; + param.addInt(String8("camcorder_mode"), camcorder_enabled); + + mpClientInterface->setParameters(input, param.toString()); + + inputDesc->mRefCount = 1; + return NO_ERROR; +} + +status_t AudioPolicyManager::stopInput(audio_io_handle_t input) +{ + ALOGV("stopInput() input %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + ALOGW("stopInput() unknow input %d", input); + return BAD_VALUE; + } + AudioInputDescriptor *inputDesc = mInputs.valueAt(index); + + if (inputDesc->mRefCount == 0) { + ALOGW("stopInput() input %d already stopped", input); + return INVALID_OPERATION; + } else { + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), 0); + mpClientInterface->setParameters(input, param.toString()); + setOutputDevice(mPrimaryOutput, getNewDevice(mPrimaryOutput, true), true); + inputDesc->mRefCount = 0; + return NO_ERROR; + } +} + + +status_t AudioPolicyManager::setStreamVolumeIndex(AudioSystem::stream_type stream, + int index, + audio_devices_t device) +{ + + if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) { + return BAD_VALUE; + } + if (!audio_is_output_device(device)) { + return BAD_VALUE; + } + + // Force max volume if stream cannot be muted + if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax; + + ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d", + stream, device, index); + + // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and + // clear all device specific values + if ((device == AUDIO_DEVICE_OUT_DEFAULT) && (AUDIO_DEVICE_OUT_DEFAULT != AUDIO_DEVICE_OUT_SPEAKER)) { + mStreams[stream].mIndexCur.clear(); + } + mStreams[stream].mIndexCur.add(device, index); + + // compute and apply stream volume on all outputs according to connected device + status_t status = NO_ERROR; + for (size_t i = 0; i < mOutputs.size(); i++) { + audio_devices_t curDevice = + getDeviceForVolume(mOutputs.valueAt(i)->device()); + if (device == curDevice) { + status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice); + if (volStatus != NO_ERROR) { + status = volStatus; + } + } + } + return status; +} + + +status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, + AudioSystem::device_connection_state state, + SortedVector& outputs) +{ + AudioOutputDescriptor *desc; + + if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { + // first list already open outputs that can be routed to this device + for (size_t i = 0; i < mOutputs.size(); i++) { + desc = mOutputs.valueAt(i); + if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) { + ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i)); + outputs.add(mOutputs.keyAt(i)); + } + } + // then look for output profiles that can be routed to this device + SortedVector profiles; + for (size_t i = 0; i < mHwModules.size(); i++) + { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) + { + if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) { + ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i); + profiles.add(mHwModules[i]->mOutputProfiles[j]); + } + } + } + + if (profiles.isEmpty() && outputs.isEmpty()) { + ALOGW("checkOutputsForDevice(): No output available for device %04x", device); + return BAD_VALUE; + } + + // open outputs for matching profiles if needed. Direct outputs are also opened to + // query for dynamic parameters and will be closed later by setDeviceConnectionState() + for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { + IOProfile *profile = profiles[profile_index]; + + // nothing to do if one output is already opened for this profile + size_t j; + for (j = 0; j < mOutputs.size(); j++) { + desc = mOutputs.valueAt(j); + if (!desc->isDuplicated() && desc->mProfile == profile) { + break; + } + } + if (j != mOutputs.size()) { + continue; + } + + ALOGV("opening output for device %08x", device); + desc = new AudioOutputDescriptor(profile); + desc->mDevice = device; + audio_io_handle_t output = 0; +#if QCOM_OUTPUT_FLAGS_ENABLED + if (!(desc->mFlags & AUDIO_OUTPUT_FLAG_LPA || desc->mFlags & AUDIO_OUTPUT_FLAG_TUNNEL || + desc->mFlags & AUDIO_OUTPUT_FLAG_VOIP_RX)) { +#endif + output = mpClientInterface->openOutput(profile->mModule->mHandle, + &desc->mDevice, + &desc->mSamplingRate, + &desc->mFormat, + &desc->mChannelMask, + &desc->mLatency, + desc->mFlags); +#ifdef QCOM_OUTPUT_FLAGS_ENABLED + } +#endif + if (output != 0) { + if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + String8 reply; + char *value; + if (profile->mSamplingRates[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); + ALOGV("checkOutputsForDevice() direct output sup sampling rates %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadSamplingRates(value, profile); + } + } + if (profile->mFormats[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); + ALOGV("checkOutputsForDevice() direct output sup formats %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadFormats(value, profile); + } + } + if (profile->mChannelMasks[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); + ALOGV("checkOutputsForDevice() direct output sup channel masks %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadOutChannels(value + 1, profile); + } + } + if (((profile->mSamplingRates[0] == 0) && + (profile->mSamplingRates.size() < 2)) || + ((profile->mFormats[0] == 0) && + (profile->mFormats.size() < 2)) || + ((profile->mFormats[0] == 0) && + (profile->mChannelMasks.size() < 2))) { + ALOGW("checkOutputsForDevice() direct output missing param"); + output = 0; + } else { + addOutput(output, desc); + } + } else { + audio_io_handle_t duplicatedOutput = 0; + // add output descriptor + addOutput(output, desc); + // set initial stream volume for device + applyStreamVolumes(output, device, 0, true); + + //TODO: configure audio effect output stage here + + // open a duplicating output thread for the new output and the primary output + duplicatedOutput = mpClientInterface->openDuplicateOutput(output, + mPrimaryOutput); + if (duplicatedOutput != 0) { + // add duplicated output descriptor + AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL); + dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); + dupOutputDesc->mOutput2 = mOutputs.valueFor(output); + dupOutputDesc->mSamplingRate = desc->mSamplingRate; + dupOutputDesc->mFormat = desc->mFormat; + dupOutputDesc->mChannelMask = desc->mChannelMask; + dupOutputDesc->mLatency = desc->mLatency; + addOutput(duplicatedOutput, dupOutputDesc); + applyStreamVolumes(duplicatedOutput, device, 0, true); + } else { + ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", + mPrimaryOutput, output); + mpClientInterface->closeOutput(output); + mOutputs.removeItem(output); + output = 0; + } + } + } + if (output == 0) { + ALOGW("checkOutputsForDevice() could not open output for device %x", device); + delete desc; + profiles.removeAt(profile_index); + profile_index--; + } else { + outputs.add(output); + ALOGV("checkOutputsForDevice(): adding output %d", output); + } + } + + if (profiles.isEmpty()) { + ALOGW("checkOutputsForDevice(): No output available for device %04x", device); + return BAD_VALUE; + } + } else { + // check if one opened output is not needed any more after disconnecting one device + for (size_t i = 0; i < mOutputs.size(); i++) { + desc = mOutputs.valueAt(i); + if (!desc->isDuplicated() && + !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) { + ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); + outputs.add(mOutputs.keyAt(i)); + } + } + for (size_t i = 0; i < mHwModules.size(); i++) + { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) + { + IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + if ((profile->mSupportedDevices & device) && + (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { + ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d", + j, i); + if (profile->mSamplingRates[0] == 0) { + profile->mSamplingRates.clear(); + profile->mSamplingRates.add(0); + } + if (profile->mFormats[0] == 0) { + profile->mFormats.clear(); + profile->mFormats.add((audio_format_t)0); + } + if (profile->mChannelMasks[0] == 0) { + profile->mChannelMasks.clear(); + profile->mChannelMasks.add((audio_channel_mask_t)0); + } + } + } + } + } + return NO_ERROR; +} + +audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache) +{ + audio_devices_t device = AUDIO_DEVICE_NONE; + + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + AudioOutputDescriptor *primaryOutputDesc = mOutputs.valueFor(mPrimaryOutput); + // check the following by order of priority to request a routing change if necessary: + // 1: the strategy enforced audible is active on the output: + // use device for strategy enforced audible + // 2: we are in call or the strategy phone is active on the output: + // use device for strategy phone + // 3: the strategy sonification is active on the output: + // use device for strategy sonification + // 4: the strategy "respectful" sonification is active on the output: + // use device for strategy "respectful" sonification + // 5: the strategy media is active on the output: + // use device for strategy media + // 6: the strategy DTMF is active on the output: + // use device for strategy DTMF + if ((primaryOutputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE))) { + device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); + } else if (isInCall() || + (primaryOutputDesc->isStrategyActive(STRATEGY_PHONE))) { + device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)){ + device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) { + device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) { + device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); + } + + ALOGV("getNewDevice() selected device %x", device); + return device; +} + +AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy( + AudioSystem::stream_type stream) { + // stream to strategy mapping + switch (stream) { + case AudioSystem::VOICE_CALL: + case AudioSystem::BLUETOOTH_SCO: + return STRATEGY_PHONE; + case AudioSystem::RING: + case AudioSystem::ALARM: + return STRATEGY_SONIFICATION; + case AudioSystem::NOTIFICATION: + return STRATEGY_SONIFICATION_RESPECTFUL; + case AudioSystem::DTMF: + return STRATEGY_DTMF; + default: + ALOGE("unknown stream type"); + case AudioSystem::SYSTEM: + // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs + // while key clicks are played produces a poor result + case AudioSystem::TTS: + case AudioSystem::MUSIC: +#ifdef QCOM_FM_ENABLED + case AudioSystem::FM: +#endif + return STRATEGY_MEDIA; + case AudioSystem::ENFORCED_AUDIBLE: + return STRATEGY_ENFORCED_AUDIBLE; + } +} +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 (!isInCall()) + { + if ((mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + !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; +#ifdef QCOM_ANC_HEADSET_ENABLED + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADPHONE; + if (device) break; + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADSET; + if (device) break; +#endif + 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_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 (!isInCall() && + (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + !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; + } +#ifdef QCOM_FM_ENABLED + if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) { + if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) { + device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADSET); + device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADPHONE); + device &= ~(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET); + 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 (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_SPEAKER) { + if (strategy != STRATEGY_SONIFICATION) { + // no sonification on remote submix (e.g. WFD) + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } + if ((device2 == AUDIO_DEVICE_NONE) && + (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) && + !mA2dpSuspended) { + if (device2 == AUDIO_DEVICE_NONE) { + 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; + } +#ifdef QCOM_ANC_HEADSET_ENABLED + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADPHONE; + } + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADSET; + } +#endif + 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) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + } +#ifdef QCOM_FM_ENABLED + if (device2 == AUDIO_DEVICE_NONE) { + device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX; + } +#endif +#ifdef QCOM_PROXY_DEVICE_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) { + device = mDefaultOutputDevice; + } + if (device == AUDIO_DEVICE_NONE) { + ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); + } + + } else { + //AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA + device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER; + } + + if (isInCall()) { + // when in call, get the device for Phone strategy + device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/); + } + + } break; + + default: + ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy); + break; + } + + ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device); + return device; +} + +uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, + audio_devices_t device, + bool force, + int delayMs) + +{ + ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs); + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + AudioParameter param; + uint32_t muteWaitMs = 0; + + if (outputDesc->isDuplicated()) { + muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); + muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); + return muteWaitMs; + } + // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current + // output profile + if ((device != AUDIO_DEVICE_NONE) && + ((device & outputDesc->mProfile->mSupportedDevices) == 0)) { + return 0; + } + + // filter devices according to output selected + device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices); + + audio_devices_t prevDevice = outputDesc->mDevice; + + ALOGV("setOutputDevice() prevDevice %04x", prevDevice); + + if (device != AUDIO_DEVICE_NONE) { + outputDesc->mDevice = device; + } + muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs); + + // Do not change the routing if: + // - the requested device is AUDIO_DEVICE_NONE + // - the requested device is the same as current device and force is not specified. + // Doing this check here allows the caller to call setOutputDevice() without conditions + if ((device == AUDIO_DEVICE_NONE) || ((device == prevDevice) && !force)) { + ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output); + return muteWaitMs; + } + if (device == prevDevice) { + ALOGV("setOutputDevice() Call routing with same device with zero delay "); + delayMs = 0; + } + ALOGV("setOutputDevice() changing device:%x",device); + // do the routing + param.addInt(String8(AudioParameter::keyRouting), (int)device); + mpClientInterface->setParameters(output, param.toString(), delayMs); + + // update stream volumes according to new device + applyStreamVolumes(output, device, delayMs); + + + return muteWaitMs; +} + +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: + 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; +#ifdef QCOM_ANC_HEADSET_ENABLED + } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANC_HEADSET) { + device = AUDIO_DEVICE_IN_ANC_HEADSET; +#endif + } 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_VOICE_COMMUNICATION: + device = AUDIO_DEVICE_IN_COMMUNICATION; + break; + case AUDIO_SOURCE_CAMCORDER: + if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) { + device = AUDIO_DEVICE_IN_BACK_MIC; + } else if (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_AUX_DIGITAL) { + device = AUDIO_DEVICE_IN_AUX_DIGITAL; + } 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 QCOM_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; +} + + + + +audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device) +{ + if (device == AUDIO_DEVICE_NONE) { + // this happens when forcing a route update and no track is active on an output. + // In this case the returned category is not important. + device = AUDIO_DEVICE_OUT_SPEAKER; + } else if (AudioSystem::popCount(device) > 1) { + // Multiple device selection is either: + // - speaker + one other device: give priority to speaker in this case. + // - one A2DP device + another device: happens with duplicated output. In this case + // retain the device on the A2DP output as the other must not correspond to an active + // selection if not the speaker. + if (device & AUDIO_DEVICE_OUT_SPEAKER) { + device = AUDIO_DEVICE_OUT_SPEAKER; + } else if ((device & AUDIO_DEVICE_OUT_WIRED_HEADSET) != 0) { + device = AUDIO_DEVICE_OUT_WIRED_HEADSET; + } else if ((device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) != 0) { + device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + } else { + device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP); + } + } + + ALOGW_IF(AudioSystem::popCount(device) != 1, + "getDeviceForVolume() invalid device combination: %08x", + device); + + return device; +} + +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: +#ifdef QCOM_ANC_HEADSET_ENABLED + case AUDIO_DEVICE_OUT_ANC_HEADSET: + case AUDIO_DEVICE_OUT_ANC_HEADPHONE: +#endif + 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 QCOM_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 QCOM_PROXY_DEVICE_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) +{ + // 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] || +#ifdef QCOM_FM_ENABLED + (stream == AudioSystem::FM) || +#endif + force) { + mOutputs.valueFor(output)->mCurVolume[stream] = volume; + ALOGVV("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 QCOM_FM_ENABLED + } else if (stream == AudioSystem::FM) { + float fmVolume = -1.0; + fmVolume = computeVolume(stream, index, output, device); + if (fmVolume >= 0) { + if(output == mPrimaryOutput) + mpClientInterface->setFmVolume(fmVolume, delayMs); + else if(mHasA2dp && output == getA2dpOutput()) + mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); + } + return NO_ERROR; +#endif + } + mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); + } + + if (stream == AudioSystem::VOICE_CALL || + stream == AudioSystem::BLUETOOTH_SCO) { + float voiceVolume; + // Force voice volume to max for bluetooth SCO as volume is managed by the headset + if (stream == AudioSystem::VOICE_CALL) { + voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; + } else { + voiceVolume = 1.0; + } + + 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; +} + + +void AudioPolicyManager::checkA2dpSuspend() +{ + + // suspend A2DP output if: + // (NOT already suspended) && + // ((SCO device is connected && + // (forced usage for communication || for record is SCO))) || + // (phone state is ringing || in call) + // + // restore A2DP output if: + // (Already suspended) && + // ((SCO device is NOT connected || + // (forced usage NOT for communication && NOT for record is SCO))) && + // (phone state is NOT ringing && NOT in call) + // + if (mA2dpSuspended) { + if (((mScoDeviceAddress == "") || + ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) && + (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) || + ((mPhoneState != AudioSystem::MODE_IN_CALL) && + (mPhoneState != AudioSystem::MODE_RINGTONE))) { + + mA2dpSuspended = false; + } + } else { + if (((mScoDeviceAddress != "") && + ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || + (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) && + ((mPhoneState == AudioSystem::MODE_IN_CALL) || + (mPhoneState == AudioSystem::MODE_RINGTONE))) { + + mA2dpSuspended = true; + } + } +} + +audio_io_handle_t AudioPolicyManager::getA2dpOutput() +{ + return 0; +} + +//private function, no changes from AudioPolicyManagerBase +void AudioPolicyManager::handleNotificationRoutingForStream(AudioSystem::stream_type stream) { + switch(stream) { + case AudioSystem::MUSIC: + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + updateDevicesAndOutputs(); + break; + default: + break; + } +} + + +AudioPolicyManagerBase::IOProfile *AudioPolicyManager::getProfileForDirectOutput( + audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags) +{ +#ifdef QCOM_OUTPUT_FLAGS_ENABLED + if( !((flags & AUDIO_OUTPUT_FLAG_LPA) || + (flags & AUDIO_OUTPUT_FLAG_TUNNEL)|| + (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)) ) + flags = AUDIO_OUTPUT_FLAG_DIRECT; +#endif + for (size_t i = 0; i < mHwModules.size(); i++) { + if (mHwModules[i]->mHandle == 0) { + continue; + } + for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { + AudioPolicyManagerBase::IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + if (isCompatibleProfile(profile, device, samplingRate, format, + channelMask, + flags)) { + if (mAvailableOutputDevices & profile->mSupportedDevices) { + return mHwModules[i]->mOutputProfiles[j]; + } + } + } + } + return 0; +} + +bool AudioPolicyManager::isCompatibleProfile(AudioPolicyManagerBase::IOProfile *profile, + audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags) +{ + if ((profile->mSupportedDevices & device) != device) { + return false; + } + if (profile->mFlags != flags) { + return false; + } + if (samplingRate != 0) { + size_t i; + for (i = 0; i < profile->mSamplingRates.size(); i++) + { + if (profile->mSamplingRates[i] == samplingRate) { + break; + } + } + if (i == profile->mSamplingRates.size()) { + return false; + } + } + if (format != 0) { + size_t i; + for (i = 0; i < profile->mFormats.size(); i++) + { + if (profile->mFormats[i] == format) { + break; + } + } + if (i == profile->mFormats.size()) { + return false; + } + } + if (channelMask != 0) { + size_t i; + for (i = 0; i < profile->mChannelMasks.size(); i++) + { + if (profile->mChannelMasks[i] == channelMask) { + break; + } + } + if (i == profile->mChannelMasks.size()) { + return false; + } + } + ALOGD(" profile found: device %x, flags %x, samplingrate %d,\ + format %x, channelMask %d", + device, flags, samplingRate, format, channelMask); + return true; +} + +bool AudioPolicyManager::platform_is_Fusion3() +{ + char platform[128], baseband[128]; + property_get("ro.board.platform", platform, ""); + property_get("ro.baseband", baseband, ""); + if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) + return true; + else + return false; +} + +extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) +{ + return new AudioPolicyManager(clientInterface); +} + +extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) +{ + delete interface; +} + + +}; // namespace android diff --git a/legacy/alsa_sound/AudioPolicyManagerALSA.h b/legacy/alsa_sound/AudioPolicyManagerALSA.h index 91b7e1392..b6427c00e 100644 --- a/legacy/alsa_sound/AudioPolicyManagerALSA.h +++ b/legacy/alsa_sound/AudioPolicyManagerALSA.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (C) 2011-2012, Code Aurora Forum. All rights reserved. + * 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. @@ -35,9 +36,126 @@ public: AudioPolicyManager(AudioPolicyClientInterface *clientInterface) : AudioPolicyManagerBase(clientInterface) {} + virtual ~AudioPolicyManager() {} + + // AudioPolicyInterface + virtual status_t setDeviceConnectionState(audio_devices_t device, + AudioSystem::device_connection_state state, + const char *device_address); + uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc, + audio_devices_t prevDevice, + uint32_t delayMs); + virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device, + const char *device_address); virtual void setPhoneState(int state); + virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); + virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, + uint32_t samplingRate = 0, + uint32_t format = AudioSystem::FORMAT_DEFAULT, + uint32_t channels = 0, + AudioSystem::output_flags flags = + AudioSystem::OUTPUT_FLAG_INDIRECT); + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual void releaseOutput(audio_io_handle_t output); + virtual audio_io_handle_t getInput(int inputSource, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::audio_in_acoustics acoustics); - virtual ~AudioPolicyManager() {} + // indicates to the audio policy manager that the input starts being used. + virtual status_t startInput(audio_io_handle_t input); + + // indicates to the audio policy manager that the input stops being used. + virtual status_t stopInput(audio_io_handle_t input); + virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, + int index, + audio_devices_t device); +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); + + // change the route of the specified output. Returns the number of ms we have slept to + // allow new routing to take effect in certain cases. + uint32_t setOutputDevice(audio_io_handle_t output, + audio_devices_t device, + bool force = false, + int delayMs = 0); + + // select input device corresponding to requested audio source + virtual audio_devices_t getDeviceForInputSource(int inputSource); + + // 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); + + + // when a device is connected, checks if an open output can be routed + // to this device. If none is open, tries to open one of the available outputs. + // Returns an output suitable to this device or 0. + // when a device is disconnected, checks if an output is not used any more and + // returns its handle if any. + // transfers the audio tracks and effects from one output thread to another accordingly. + status_t checkOutputsForDevice(audio_devices_t device, + AudioSystem::device_connection_state state, + SortedVector& outputs); + // manages A2DP output suspend/restore according to phone state and BT SCO usage + void checkA2dpSuspend(); + + // returns the A2DP output handle if it is open or 0 otherwise + audio_io_handle_t getA2dpOutput(); + + virtual AudioPolicyManagerBase::IOProfile* getProfileForDirectOutput( + audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags); + bool isCompatibleProfile(AudioPolicyManagerBase::IOProfile *profile, + audio_devices_t device, + uint32_t samplingRate, + uint32_t format, + uint32_t channelMask, + audio_output_flags_t flags); + // selects the most appropriate device on output for current state + // must be called every time a condition that affects the device choice for a given output is + // changed: connected device, phone state, force use, output start, output stop.. + // see getDeviceForStrategy() for the use of fromCache parameter + + audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache); + + + // returns the category the device belongs to with regard to volume curve management + static device_category getDeviceCategory(audio_devices_t device); + + // extract one device relevant for volume control from multiple device selection + static audio_devices_t getDeviceForVolume(audio_devices_t device); + // true is current platform implements a back microphone + virtual bool hasBackMicrophone() const { return false; } + // true is current platform supports suplication of notifications and ringtones over A2DP output + virtual bool a2dpUsedForSonification() const { return true; } + +private: + void handleNotificationRoutingForStream(AudioSystem::stream_type stream); + bool platform_is_Fusion3(); }; }; diff --git a/legacy/alsa_sound/AudioSessionOut.cpp b/legacy/alsa_sound/AudioSessionOut.cpp new file mode 100644 index 000000000..3b0e2f30f --- /dev/null +++ b/legacy/alsa_sound/AudioSessionOut.cpp @@ -0,0 +1,1091 @@ +/* AudioSessionOutALSA.cpp + ** + ** Copyright 2008-2009 Wind River Systems + ** 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 +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "AudioSessionOutALSA" +#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "AudioHardwareALSA.h" + +namespace sys_write { + ssize_t lib_write(int fd, const void *buf, size_t count) { + return write(fd, buf, count); + } +}; +namespace android_audio_legacy +{ +#define LPA_MODE 0 +#define TUNNEL_MODE 1 +#define NUM_FDS 2 +#define KILL_EVENT_THREAD 1 +#define BUFFER_COUNT 4 +#define LPA_BUFFER_SIZE 256*1024 +#define TUNNEL_BUFFER_SIZE 240*1024 +#define TUNNEL_METADATA_SIZE 64 +#define MONO_CHANNEL_MODE 1 +// ---------------------------------------------------------------------------- + +AudioSessionOutALSA::AudioSessionOutALSA(AudioHardwareALSA *parent, + uint32_t devices, + int format, + uint32_t channels, + uint32_t samplingRate, + int type, + status_t *status) +{ + + alsa_handle_t alsa_handle; + char *use_case; + bool bIsUseCaseSet = false; + + Mutex::Autolock autoLock(mLock); + // Default initilization + mParent = parent; + mAlsaDevice = mParent->mALSADevice; + mUcMgr = mParent->mUcMgr; + mFormat = format; + mSampleRate = samplingRate; + mChannels = channels; + + + mBufferSize = 0; + *status = BAD_VALUE; + + mPaused = false; + mSeeking = false; + mReachedEOS = false; + mSkipWrite = false; + + mAlsaHandle = NULL; + mUseCase = AudioHardwareALSA::USECASE_NONE; + + mInputBufferSize = type ? TUNNEL_BUFFER_SIZE : LPA_BUFFER_SIZE; + mInputBufferCount = BUFFER_COUNT; + mEfd = -1; + mEosEventReceived = false; + mEventThread = NULL; + mEventThreadAlive = false; + mKillEventThread = false; + mObserver = NULL; + mOutputMetadataLength = 0; + mSkipEOS = false; + mTunnelMode = false; + + if(devices == 0) { + ALOGE("No output device specified"); + return; + } + if((format == AUDIO_FORMAT_PCM_16_BIT) && (channels == 0 || channels > 6)) { + ALOGE("Invalid number of channels %d", channels); + return; + } + + if(mParent->isExtOutDevice(devices)) { + ALOGE("Set Capture from proxy true"); + mParent->mRouteAudioToExtOut = true; + if(mParent->mExtOutStream == NULL) { + mParent->switchExtOut(devices); + } + } + + //open device based on the type (LPA or Tunnel) and devices + //TODO: Check format type for linear vs non-linear to determine LPA/Tunnel + *status = openAudioSessionDevice(type, devices); + + if (*status != NO_ERROR) { + ALOGE("Failed to open LPA/Tunnel Session"); + return; + } + //Creates the event thread to poll events from LPA/Compress Driver + createEventThread(); + + mUseCase = mParent->useCaseStringToEnum(mAlsaHandle->useCase); + ALOGV("mParent->mRouteAudioToExtOut = %d", mParent->mRouteAudioToExtOut); + if (mParent->mRouteAudioToExtOut) { + status_t err = NO_ERROR; + err = mParent->startPlaybackOnExtOut_l(mUseCase); + *status = err; + } + + *status = NO_ERROR; +} + +AudioSessionOutALSA::~AudioSessionOutALSA() +{ + ALOGD("~AudioSessionOutALSA"); + mSkipWrite = true; + + mWriteCv.signal(); + // trying to acquire mDecoderLock, make sure that, the waiting decoder thread + // receives the signal before the conditional variable "mWriteCv" is + // destroyed in ~AudioSessionOut(). Decoder thread acquires this lock + // before it waits for the signal. + Mutex::Autolock autoDecoderLock(mDecoderLock); + //TODO: This might need to be Locked using Parent lock + reset(); + if (mParent->mRouteAudioToExtOut) { + status_t err = mParent->stopPlaybackOnExtOut_l(mUseCase); + if(err){ + ALOGE("stopPlaybackOnExtOut_l return err %d", err); + } + } +} + +status_t AudioSessionOutALSA::setVolume(float left, float right) +{ + Mutex::Autolock autoLock(mLock); + float volume; + status_t status = NO_ERROR; + + volume = (left + right) / 2; + if (volume < 0.0) { + ALOGW("AudioSessionOutALSA::setVolume(%f) under 0.0, assuming 0.0\n", volume); + volume = 0.0; + } else if (volume > 1.0) { + ALOGW("AudioSessionOutALSA::setVolume(%f) over 1.0, assuming 1.0\n", volume); + volume = 1.0; + } + mStreamVol = (lrint((left * 0x2000)+0.5)) << 16 | (lrint((right * 0x2000)+0.5)); + + ALOGV("Setting stream volume to %d (available range is 0 to 0x2000)\n", mStreamVol); + if(mAlsaHandle) { + if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) || + !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) { + ALOGD("setLpaVolume(%u)\n", mStreamVol); + ALOGD("Setting LPA volume to %d (available range is 0 to 100)\n", mStreamVol); + mAlsaHandle->module->setLpaVolume(mStreamVol); + return status; + } + else if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) || + !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) { + ALOGD("setCompressedVolume(%u)\n", mStreamVol); + ALOGD("Setting Compressed volume to %d (available range is 0 to 100)\n", mStreamVol); + mAlsaHandle->module->setCompressedVolume(mStreamVol); + return status; + } + } + return INVALID_OPERATION; +} + + +status_t AudioSessionOutALSA::openAudioSessionDevice(int type, int devices) +{ + char* use_case; + status_t status = NO_ERROR; + //1.) Based on the current device and session type (LPA/Tunnel), open a device + // with verb or modifier + snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case); + if (type == LPA_MODE) { + if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, + strlen(SND_USE_CASE_VERB_INACTIVE)))) { + status = openDevice(SND_USE_CASE_VERB_HIFI_LOW_POWER, true, devices); + } else { + status = openDevice(SND_USE_CASE_MOD_PLAY_LPA, false, devices); + } + } else if (type == TUNNEL_MODE) { + if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, + strlen(SND_USE_CASE_VERB_INACTIVE)))) { + status = openDevice(SND_USE_CASE_VERB_HIFI_TUNNEL, true, devices); + } else { + status = openDevice(SND_USE_CASE_MOD_PLAY_TUNNEL, false, devices); + } + mTunnelMode = true; + } + + mOutputMetadataLength = sizeof(output_metadata_handle_t); + ALOGD("openAudioSessionDevice - mOutputMetadataLength = %d", mOutputMetadataLength); + + if(use_case) { + free(use_case); + use_case = NULL; + } + if(status != NO_ERROR) { + return status; + } + + //2.) Get the device handle + ALSAHandleList::iterator it = mParent->mDeviceList.end(); + it--; + + mAlsaHandle = &(*it); + ALOGV("mAlsaHandle %p, mAlsaHandle->useCase %s",mAlsaHandle, mAlsaHandle->useCase); + + //3.) mmap the buffers for playback + status_t err = mmap_buffer(mAlsaHandle->handle); + if(err) { + ALOGE("MMAP buffer failed - playback err = %d", err); + return err; + } + ALOGV("buffer pointer %p ", mAlsaHandle->handle->addr); + + //Set Meta data mode + if (type == LPA_MODE) { + status = setMetaDataMode(); + if(status != NO_ERROR) { + return status; + } + } + + //4.) prepare the driver for playback and allocate the buffers + status = pcm_prepare(mAlsaHandle->handle); + if (status) { + ALOGE("PCM Prepare failed - playback err = %d", err); + return status; + } + bufferAlloc(mAlsaHandle); + mBufferSize = mAlsaHandle->periodSize; + return NO_ERROR; +} + +ssize_t AudioSessionOutALSA::write(const void *buffer, size_t bytes) +{ + Mutex::Autolock autoLock(mLock); + int err = 0; + + ALOGV("write Empty Queue size() = %d, Filled Queue size() = %d " + "mReached EOS %d, mEosEventReceived %d bytes %d", + mEmptyQueue.size(),mFilledQueue.size(), mReachedEOS, mEosEventReceived, bytes); + + mEosEventReceived = false; + mReachedEOS = false; + + if (!bytes) { + mReachedEOS = true; + } + + //1.) Dequeue the buffer from empty buffer queue. Copy the data to be + // written into the buffer. Then Enqueue the buffer to the filled + // buffer queue + + if (mSkipWrite) { + LOG_ALWAYS_FATAL_IF((mEmptyQueue.size() != BUFFER_COUNT), + "::write, mSkipwrite is true but empty queue isnt full"); + ALOGD("reset mSkipWrite in write"); + mSkipWrite = false; + ALOGD("mSkipWrite is false now write bytes %d", bytes); + ALOGD("skipping buffer in write"); + return 0; + } + + ALOGV("not skipping buffer in write since mSkipWrite = %d, " + "mEmptyQueuesize %d ", mSkipWrite, mEmptyQueue.size()); + + List::iterator it = mEmptyQueue.begin(); + BuffersAllocated buf = *it; + + mEmptyQueue.erase(it); + + updateMetaData(bytes); + + memcpy(buf.memBuf, &mOutputMetadataTunnel, mOutputMetadataLength); + ALOGD("buf.memBuf =%x , Copy Metadata = %d, bytes = %d", buf.memBuf,mOutputMetadataLength, bytes); + + if (bytes == 0) { + buf.bytesToWrite = 0; + err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size); + + //bad part is !err does not guarantee pcm_write succeeded! + if (!err) { //mReachedEOS is already set + /* + * This workaround is needed to ensure EOS from the event thread + * is posted when the first (only) buffer given to the driver + * is a zero length buffer. Note that the compressed driver + * does not interrupt the timer fd if the EOS buffer was queued + * after a buffer with valid data (full or partial). So we + * only need to do this in this special case. + */ + if (mFilledQueue.empty()) { + mFilledQueue.push_back(buf); + } + } + + return err; + } + ALOGV("PCM write before memcpy start"); + memcpy((buf.memBuf + mOutputMetadataLength), buffer, bytes); + + buf.bytesToWrite = bytes; + + //2.) Write the buffer to the Driver + ALOGV("PCM write start"); + err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size); + ALOGV("PCM write complete"); + if (bytes < (mAlsaHandle->handle->period_size - mOutputMetadataLength)) { + ALOGV("Last buffer case %d", mAlsaHandle->handle->start); + if(!mAlsaHandle->handle->start) { + if ( ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START) < 0 ) { + ALOGE("Audio Start failed"); + } else { + mAlsaHandle->handle->start = 1; + } + } + + if (!mTunnelMode) mReachedEOS = true; + } + int32_t * Buf = (int32_t *) buf.memBuf; + ALOGD(" buf.memBuf [0] = %x , buf.memBuf [1] = %x", Buf[0], Buf[1]); + mFilledQueue.push_back(buf); + return err; +} + +void AudioSessionOutALSA::bufferAlloc(alsa_handle_t *handle) { + void *mem_buf = NULL; + int i = 0; + + int32_t nSize = mAlsaHandle->handle->period_size; + ALOGV("number of input buffers = %d", mInputBufferCount); + ALOGV("memBufferAlloc calling with required size %d", nSize); + for (i = 0; i < mInputBufferCount; i++) { + mem_buf = (int32_t *)mAlsaHandle->handle->addr + (nSize * i/sizeof(int)); + ALOGV("Buffer pointer %p ", mem_buf); + BuffersAllocated buf(mem_buf, nSize); + memset(buf.memBuf, 0x0, nSize); + mEmptyQueue.push_back(buf); + mBufPool.push_back(buf); + ALOGV("The MEM that is allocated - buffer is %x",\ + (unsigned int)mem_buf); + } +} + +void AudioSessionOutALSA::bufferDeAlloc() { + while (!mBufPool.empty()) { + List::iterator it = mBufPool.begin(); + ALOGV("Removing input buffer from Buffer Pool "); + mBufPool.erase(it); + } +} + +void AudioSessionOutALSA::requestAndWaitForEventThreadExit() { + if (!mEventThreadAlive) + return; + mKillEventThread = true; + if(mEfd != -1) { + ALOGE("Writing to mEfd %d",mEfd); + uint64_t writeValue = KILL_EVENT_THREAD; + sys_write::lib_write(mEfd, &writeValue, sizeof(uint64_t)); + } + pthread_join(mEventThread,NULL); + ALOGV("event thread killed"); +} + +void * AudioSessionOutALSA::eventThreadWrapper(void *me) { + static_cast(me)->eventThreadEntry(); + return NULL; +} + +void AudioSessionOutALSA::eventThreadEntry() { + //1.) Initialize the variables required for polling events + int rc = 0; + int err_poll = 0; + int avail = 0; + int i = 0; + struct pollfd pfd[NUM_FDS]; + int timeout = -1; + + //2.) Set the priority for the event thread + pid_t tid = gettid(); + androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO); + prctl(PR_SET_NAME, (unsigned long)"HAL Audio EventThread", 0, 0, 0); + + //3.) Allocate two FDs for polling. + // 1st FD: Polling on the Driver's timer_fd. This is used for getting write done + // events from the driver + // 2nd FD: Polling on a local fd so we can interrup the event thread locally + // when playback is stopped from Apps + // The event thread will when a write is performed on one of these FDs + ALOGV("Allocating poll fd"); + if(!mKillEventThread) { + pfd[0].fd = mAlsaHandle->handle->timer_fd; + pfd[0].events = (POLLIN | POLLERR | POLLNVAL); + mEfd = eventfd(0,0); + pfd[1].fd = mEfd; + pfd[1].events = (POLLIN | POLLERR | POLLNVAL); + } + + //4.) Start a poll for write done events from driver. + while(!mKillEventThread && ((err_poll = poll(pfd, NUM_FDS, timeout)) >=0)) { + ALOGV("pfd[0].revents =%d ", pfd[0].revents); + ALOGV("pfd[1].revents =%d ", pfd[1].revents); + // Handle Poll errors + if (err_poll == EINTR) + ALOGE("Timer is intrrupted"); + if ((pfd[1].revents & POLLERR) || (pfd[1].revents & POLLNVAL)) { + pfd[1].revents = 0; + ALOGE("POLLERR or INVALID POLL"); + } + + //POLLIN event on 2nd FD. Kill from event thread + if (pfd[1].revents & POLLIN) { + uint64_t u; + read(mEfd, &u, sizeof(uint64_t)); + ALOGV("POLLIN event occured on the event fd, value written to %llu", + (unsigned long long)u); + pfd[1].revents = 0; + if (u == KILL_EVENT_THREAD) { + continue; + } + } + + //Poll error on Driver's timer fd + if((pfd[0].revents & POLLERR) || (pfd[0].revents & POLLNVAL)) { + pfd[0].revents = 0; + continue; + } + + //Pollin event on Driver's timer fd + if (pfd[0].revents & POLLIN && !mKillEventThread) { + struct snd_timer_tread rbuf[4]; + ALOGV("mAlsaHandle->handle = %p", mAlsaHandle->handle); + if( !mAlsaHandle->handle ) { + ALOGD(" mAlsaHandle->handle is NULL, breaking from while loop in eventthread"); + pfd[0].revents = 0; + break; + } + read(mAlsaHandle->handle->timer_fd, rbuf, sizeof(struct snd_timer_tread) * 4 ); + pfd[0].revents = 0; + ALOGV("After an event occurs"); + + { + Mutex::Autolock _l(mLock); + if (mFilledQueue.empty()) { + ALOGV("Filled queue is empty"); //only time this would be valid is after a flush? + continue; + } + // Transfer a buffer that was consumed by the driver from filled queue + // to empty queue + + BuffersAllocated buf = *(mFilledQueue.begin()); + mFilledQueue.erase(mFilledQueue.begin()); + ALOGV("mFilledQueue %d", mFilledQueue.size()); + + mEmptyQueue.push_back(buf); + mWriteCv.signal(); + ALOGV("Reset mSkipwrite in eventthread entry"); + mSkipWrite = false; + + //Post EOS in case the filled queue is empty and EOS is reached. + if (mFilledQueue.empty() && mReachedEOS) { + drainAndPostEOS_l(); + } + } + } + } + + //5.) Close mEfd that was created + mEventThreadAlive = false; + if (mEfd != -1) { + close(mEfd); + mEfd = -1; + } + ALOGV("Event Thread is dying."); + return; + +} + +void AudioSessionOutALSA::createEventThread() { + ALOGV("Creating Event Thread"); + mKillEventThread = false; + mEventThreadAlive = true; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_create(&mEventThread, &attr, eventThreadWrapper, this); + ALOGV("Event Thread created"); +} + +status_t AudioSessionOutALSA::start() +{ + Mutex::Autolock autoLock(mLock); + ALOGV("AudioSessionOutALSA start()"); + //we should not reset EOS here, since EOS could have been + //marked in write, the only place to clear EOS should + //be flush + //mEosEventReceived = false; + //mReachedEOS = false; + //mSkipEOS = false; + if (mPaused) { + ALOGV("AudioSessionOutALSA ::start mPaused true"); + status_t err = NO_ERROR; + if (mSeeking) { + ALOGV("AudioSessionOutALSA ::start before drain"); + drain(); + ALOGV("AudioSessionOutALSA ::start after drain"); + mSeeking = false; + } else { + ALOGV("AudioSessionOutALSA ::start before resume"); + if (resume_l() == UNKNOWN_ERROR) { + ALOGV("AudioSessionOutALSA ::start after resume error"); + return UNKNOWN_ERROR; + } + } + mPaused = false; + } else if (!mAlsaHandle->handle->start) { + //Signal the driver to start rendering data + ALOGV("AudioSessionOutALSA ::start calling _ioctl_start"); + if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START)) { + ALOGE("start:SNDRV_PCM_IOCTL_START failed\n"); + return UNKNOWN_ERROR; + } + mAlsaHandle->handle->start = 1; + } + ALOGV("AudioSessionOutALSA ::start done"); + return NO_ERROR; +} + +status_t AudioSessionOutALSA::pause() +{ + Mutex::Autolock autoLock(mLock); + status_t err = NO_ERROR; + ALOGD("Pausing the driver"); + //Signal the driver to pause rendering data + if (pause_l() == UNKNOWN_ERROR) { + return UNKNOWN_ERROR; + } + mPaused = true; + + if(err) { + ALOGE("pause returned error"); + return err; + } + return err; + +} + +status_t AudioSessionOutALSA::pause_l() +{ + if (!mPaused) { + if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1) < 0) { + ALOGE("PAUSE failed on use case %s", mAlsaHandle->useCase); + return UNKNOWN_ERROR; + } + } + return NO_ERROR; +} + +status_t AudioSessionOutALSA::resume_l() +{ + status_t err = NO_ERROR; + if (mPaused) { + if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,0) < 0) { + ALOGE("Resume failed on use case %s", mAlsaHandle->useCase); + return UNKNOWN_ERROR; + } + } + return NO_ERROR; +} + +status_t AudioSessionOutALSA::drain() +{ + mAlsaHandle->handle->start = 0; + int err = pcm_prepare(mAlsaHandle->handle); + if(err != OK) { + ALOGE("pcm_prepare -seek = %d",err); + //Posting EOS + if (mObserver) + mObserver->postEOS(0); + return UNKNOWN_ERROR; + } + + ALOGV("drain Empty Queue size() = %d, Filled Queue size() = %d ", + mEmptyQueue.size(), mFilledQueue.size()); + + mAlsaHandle->handle->sync_ptr->flags = + SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN; + sync_ptr(mAlsaHandle->handle); + ALOGV("appl_ptr=%d",(int)mAlsaHandle->handle->sync_ptr->c.control.appl_ptr); + return NO_ERROR; +} + +status_t AudioSessionOutALSA::flush() +{ + Mutex::Autolock autoLock(mLock); + ALOGV("AudioSessionOutALSA flush"); + int err; + { + // 1.) Clear the Empty and Filled buffer queue + mEmptyQueue.clear(); + mFilledQueue.clear(); + + // 2.) Add all the available buffers to Request Queue (Maintain order) + List::iterator it = mBufPool.begin(); + for (; it!=mBufPool.end(); ++it) { + memset(it->memBuf, 0x0, (*it).memBufsize); + mEmptyQueue.push_back(*it); + } + } + + ALOGV("Transferred all the buffers from Filled queue to " + "Empty queue to handle seek paused %d, skipwrite %d", mPaused, mSkipWrite); + ALOGV("Set mReachedEOS to false and mEosEventReceived to false"); + mReachedEOS = false; + mEosEventReceived = false; + mSkipEOS = false; + // 3.) If its in start state, + // Pause and flush the driver and Resume it again + // If its in paused state, + // Set the seek flag, Resume will take care of flushing the + // driver + if (!mPaused) { + ALOGV("AudioSessionOutALSA flush going to call Pause"); + if ((err = ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1)) < 0) { + ALOGE("Audio Pause failed - continuing"); + //return UNKNOWN_ERROR; + } + } else { + mSeeking = true; + } + + //drain has to be called every time irrespective of whether its paused or not + if ((err = drain()) != OK) { + ALOGE("pcm_prepare failed - continuing"); + //return err; + } + + //4.) Skip the current write from the decoder and signal to the Write get + // the next set of data from the decoder + mSkipWrite = true; + ALOGV("signalling from flush mSkipWrite %d", mSkipWrite); + mWriteCv.signal(); + + ALOGV("AudioSessionOutALSA::flush completed"); + return NO_ERROR; +} + + + +status_t AudioSessionOutALSA::stop() +{ + Mutex::Autolock autoLock(mLock); + ALOGV("AudioSessionOutALSA- stop"); + // close all the existing PCM devices + mSkipWrite = true; + mWriteCv.signal(); + + if (mParent->mRouteAudioToExtOut) { + status_t err = mParent->suspendPlaybackOnExtOut(mUseCase); + if(err) { + ALOGE("stop-suspendPlaybackOnExtOut- return err = %d", err); + return err; + } + } + + ALOGV("stop -"); + + return NO_ERROR; +} + +status_t AudioSessionOutALSA::standby() +{ + Mutex::Autolock autoLock(mParent->mLock); + // At this point, all the buffers with the driver should be + // flushed. + status_t err = NO_ERROR; + flush(); + mAlsaHandle->module->standby(mAlsaHandle); + if (mParent->mRouteAudioToExtOut) { + ALOGD("Standby - stopPlaybackOnExtOut_l - mUseCase = %d",mUseCase); + err = mParent->stopPlaybackOnExtOut_l(mUseCase); + if(err){ + ALOGE("stopPlaybackOnExtOut_l return err %d", err); + } + } + mPaused = false; + return err; +} + +#define USEC_TO_MSEC(x) ((x + 999) / 1000) + +uint32_t AudioSessionOutALSA::latency() const +{ + // Android wants latency in milliseconds. + return USEC_TO_MSEC (mAlsaHandle->latency); +} + +status_t AudioSessionOutALSA::setObserver(void *observer) +{ + ALOGV("Registering the callback \n"); + mObserver = reinterpret_cast(observer); + return NO_ERROR; +} + +status_t AudioSessionOutALSA::dump(int fd, const Vector& args) +{ + return NO_ERROR; +} + +status_t AudioSessionOutALSA::getNextWriteTimestamp(int64_t *timestamp) +{ + struct snd_compr_tstamp tstamp; + tstamp.timestamp = -1; + if (ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_TSTAMP, &tstamp)){ + ALOGE("Failed SNDRV_COMPRESS_TSTAMP\n"); + return UNKNOWN_ERROR; + } else { + ALOGV("Timestamp returned = %lld\n", tstamp.timestamp); + *timestamp = tstamp.timestamp; + return NO_ERROR; + } + return NO_ERROR; +} + +// return the number of audio frames written by the audio dsp to DAC since +// the output has exited standby +status_t AudioSessionOutALSA::getRenderPosition(uint32_t *dspFrames) +{ + Mutex::Autolock autoLock(mLock); + *dspFrames = mFrameCount; + return NO_ERROR; +} + +status_t AudioSessionOutALSA::getBufferInfo(buf_info **buf) { + if (!mAlsaHandle) { + return NO_ERROR; + } + buf_info *tempbuf = (buf_info *)malloc(sizeof(buf_info) + mInputBufferCount*sizeof(int *)); + ALOGV("Get buffer info"); + tempbuf->bufsize = (mAlsaHandle->handle->period_size - mOutputMetadataLength); + tempbuf->nBufs = mInputBufferCount; + tempbuf->buffers = (int **)((char*)tempbuf + sizeof(buf_info)); + List::iterator it = mBufPool.begin(); + for (int i = 0; i < mInputBufferCount; i++) { + tempbuf->buffers[i] = (int *)(((char *)it->memBuf) + mOutputMetadataLength); + it++; + } + *buf = tempbuf; + return NO_ERROR; +} + +status_t AudioSessionOutALSA::isBufferAvailable(int *isAvail) { + + Mutex::Autolock autoLock(mLock); + // this lock is required to synchronize between decoder thread and control thread. + // if this thread is waiting for a signal on the conditional ariable "mWriteCv" + // and the ~AudioSessionOut() signals but the mWriteCv is destroyed, before the + // signal reaches the waiting thread, it can lead to an indefinite wait resulting + // in deadlock. + ALOGV("acquiring mDecoderLock in isBufferAvailable()"); + Mutex::Autolock autoDecoderLock(mDecoderLock); + ALOGV("isBufferAvailable Empty Queue size() = %d, Filled Queue size() = %d ", + mEmptyQueue.size(),mFilledQueue.size()); + *isAvail = false; + + /* + * Only time the below condition is true is when isBufferAvailable is called + * immediately after a flush + */ + if (mSkipWrite) { + LOG_ALWAYS_FATAL_IF((mEmptyQueue.size() != BUFFER_COUNT), + "::isBufferAvailable, mSkipwrite is true but empty queue isnt full"); + mSkipWrite = false; + } + // 1.) Wait till a empty buffer is available in the Empty buffer queue + while (mEmptyQueue.empty()) { + ALOGV("Write: waiting on mWriteCv"); + mWriteCv.wait(mLock); + if (mSkipWrite) { + ALOGV("Write: Flushing the previous write buffer"); + mSkipWrite = false; + return NO_ERROR; + } + ALOGV("isBufferAvailable: received a signal to wake up"); + } + + *isAvail = true; + return NO_ERROR; +} + +status_t AudioSessionOutALSA::openDevice(char *useCase, bool bIsUseCase, int devices) +{ + alsa_handle_t alsa_handle; + status_t status = NO_ERROR; + ALOGV("openDevice: E usecase %s", useCase); + alsa_handle.module = mAlsaDevice; + alsa_handle.bufferSize = mInputBufferSize; + alsa_handle.devices = devices; + alsa_handle.handle = 0; + alsa_handle.format = (mFormat == AUDIO_FORMAT_PCM_16_BIT ? SNDRV_PCM_FORMAT_S16_LE : mFormat); + //ToDo: Add conversion from channel Mask to channel count. + if (mChannels == AUDIO_CHANNEL_OUT_MONO) + alsa_handle.channels = MONO_CHANNEL_MODE; + else + alsa_handle.channels = DEFAULT_CHANNEL_MODE; + alsa_handle.channels = AudioSystem::popCount(mChannels); + alsa_handle.sampleRate = mSampleRate; + alsa_handle.latency = PLAYBACK_LATENCY; + alsa_handle.rxHandle = 0; + alsa_handle.ucMgr = mUcMgr; + alsa_handle.session = this; + strlcpy(alsa_handle.useCase, useCase, sizeof(alsa_handle.useCase)); + + mAlsaDevice->route(&alsa_handle, devices, mParent->mode()); + if (bIsUseCase) { + snd_use_case_set(mUcMgr, "_verb", useCase); + } else { + snd_use_case_set(mUcMgr, "_enamod", useCase); + } +#ifdef QCOM_USBAUDIO_ENABLED + //Set Tunnel or LPA bit if the playback over usb is tunnel or Lpa + if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| + (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){ + if((!strcmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || + (!strcmp(useCase, SND_USE_CASE_MOD_PLAY_LPA))) { + ALOGV("doRouting: LPA device switch to proxy"); + mParent->startUsbPlaybackIfNotStarted(); + mParent->musbPlaybackState |= USBPLAYBACKBIT_LPA; + } else if((!strcmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || + (!strcmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { + ALOGD("doRouting: Tunnel Player device switch to proxy"); + mParent->startUsbPlaybackIfNotStarted(); + mParent->musbPlaybackState |= USBPLAYBACKBIT_TUNNEL; + } + } +#endif + status = mAlsaDevice->open(&alsa_handle); + if(status != NO_ERROR) { + ALOGE("Could not open the ALSA device for use case %s", alsa_handle.useCase); + mAlsaDevice->close(&alsa_handle); + } else{ + mParent->mDeviceList.push_back(alsa_handle); + } + return status; +} + +status_t AudioSessionOutALSA::closeDevice(alsa_handle_t *pHandle) +{ + status_t status = NO_ERROR; + ALOGV("closeDevice: useCase %s", pHandle->useCase); + //TODO: remove from mDeviceList + if(pHandle) { + status = mAlsaDevice->close(pHandle); + } + return status; +} + +status_t AudioSessionOutALSA::setParameters(const String8& keyValuePairs) +{ + Mutex::Autolock autoLock(mLock); + AudioParameter param = AudioParameter(keyValuePairs); + String8 key = String8(AudioParameter::keyRouting); + String8 value; + + int device; + if (param.getInt(key, device) == NO_ERROR) { + // Ignore routing if device is 0. + if(device) { + ALOGV("setParameters(): keyRouting with device %#x", device); + if (mParent->isExtOutDevice(device)) { + mParent->mRouteAudioToExtOut = true; + ALOGD("setParameters(): device %#x", device); + } + mParent->doRouting(device); + } + param.remove(key); + } +#ifdef QCOM_ADSP_SSR_ENABLED + key = String8(AudioParameter::keyADSPStatus); + if (param.get(key, value) == NO_ERROR) { + if (value == "ONLINE"){ + mReachedEOS = true; + mSkipWrite = true; + mWriteCv.signal(); + mObserver->postEOS(1); + } + else if (value == "OFFLINE") { + mParent->mLock.lock(); + requestAndWaitForEventThreadExit(); + mParent->mLock.unlock(); + } + } else { +#endif + mParent->setParameters(keyValuePairs); +#ifdef QCOM_ADSP_SSR_ENABLED + } +#endif + return NO_ERROR; +} + +String8 AudioSessionOutALSA::getParameters(const String8& keys) +{ + Mutex::Autolock autoLock(mLock); + AudioParameter param = AudioParameter(keys); + String8 value; + String8 key = String8(AudioParameter::keyRouting); + + if (param.get(key, value) == NO_ERROR) { + param.addInt(key, (int)mAlsaHandle->devices); + } + + ALOGV("getParameters() %s", param.toString().string()); + return param.toString(); +} + +void AudioSessionOutALSA::reset() { + mParent->mLock.lock(); + requestAndWaitForEventThreadExit(); + +#ifdef QCOM_USBAUDIO_ENABLED + if (mParent->musbPlaybackState) { + if((!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || + (!strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) { + ALOGV("Deregistering LPA bit: musbPlaybackState =%d",mParent->musbPlaybackState); + mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA; + } else if((!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || + (!strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { + ALOGV("Deregistering Tunnel Player bit: musbPlaybackState =%d",mParent->musbPlaybackState); + mParent->musbPlaybackState &= ~USBPLAYBACKBIT_TUNNEL; + } + } +#endif + + if(mAlsaHandle) { + ALOGV("closeDevice mAlsaHandle"); + closeDevice(mAlsaHandle); + mAlsaHandle = NULL; + } +#ifdef QCOM_USBAUDIO_ENABLED + mParent->closeUsbPlaybackIfNothingActive(); +#endif + ALOGV("Erase device list"); + for(ALSAHandleList::iterator it = mParent->mDeviceList.begin(); + it != mParent->mDeviceList.end(); ++it) { + if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, + strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) || + (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, + strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) || + (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, + strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) || + (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA, + strlen(SND_USE_CASE_MOD_PLAY_LPA)))) { + mParent->mDeviceList.erase(it); + break; + } + } + mParent->mLock.unlock(); +} +void AudioSessionOutALSA::updateMetaData(size_t bytes) { + mOutputMetadataTunnel.metadataLength = sizeof(mOutputMetadataTunnel); + mOutputMetadataTunnel.timestamp = 0; + mOutputMetadataTunnel.bufferLength = bytes; + ALOGD("bytes = %d , mAlsaHandle->handle->period_size = %d, metadata = %d ", + mOutputMetadataTunnel.bufferLength, mAlsaHandle->handle->period_size, mOutputMetadataTunnel.metadataLength); +} + +status_t AudioSessionOutALSA::drainAndPostEOS_l() +{ + if (!mFilledQueue.empty()) { + ALOGD("drainAndPostEOS called without empty mFilledQueue"); + return INVALID_OPERATION; + } + + if (!mReachedEOS) { + ALOGD("drainAndPostEOS called without mReachedEOS set"); + return INVALID_OPERATION; + } + + if (mEosEventReceived) { + ALOGD("drainAndPostEOS called after mEosEventReceived"); + return INVALID_OPERATION; + } + + mSkipEOS = false; + if ((!strncmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, + strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) || + (!strncmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, + strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) { + ALOGD("Audio Drain DONE ++"); + mLock.unlock(); //to allow flush() + int ret = ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_DRAIN); + mLock.lock(); + + if (ret < 0) { + ret = -errno; + ALOGE("Audio Drain failed with errno %s", strerror(errno)); + switch (ret) { + case -EINTR: //interrupted by flush + mSkipEOS = true; + break; + case -EWOULDBLOCK: //no writes given, drain would block indefintely + //mReachedEOS might have been cleared in the meantime + //by a flush. Do not send a false EOS in that case + mSkipEOS = mReachedEOS ? false : true; + break; + default: + mSkipEOS = false; + break; + } + } + ALOGD("Audio Drain DONE --"); + } + + if (mSkipEOS == false) { + ALOGV("Posting the EOS to the observer player %p depending on mReachedEOS %d", \ + mObserver, mReachedEOS); + mEosEventReceived = true; + if (mObserver != NULL) { + ALOGV("mObserver: posting EOS from eventcallback"); + mLock.unlock(); + mObserver->postEOS(0); + mLock.lock(); + }; + } else { + ALOGD("Ignored EOS posting since mSkipEOS is false"); + } + return OK; +} + +status_t AudioSessionOutALSA::setMetaDataMode() { + + status_t err = NO_ERROR; + //Call IOCTL + if(mAlsaHandle->handle && !mAlsaHandle->handle->start) { + err = ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_METADATA_MODE); + if(err < 0) { + ALOGE("ioctl Set metadata mode failed = %d", err); + } + } + else { + ALOGE("ALSA pcm handle invalid / pcm driver already started"); + err = INVALID_OPERATION; + } + return err; +} +} // namespace android_audio_legacy diff --git a/legacy/alsa_sound/AudioStreamInALSA.cpp b/legacy/alsa_sound/AudioStreamInALSA.cpp index 4771d429c..a6a088a07 100644 --- a/legacy/alsa_sound/AudioStreamInALSA.cpp +++ b/legacy/alsa_sound/AudioStreamInALSA.cpp @@ -1,7 +1,7 @@ /* AudioStreamInALSA.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -38,10 +38,9 @@ extern "C" { #ifdef QCOM_CSDCLIENT_ENABLED -static int (*csd_start_record)(int); -static int (*csd_stop_record)(void); +static int (*csd_start_record)(uint32_t, int); +static int (*csd_stop_record)(uint32_t); #endif - #ifdef QCOM_SSR_ENABLED #include "surround_filters_interface.h" #endif @@ -69,8 +68,8 @@ AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent, AudioSystem::audio_in_acoustics audio_acoustics) : ALSAStreamOps(parent, handle), mFramesLost(0), - mAcoustics(audio_acoustics), - mParent(parent) + mParent(parent), + mAcoustics(audio_acoustics) #ifdef QCOM_SSR_ENABLED , mFp_4ch(NULL), mFp_6ch(NULL), @@ -90,7 +89,9 @@ AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent, // Call surround sound library init if device is Surround Sound if ( handle->channels == 6) { if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) - || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { + || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) + || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) { err = initSurroundSoundLibrary(handle->bufferSize); if ( NO_ERROR != err) { @@ -102,15 +103,23 @@ AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent, //Remember to change file system permission of data(e.g. chmod 777 data/), //otherwise, fopen may fail. if ( !mFp_4ch) - mFp_4ch = fopen("/data/4ch_ssr.pcm", "wb"); + mFp_4ch = fopen("/data/media/0/4ch_ssr.pcm", "wb"); if ( !mFp_6ch) - mFp_6ch = fopen("/data/6ch_ssr.pcm", "wb"); + mFp_6ch = fopen("/data/media/0/6ch_ssr.pcm", "wb"); if ((!mFp_4ch) || (!mFp_6ch)) ALOGE("mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",mFp_4ch,mFp_6ch); } } } #endif +#ifdef QCOM_CSDCLIENT_ENABLED + if (mParent->mCsdHandle != NULL) { + csd_start_record = (int (*)(uint32_t, int))::dlsym(mParent->mCsdHandle, + "csd_client_start_record"); + csd_stop_record = (int (*)(uint32_t))::dlsym(mParent->mCsdHandle, + "csd_client_stop_record"); + } +#endif } AudioStreamInALSA::~AudioStreamInALSA() @@ -125,51 +134,69 @@ status_t AudioStreamInALSA::setGain(float gain) ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) { - int period_size; + unsigned int period_size; ALOGV("read:: buffer %p, bytes %d", buffer, bytes); int n; status_t err; - ssize_t read = 0; - char *use_case; + size_t read = 0; + char *use_case; int newMode = mParent->mode(); if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) && - (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) && - (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { + (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) && + (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { mParent->mLock.lock(); snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case); if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) && - (newMode == AudioSystem::MODE_IN_CALL)) { + (newMode == AUDIO_MODE_IN_CALL)) { ALOGD("read:: mParent->mIncallMode=%d", mParent->mIncallMode); - if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) && - (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) { + if ((mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_UPLINK) && + (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK)) { #ifdef QCOM_CSDCLIENT_ENABLED if (mParent->mFusion3Platform) { mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO); strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, sizeof(mHandle->useCase)); - start_csd_record(INCALL_REC_STEREO); + if (csd_start_record == NULL) { + ALOGE("csd_start_record is NULL"); + } else { + csd_start_record(ALL_SESSION_VSID, INCALL_REC_STEREO); + } } else #endif { - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, - sizeof(mHandle->useCase)); + if (mHandle->format == AUDIO_FORMAT_AMR_WB) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL, + sizeof(mHandle->useCase)); + } else { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, + sizeof(mHandle->useCase)); + } } - } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) { + } else if (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK) { #ifdef QCOM_CSDCLIENT_ENABLED if (mParent->mFusion3Platform) { mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO); strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, sizeof(mHandle->useCase)); - start_csd_record(INCALL_REC_MONO); + if (csd_start_record == NULL) { + ALOGE("csd_start_record is NULL"); + } else { + csd_start_record(ALL_SESSION_VSID, INCALL_REC_MONO); + } } else #endif { - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, - sizeof(mHandle->useCase)); + if (mHandle->format == AUDIO_FORMAT_AMR_WB) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL, + sizeof(mHandle->useCase)); + } else { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, + sizeof(mHandle->useCase)); + } } } #ifdef QCOM_FM_ENABLED @@ -181,44 +208,68 @@ ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) { strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase)); } else { - char value[128]; - property_get("persist.audio.lowlatency.rec",value,"0"); - if (!strcmp("true", value)) { - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase)); - } else { - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase)); - } + char value[128]; + property_get("persist.audio.lowlatency.rec",value,"0"); + if (!strcmp("true", value)) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase)); + } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, sizeof(mHandle->useCase)); + } else { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase)); + } } } else { if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) && - (newMode == AudioSystem::MODE_IN_CALL)) { + (newMode == AUDIO_MODE_IN_CALL)) { ALOGD("read:: ---- mParent->mIncallMode=%d", mParent->mIncallMode); - if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) && - (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) { + if ((mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_UPLINK) && + (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK)) { #ifdef QCOM_CSDCLIENT_ENABLED if (mParent->mFusion3Platform) { + ALOGD("AudioStreamInALSA: check useCase: %s", mHandle->useCase); mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO); strlcpy(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC, sizeof(mHandle->useCase)); - start_csd_record(INCALL_REC_STEREO); + if (csd_start_record == NULL) { + ALOGE("csd_start_record is NULL"); + } else { + csd_start_record(ALL_SESSION_VSID, + INCALL_REC_STEREO); + } } else #endif { - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC, - sizeof(mHandle->useCase)); + if (mHandle->format == AUDIO_FORMAT_AMR_WB) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL, + sizeof(mHandle->useCase)); + } else { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC, + sizeof(mHandle->useCase)); + } } - } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) { + } else if (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK) { #ifdef QCOM_CSDCLIENT_ENABLED if (mParent->mFusion3Platform) { + ALOGD("AudioStreamInALSA: check useCase: %s", mHandle->useCase); mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO); strlcpy(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC, sizeof(mHandle->useCase)); - start_csd_record(INCALL_REC_MONO); + if (csd_start_record == NULL) { + ALOGE("csd_start_record is NULL"); + } else { + csd_start_record(ALL_SESSION_VSID, INCALL_REC_MONO); + } } else #endif { - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC, - sizeof(mHandle->useCase)); + if (mHandle->format == AUDIO_FORMAT_AMR_WB) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL, + sizeof(mHandle->useCase)); + } + else { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC, + sizeof(mHandle->useCase)); + } } } #ifdef QCOM_FM_ENABLED @@ -229,30 +280,29 @@ ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) #endif } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(mHandle->useCase)); + } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)){ + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, sizeof(mHandle->useCase)); } else { - char value[128]; - property_get("persist.audio.lowlatency.rec",value,"0"); - if (!strcmp("true", value)) { - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase)); - } else { - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase)); - } + char value[128]; + property_get("persist.audio.lowlatency.rec",value,"0"); + if (!strcmp("true", value)) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase)); + } else { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase)); + } } } - if (mHandle->channelMask == AUDIO_CHANNEL_IN_FRONT_BACK) { - mHandle->module->setFlags(mParent->mDevSettingsFlag | DMIC_FLAG); - } free(use_case); if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { #ifdef QCOM_USBAUDIO_ENABLED if((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) || (mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) { - mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AudioSystem::MODE_IN_COMMUNICATION); + mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AUDIO_MODE_IN_COMMUNICATION); }else #endif { - mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION); + mHandle->module->route(mHandle, mDevices , AUDIO_MODE_IN_COMMUNICATION); } } else { #ifdef QCOM_USBAUDIO_ENABLED @@ -268,6 +318,7 @@ ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) } if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC) || !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) || + !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) || !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_REC) || !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) || !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) || @@ -415,6 +466,39 @@ ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) buffer = buffer_start; } else #endif + if (mHandle->format == AUDIO_FORMAT_AMR_WB && + (strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) && + (strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { + ALOGV("AUDIO_FORMAT_AMR_WB"); + do { + if (read_pending < 61) { + read_pending = 61; + } + //We should pcm_read period_size to get complete data from driver + n = pcm_read(mHandle->handle, buffer, period_size); + if (n < 0) { + ALOGE("pcm_read() returned failure: %d", n); + return 0; + } else { + struct snd_compr_audio_info *header = (struct snd_compr_audio_info *) buffer; + if (header->frame_size > 0) { + if (sizeof(*header) + header->reserved[0] + header->frame_size > period_size) { + ALOGE("AMR WB read buffer overflow. Assign bigger buffer size"); + header->frame_size = period_size - sizeof(*header) - header->reserved[0]; + } + read += header->frame_size; + read_pending -= header->frame_size; + ALOGV("buffer: %p, data offset: %p, header size: %u, reserved[0]: %u", + buffer, ((uint8_t*)buffer) + sizeof(*header) + header->reserved[0], + sizeof(*header), header->reserved[0]); + memmove(buffer, ((uint8_t*)buffer) + sizeof(*header) + header->reserved[0], header->frame_size); + buffer += header->frame_size; + } else { + ALOGW("pcm_read() with zero frame size"); + } + } + } while (mHandle->handle && read < bytes); + } else { do { @@ -427,24 +511,31 @@ ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) ALOGV("pcm_read() returned n = %d", n); if (n && (n == -EIO || n == -EAGAIN || n == -EPIPE || n == -EBADFD)) { mParent->mLock.lock(); - ALOGW("pcm_read() returned error n %d, Recovering from error\n", n); - pcm_close(mHandle->handle); - mHandle->handle = NULL; - if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || - (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { - pcm_close(mHandle->rxHandle); - mHandle->rxHandle = NULL; - mHandle->module->startVoipCall(mHandle); - } - else - mHandle->module->open(mHandle); - - if(mHandle->handle == NULL) { - ALOGE("read:: PCM device re-open failed"); - mParent->mLock.unlock(); - return 0; + if (mHandle->handle != NULL) { + ALOGW("pcm_read() returned error n %d, Recovering from error\n", n); + pcm_close(mHandle->handle); + mHandle->handle = NULL; + if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || + (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { + pcm_close(mHandle->rxHandle); + mHandle->rxHandle = NULL; + mHandle->module->startVoipCall(mHandle); + } + else + { + if (mParent->mALSADevice->mSSRComplete) { + ALOGD("SSR Case: Call device switch to apply AMIX controls."); + mHandle->module->route(mHandle, mDevices , mParent->mode()); + mParent->mALSADevice->mSSRComplete = false; + } + mHandle->module->open(mHandle); + } + if(mHandle->handle == NULL) { + ALOGE("read:: PCM device re-open failed"); + mParent->mLock.unlock(); + return 0; + } } - mParent->mLock.unlock(); continue; } @@ -455,11 +546,7 @@ ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) else { read += static_cast((period_size)); read_pending -= period_size; - //Set mute by cleanning buffers read - if (mParent->mMicMute) { - memset(buffer, 0, period_size); - } - buffer = ((uint8_t *)buffer) + period_size; + buffer += period_size; } } while (mHandle->handle && read < bytes); @@ -489,12 +576,12 @@ status_t AudioStreamInALSA::close() ALOGD("close"); if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { - if((mParent->mVoipStreamCount)) { + if(mParent->mVoipInStreamCount||mParent->mVoipOutStreamCount) { #ifdef QCOM_USBAUDIO_ENABLED - ALOGD("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState, - mParent->mVoipStreamCount ); - if(mParent->mVoipStreamCount == 1) { - ALOGD("Deregistering VOIP Call bit, musbPlaybackState:%d," + ALOGV("musbRecordingState: %d, mVoipInStreamCount:%d, mVoipOutStreamCount:%d",mParent->musbRecordingState, + mParent->mVoipInStreamCount,mParent->mVoipOutStreamCount); + if(mParent->mVoipInStreamCount^mParent->mVoipOutStreamCount) { + ALOGV("Deregistering VOIP Call bit, musbPlaybackState:%d," "musbRecordingState:%d", mParent->musbPlaybackState, mParent->musbRecordingState); mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL; mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL; @@ -502,9 +589,14 @@ status_t AudioStreamInALSA::close() mParent->closeUsbPlaybackIfNothingActive(); } #endif - return NO_ERROR; + if (mParent->mVoipInStreamCount > 0) { + mParent->mVoipInStreamCount--; + } + ALOGE("AudioStreamInALSA Close :mVoipInStreamCount= %d, mParent->mVoipOutStreamCount=%d ", + mParent->mVoipInStreamCount,mParent->mVoipOutStreamCount); + return NO_ERROR; } - mParent->mVoipStreamCount = 0; + mParent->mVoipMicMute = 0; #ifdef QCOM_USBAUDIO_ENABLED } else { ALOGD("Deregistering REC bit, musbRecordingState:%d", mParent->musbRecordingState); @@ -515,7 +607,11 @@ status_t AudioStreamInALSA::close() if (mParent->mFusion3Platform) { if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) || (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE))) { - stop_csd_record(); + if (csd_stop_record == NULL) { + ALOGE("csd_stop_record is NULL"); + } else { + csd_stop_record(ALL_SESSION_VSID); + } } } #endif @@ -580,14 +676,16 @@ status_t AudioStreamInALSA::standby() (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { return NO_ERROR; } - #ifdef QCOM_CSDCLIENT_ENABLED ALOGD("standby"); if (mParent->mFusion3Platform) { if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) || (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE))) { - ALOGD(" into standby, stop record"); - stop_csd_record(); + if (csd_stop_record == NULL) { + ALOGE("csd_stop_record is NULL"); + } else { + csd_stop_record(ALL_SESSION_VSID); + } } } #endif @@ -599,10 +697,6 @@ status_t AudioStreamInALSA::standby() mParent->closeUsbRecordingIfNothingActive(); #endif - if (mHandle->channelMask == AUDIO_CHANNEL_IN_FRONT_BACK) { - mHandle->module->setFlags(mParent->mDevSettingsFlag); - } - return NO_ERROR; } @@ -862,35 +956,4 @@ status_t AudioStreamInALSA::readCoeffsFromFile() } #endif -#ifdef QCOM_CSDCLIENT_ENABLED -int AudioStreamInALSA::start_csd_record(int param) -{ - int err = NO_ERROR; - - if (mParent->mCsdHandle != NULL) { - csd_start_record = (int (*)(int))::dlsym(mParent->mCsdHandle,"csd_client_start_record"); - if (csd_start_record == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_start_record", dlerror()); - } else { - err = csd_start_record(param); - } - } - return err; -} - -int AudioStreamInALSA::stop_csd_record() -{ - int err = NO_ERROR; - if (mParent->mCsdHandle != NULL) { - csd_stop_record = (int (*)())::dlsym(mParent->mCsdHandle,"csd_client_stop_record"); - if (csd_start_record == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_start_record", dlerror()); - } else { - csd_stop_record(); - } - } - return err; -} -#endif - } // namespace android_audio_legacy diff --git a/legacy/alsa_sound/AudioStreamOutALSA.cpp b/legacy/alsa_sound/AudioStreamOutALSA.cpp index 2adb5d817..e538f44a8 100644 --- a/legacy/alsa_sound/AudioStreamOutALSA.cpp +++ b/legacy/alsa_sound/AudioStreamOutALSA.cpp @@ -1,7 +1,7 @@ /* AudioStreamOutALSA.cpp ** ** Copyright 2008-2009 Wind River Systems - ** Copyright (c) 2011, Code Aurora Forum. All rights reserved. + ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -53,12 +53,19 @@ static const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE; AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent, alsa_handle_t *handle) : ALSAStreamOps(parent, handle), mParent(parent), - mFrameCount(0) + mFrameCount(0), + mUseCase(AudioHardwareALSA::USECASE_NONE) { } AudioStreamOutALSA::~AudioStreamOutALSA() { + if (mParent->mRouteAudioToExtOut) { + status_t err = mParent->stopPlaybackOnExtOut_l(mUseCase); + if (err) { + ALOGE("stopPlaybackOnExtOut_l return err %d", err); + } + } close(); } @@ -84,21 +91,7 @@ status_t AudioStreamOutALSA::setVolume(float left, float right) } vol = lrint((volume * 0x2000)+0.5); - if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) || - !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) { - ALOGV("setLpaVolume(%f)\n", volume); - ALOGV("Setting LPA volume to %d (available range is 0 to 100)\n", vol); - mHandle->module->setLpaVolume(vol); - return status; - } - else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) || - !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) { - ALOGV("setCompressedVolume(%f)\n", volume); - ALOGV("Setting Compressed volume to %d (available range is 0 to 100)\n", vol); - mHandle->module->setCompressedVolume(vol); - return status; - } - else if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, + if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(mHandle->useCase)) || !strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase))) { ALOGV("Avoid Software volume by returning success\n"); @@ -120,98 +113,120 @@ ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes) int write_pending = bytes; - if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) && - (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) && - (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { + if((strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) && + (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { mParent->mLock.lock(); - - ALOGD("mHandle->useCase: %s", mHandle->useCase); - snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case); - if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { - if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)){ - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, - sizeof(SND_USE_CASE_VERB_IP_VOICECALL)); - } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) { - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2, - sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2)); - } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)){ - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI, - sizeof(SND_USE_CASE_MOD_PLAY_MUSIC)); - } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) { - strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, - sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)); + /* PCM handle might be closed and reopened immediately to flush + * the buffers, recheck and break if PCM handle is valid */ + if (mHandle->handle == NULL && mHandle->rxHandle == NULL) { + ALOGV("mDevices =0x%x", mDevices); + if(mParent->isExtOutDevice(mDevices)) { + ALOGV("StreamOut write - mRouteAudioToExtOut = %d ", mParent->mRouteAudioToExtOut); + mParent->mRouteAudioToExtOut = true; + if(mParent->mExtOutStream == NULL) { + mParent->switchExtOut(mDevices); + } } - } else { - if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){ - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, - sizeof(SND_USE_CASE_MOD_PLAY_VOIP)); - } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) { - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, - sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2)); - } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)){ - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, - sizeof(SND_USE_CASE_MOD_PLAY_MUSIC)); - } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) { - strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, - sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)); + ALOGV("write: mHandle->useCase: %s", mHandle->useCase); + snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case); + if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { + if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, + sizeof(SND_USE_CASE_VERB_IP_VOICECALL)); + } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2, + sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2)); + } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI, + sizeof(SND_USE_CASE_MOD_PLAY_MUSIC)); + } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) { + strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, + sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)); + } + } else { + if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, + sizeof(SND_USE_CASE_MOD_PLAY_VOIP)); + } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, + sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2)); + } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, + sizeof(SND_USE_CASE_MOD_PLAY_MUSIC)); + } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) { + strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, + sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)); + } } - } - free(use_case); - if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || - (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { + free(use_case); + if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || + (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { +#ifdef QCOM_USBAUDIO_ENABLED + if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| + (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| + (mDevices & AudioSystem::DEVICE_OUT_PROXY)) { + mHandle->module->route(mHandle, mDevices , mParent->mode()); + }else +#endif + { + mHandle->module->route(mHandle, mDevices , AUDIO_MODE_IN_COMMUNICATION); + } #ifdef QCOM_USBAUDIO_ENABLED - if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| - (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| - (mDevices & AudioSystem::DEVICE_OUT_PROXY)) { - mDevices |= AudioSystem::DEVICE_OUT_PROXY; + } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| + (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| + (mDevices & AudioSystem::DEVICE_OUT_PROXY)) { mHandle->module->route(mHandle, mDevices , mParent->mode()); - }else #endif - { - mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION); + } else { + mHandle->module->route(mHandle, mDevices , mParent->mode()); + } + if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) || + !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) || + !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) || + !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) { + snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase); + } else { + snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase); + } + if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || + (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { + err = mHandle->module->startVoipCall(mHandle); + } + else + mHandle->module->open(mHandle); + if(mHandle->handle == NULL) { + ALOGE("write:: device open failed"); + mParent->mLock.unlock(); + return bytes; } #ifdef QCOM_USBAUDIO_ENABLED - } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| - (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| - (mDevices & AudioSystem::DEVICE_OUT_PROXY)) { - mDevices |= AudioSystem::DEVICE_OUT_PROXY; - mHandle->module->route(mHandle, mDevices , mParent->mode()); + if((mDevices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)|| + (mDevices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){ + if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || + (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { + ALOGV("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState); + mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; + } else { + mParent->startUsbPlaybackIfNotStarted(); + ALOGV("enabling music, musbPlaybackState: %d ", mParent->musbPlaybackState); + mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC; + } + } #endif - } else { - mHandle->module->route(mHandle, mDevices , mParent->mode()); } - if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) || - !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) || - !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) || - !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) { - snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase); - } else { - snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase); - } - if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || - (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { - err = mHandle->module->startVoipCall(mHandle); - } - else - mHandle->module->open(mHandle); - if(mHandle->handle == NULL) { - ALOGE("write:: device open failed"); - mParent->mLock.unlock(); - return bytes; - } -#ifdef QCOM_USBAUDIO_ENABLED - if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)|| - (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){ - if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || - (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { - mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; - } else { - mParent->startUsbPlaybackIfNotStarted(); - mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC; + if (mParent->mRouteAudioToExtOut) { + mUseCase = mParent->useCaseStringToEnum(mHandle->useCase); + if (! (mParent->getExtOutActiveUseCases_l() & mUseCase )){ + ALOGD("startPlaybackOnExtOut_l from write :: useCase = %s", mHandle->useCase); + status_t err = NO_ERROR; + err = mParent->startPlaybackOnExtOut_l(mUseCase); + if(err) { + ALOGE("startPlaybackOnExtOut_l from write return err = %d", err); + mParent->mLock.unlock(); + return err; + } } } -#endif - mParent->mLock.unlock(); } @@ -224,7 +239,7 @@ ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes) ALOGV("Starting playback on USB"); if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) || !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) { - ALOGD("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState); + ALOGV("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState); mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; }else{ ALOGV("enabling music, musbPlaybackState: %d ", mParent->musbPlaybackState); @@ -239,7 +254,7 @@ ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes) if (write_pending < period_size) { write_pending = period_size; } - if((mParent->mVoipStreamCount) && (mHandle->rxHandle != 0)) { + if((mParent->mVoipOutStreamCount) && (mHandle->rxHandle != 0)) { n = pcm_write(mHandle->rxHandle, (char *)buffer + sent, period_size); @@ -261,7 +276,19 @@ ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes) mHandle->module->startVoipCall(mHandle); } else + { + if (mParent->mALSADevice->mSSRComplete) { + ALOGD("SSR Case: Call device switch to apply AMIX controls."); + mHandle->module->route(mHandle, mDevices , mParent->mode()); + mParent->mALSADevice->mSSRComplete = false; + + if(mParent->isExtOutDevice(mDevices)) { + ALOGV("StreamOut write - mRouteAudioToExtOut = %d ", mParent->mRouteAudioToExtOut); + mParent->mRouteAudioToExtOut = true; + } + } mHandle->module->open(mHandle); + } if(mHandle->handle == NULL) { ALOGE("write:: device re-open failed"); mParent->mLock.unlock(); @@ -277,7 +304,7 @@ ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes) write_pending -= period_size; } - } while ((mHandle->handle||(mHandle->rxHandle && mParent->mVoipStreamCount)) && sent < bytes); + } while ((mHandle->handle||(mHandle->rxHandle && mParent->mVoipOutStreamCount)) && sent < bytes); return sent; } @@ -301,32 +328,46 @@ status_t AudioStreamOutALSA::close() ALOGV("close"); if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { - if((mParent->mVoipStreamCount)) { + if(mParent->mVoipInStreamCount||mParent->mVoipOutStreamCount) { #ifdef QCOM_USBAUDIO_ENABLED - if(mParent->mVoipStreamCount == 1) { + if(mParent->mVoipInStreamCount^mParent->mVoipOutStreamCount) { ALOGV("Deregistering VOIP Call bit, musbPlaybackState:%d, musbRecordingState: %d", mParent->musbPlaybackState, mParent->musbRecordingState); mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL; mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL; mParent->closeUsbPlaybackIfNothingActive(); mParent->closeUsbRecordingIfNothingActive(); + + if (mParent->mRouteAudioToExtOut) { + //TODO: HANDLE VOIP A2DP + } } #endif - return NO_ERROR; + if(mParent->mVoipOutStreamCount > 0) { + mParent->mVoipOutStreamCount--; + } + ALOGE("AudioStreamOutALSA Close :mVoipInStreamCount= %d, mParent->mVoipOutStreamCount=%d ", + mParent->mVoipInStreamCount, mParent->mVoipOutStreamCount); + return NO_ERROR; } - mParent->mVoipStreamCount = 0; + mParent->mVoipMicMute = 0; } #ifdef QCOM_USBAUDIO_ENABLED - else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || - (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) { - mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA; - } else { + else { mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC; } mParent->closeUsbPlaybackIfNothingActive(); #endif + if (mParent->mRouteAudioToExtOut) { + ALOGD("close-suspendPlaybackOnExtOut_l::mUseCase = %d",mUseCase); + status_t err = mParent->suspendPlaybackOnExtOut_l(mUseCase); + if(err) { + ALOGE("suspendExtOutPlayback from hardware output close return err = %d", err); + return err; + } + } ALSAStreamOps::close(); return NO_ERROR; @@ -344,17 +385,19 @@ status_t AudioStreamOutALSA::standby() } #ifdef QCOM_USBAUDIO_ENABLED - if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || - (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) { - ALOGV("Deregistering LPA bit"); - mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA; - } else { - ALOGV("Deregistering MUSIC bit, musbPlaybackState: %d", mParent->musbPlaybackState); + if (mParent->musbPlaybackState) { + ALOGD("Deregistering MUSIC bit, musbPlaybackState: %d", mParent->musbPlaybackState); mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC; } #endif mHandle->module->standby(mHandle); + if (mParent->mRouteAudioToExtOut) { + status_t err = mParent->stopPlaybackOnExtOut_l(mUseCase); + if(err) { + ALOGE("stopPlaybackOnExtOut_l return err %d", err); + } + } #ifdef QCOM_USBAUDIO_ENABLED mParent->closeUsbPlaybackIfNothingActive(); diff --git a/legacy/alsa_sound/AudioUsbALSA.cpp b/legacy/alsa_sound/AudioUsbALSA.cpp index 3316e3e26..a38cc695a 100644 --- a/legacy/alsa_sound/AudioUsbALSA.cpp +++ b/legacy/alsa_sound/AudioUsbALSA.cpp @@ -1,5 +1,6 @@ /* AudioUsbALSA.cpp -Copyright (c) 2012, Code Aurora Forum. All rights reserved. + +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 @@ -10,7 +11,7 @@ met: 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 Code Aurora Forum, Inc. nor the names of its + * 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. @@ -49,11 +50,31 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ #include "AudioUsbALSA.h" struct pollfd pfdProxyPlayback[2]; struct pollfd pfdUsbPlayback[2]; -struct pollfd pfdProxyRecording[1]; -struct pollfd pfdUsbRecording[1]; +struct pollfd pfdProxyRecording[2]; +struct pollfd pfdUsbRecording[2]; #define USB_PERIOD_SIZE 2048 #define PROXY_PERIOD_SIZE 3072 +#define PROXY_SUPPORTED_RATE_8000 8000 +#define PROXY_SUPPORTED_RATE_16000 16000 +#define PROXY_SUPPORTED_RATE_48000 48000 +#define AFE_PROXY_PERIOD_COUNT 32 +//#define OUTPUT_PROXY_BUFFER_LOG +//#define OUTPUT_RECORD_PROXY_BUFFER_LOG +#ifdef OUTPUT_PROXY_BUFFER_LOG + FILE *outputBufferFile1; + char outputfilename [256] = "/data/usb_output_proxy"; + char outputfilename1 [256] = ""; + static int number = 0; +#endif + +#ifdef OUTPUT_RECORD_PROXY_BUFFER_LOG + FILE *outputRecordBufferFile1; + char outputRecordfilename [256] = "/data/usb_record"; + char outputRecordfilename1 [256] = ""; + + static int rNumber = 0; +#endif namespace android_audio_legacy { @@ -63,6 +84,11 @@ AudioUsbALSA::AudioUsbALSA() musbpfdPlayback = -1; mkillPlayBackThread = false; mkillRecordingThread = false; + musbRecordingHandle = NULL; + mproxyRecordingHandle = NULL; + musbPlaybackHandle = NULL; + mproxyPlaybackHandle = NULL; + mProxySoundCard = 0; } AudioUsbALSA::~AudioUsbALSA() @@ -117,7 +143,11 @@ status_t AudioUsbALSA::getCap(char * type, int &channels, int &sampleRate) fileSize = st.st_size; - read_buf = (char *)malloc(BUFFSIZE); + if ((read_buf = (char *)malloc(BUFFSIZE)) == NULL) { + ALOGE("ERROR: Unable to allocate memory to hold stream caps"); + close(fd); + return NO_MEMORY; + } memset(read_buf, 0x0, BUFFSIZE); err = read(fd, read_buf, BUFFSIZE); str_start = strstr(read_buf, type); @@ -175,8 +205,19 @@ status_t AudioUsbALSA::getCap(char * type, int &channels, int &sampleRate) return UNKNOWN_ERROR; } size = target - ratesStrStart; - ratesStr = (char *)malloc(size + 1) ; - ratesStrForVal = (char *)malloc(size + 1) ; + if ((ratesStr = (char *)malloc(size + 1)) == NULL) { + ALOGE("ERROR: Unable to allocate memory to hold sample rate strings"); + close(fd); + free(read_buf); + return NO_MEMORY; + } + if ((ratesStrForVal = (char *)malloc(size + 1)) == NULL) { + ALOGE("ERROR: Unable to allocate memory to hold sample rate string"); + close(fd); + free(ratesStr); + free(read_buf); + return NO_MEMORY; + } memcpy(ratesStr, ratesStrStart, size); memcpy(ratesStrForVal, ratesStrStart, size); ratesStr[size] = '\0'; @@ -205,16 +246,22 @@ status_t AudioUsbALSA::getCap(char * type, int &channels, int &sampleRate) } ratesSupported[0] = atoi(nextSRString); + ALOGV("ratesSupported[0] for playback: %d", ratesSupported[0]); for (i = 1; i sampleRate) && (ratesSupported[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 ((ratesSupported[i] == PROXY_SUPPORTED_RATE_8000) || + (ratesSupported[i] == PROXY_SUPPORTED_RATE_16000) || + (ratesSupported[i] == PROXY_SUPPORTED_RATE_48000)) { + sampleRate = ratesSupported[i]; + } } } ALOGD("sampleRate: %d", sampleRate); @@ -231,43 +278,85 @@ status_t AudioUsbALSA::getCap(char * type, int &channels, int &sampleRate) void AudioUsbALSA::exitPlaybackThread(uint64_t writeVal) { - ALOGD("exitPlaybackThread, mproxypfdPlayback: %d", mproxypfdPlayback); +#ifdef OUTPUT_PROXY_BUFFER_LOG + ALOGV("close file output"); + if(outputBufferFile1) + fclose (outputBufferFile1); +#endif + { + Mutex::Autolock autoLock(mLock); + ALOGD("exitPlaybackThread, mproxypfdPlayback: %d", mproxypfdPlayback); + mkillPlayBackThread = true; + if ((mproxypfdPlayback != -1) && (musbpfdPlayback != -1)) { + write(mproxypfdPlayback, &writeVal, sizeof(uint64_t)); + write(musbpfdPlayback, &writeVal, sizeof(uint64_t)); + } + } + if(mPlaybackUsb) { + status_t ret = pthread_join(mPlaybackUsb,NULL); + ALOGE("return for pthreadjoin = %d", ret); + mPlaybackUsb = NULL; + } if (writeVal == SIGNAL_EVENT_KILLTHREAD) { int err; - - err = closeDevice(mproxyPlaybackHandle); - if (err) { - ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle); - } - err = closeDevice(musbPlaybackHandle); - if (err) { - ALOGE("Info: Could not close USB device %p", musbPlaybackHandle); + { + Mutex::Autolock autoLock(mLock); + err = closeDevice(mproxyPlaybackHandle); + if (err) { + ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle); + } + err = closeDevice(musbPlaybackHandle); + if (err) { + ALOGE("Info: Could not close USB device %p", musbPlaybackHandle); + } } } - if ((mproxypfdPlayback != -1) && (musbpfdPlayback != -1)) { - write(mproxypfdPlayback, &writeVal, sizeof(uint64_t)); - write(musbpfdPlayback, &writeVal, sizeof(uint64_t)); - mkillPlayBackThread = true; - pthread_join(mPlaybackUsb,NULL); - } } void AudioUsbALSA::exitRecordingThread(uint64_t writeVal) { + //TODO: Need to use userspace fd to kill the thread. + // Not a valid assumption to blindly close the thread. ALOGD("exitRecordingThread"); - if (writeVal == SIGNAL_EVENT_KILLTHREAD) { - int err; +#ifdef OUTPUT_RECORD_PROXY_BUFFER_LOG + ALOGV("close file output"); + if(outputRecordBufferFile1) + fclose (outputRecordBufferFile1); +#endif - err = closeDevice(mproxyRecordingHandle); - if (err) { - ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle); + mkillRecordingThread = true; + { + Mutex::Autolock autoRecordLock(mRecordLock); + if ((pfdProxyRecording[1].fd != -1) && (pfdUsbRecording[1].fd != -1)) { + ALOGD("write to fd"); + write(pfdUsbRecording[1].fd, &writeVal, sizeof(uint64_t)); + write(pfdProxyRecording[1].fd, &writeVal, sizeof(uint64_t)); } - err = closeDevice(musbRecordingHandle); - if (err) { - ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle); + } + + if(mRecordingUsb) { + int err = pthread_join(mRecordingUsb,NULL); + ALOGD("pthread join err = %d",err); + mRecordingUsb = NULL; + } + if (writeVal == SIGNAL_EVENT_KILLTHREAD ) { + int err; + { + Mutex::Autolock autoRecordLock(mRecordLock); + err = closeDevice(mproxyRecordingHandle); + if (err) { + ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle); + } else { + mproxyRecordingHandle = NULL; + } + err = closeDevice(musbRecordingHandle); + if (err) { + ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle); + } else { + musbRecordingHandle = NULL; + } } } - mkillRecordingThread = true; } void AudioUsbALSA::setkillUsbRecordingThread(bool val){ @@ -275,7 +364,8 @@ void AudioUsbALSA::setkillUsbRecordingThread(bool val){ mkillRecordingThread = val; } -status_t AudioUsbALSA::setHardwareParams(pcm *txHandle, uint32_t sampleRate, uint32_t channels, int periodBytes) +status_t AudioUsbALSA::setHardwareParams(pcm *txHandle, uint32_t sampleRate, + uint32_t channels, int periodBytes, UsbAudioPCMModes usbAudioPCMModes) { ALOGD("setHardwareParams"); struct snd_pcm_hw_params *params; @@ -308,6 +398,7 @@ status_t AudioUsbALSA::setHardwareParams(pcm *txHandle, uint32_t sampleRate, uin if (param_set_hw_params(txHandle, params)) { ALOGE("ERROR: cannot set hw params"); + free(params); return NO_INIT; } @@ -320,11 +411,13 @@ status_t AudioUsbALSA::setHardwareParams(pcm *txHandle, uint32_t sampleRate, uin ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d", txHandle->buffer_size, txHandle->period_size, txHandle->period_cnt); - + + //Do not free params here, params is used after setting hw/sw params + //params will be free-ed in pcm_close return NO_ERROR; } -status_t AudioUsbALSA::setSoftwareParams(pcm *pcm, bool playback) +status_t AudioUsbALSA::setSoftwareParams(pcm *pcm, UsbAudioPCMModes usbAudioPCMModes) { ALOGD("setSoftwareParams"); struct snd_pcm_sw_params* params; @@ -340,24 +433,30 @@ status_t AudioUsbALSA::setSoftwareParams(pcm *pcm, bool playback) params->avail_min = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4; - if (playback) { + if (usbAudioPCMModes == USB_PLAYBACK) { params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size*8 : pcm->period_size*4; params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size*8 : pcm->period_size*4; + } else if(usbAudioPCMModes == PROXY_PLAYBACK) { + params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size*2 : pcm->period_size; + params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size*2 : pcm->period_size; } else { params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4; params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4; } - params->stop_threshold = pcm->buffer_size; + //Setting stop threshold to a huge value to avoid trigger stop being called internally + params->stop_threshold = 0x0FFFFFFF; - params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4; params->silence_size = 0; params->silence_threshold = 0; if (param_set_sw_params(pcm, params)) { ALOGE("ERROR: cannot set sw params"); + free(params); return NO_INIT; } + //Do not free params here, params is used after setting hw/sw params + //params will be free-ed in pcm_close return NO_ERROR; } @@ -377,13 +476,12 @@ status_t AudioUsbALSA::closeDevice(pcm *handle) void AudioUsbALSA::RecordingThreadEntry() { ALOGD("Inside RecordingThreadEntry"); - int nfds = 1; + int nfds = 2; mtimeOutRecording = TIMEOUT_INFINITE; int fd; long frames; static int start = 0; struct snd_xferi x; - int filed; unsigned avail, bufsize; int bytes_written; uint32_t sampleRate; @@ -391,47 +489,74 @@ void AudioUsbALSA::RecordingThreadEntry() { u_int8_t *srcUsb_addr = NULL; u_int8_t *dstProxy_addr = NULL; int err; - const char *fn = "/data/RecordPcm.pcm"; - filed = open(fn, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0664); + pfdProxyRecording[0].fd = -1; + pfdProxyRecording[1].fd = -1; + pfdUsbRecording[0].fd = -1; + pfdUsbRecording[1].fd = -1; +#ifdef OUTPUT_RECORD_PROXY_BUFFER_LOG + sprintf(outputRecordfilename1, "%s%d%s", outputRecordfilename, rNumber,".pcm"); + outputRecordBufferFile1 = fopen (outputRecordfilename, "ab"); + rNumber++; +#endif + + { + Mutex::Autolock autoRecordLock(mRecordLock); + err = getCap((char *)"Capture:", mchannelsCapture, msampleRateCapture); + if (err) { + ALOGE("ERROR: Could not get capture capabilities from usb device"); + return; + } + int channelFlag = PCM_MONO; + if (mchannelsCapture >= 2) { + channelFlag = PCM_STEREO; + } - err = getCap((char *)"Capture:", mchannelsCapture, msampleRateCapture); - if (err) { - ALOGE("ERROR: Could not get capture capabilities from usb device"); - return; - } - int channelFlag = PCM_MONO; - if (mchannelsCapture >= 2) { - channelFlag = PCM_STEREO; - } + musbRecordingHandle = configureDevice(PCM_IN|channelFlag|PCM_MMAP, (char *)"hw:1,0", + msampleRateCapture, mchannelsCapture,2048,USB_RECORDING); + if (!musbRecordingHandle) { + ALOGE("ERROR: Could not configure USB device for recording"); + return; + } else { + ALOGD("USB device Configured for recording"); + } - musbRecordingHandle = configureDevice(PCM_IN|channelFlag|PCM_MMAP, (char *)"hw:1,0", - msampleRateCapture, mchannelsCapture,768,false); - if (!musbRecordingHandle) { - ALOGE("ERROR: Could not configure USB device for recording"); - return; - } else { - ALOGD("USB device Configured for recording"); - } + if (!mkillRecordingThread) { + pfdUsbRecording[0].fd = musbRecordingHandle->fd; //DEBUG + pfdUsbRecording[0].events = POLLIN; + musbpfdRecording = eventfd(0,0); + pfdUsbRecording[1].fd = musbpfdRecording; + pfdUsbRecording[1].events = (POLLIN | POLLERR | POLLNVAL | POLLHUP); + pfdUsbRecording[1].revents = 0; + } - pfdUsbRecording[0].fd = musbRecordingHandle->fd; //DEBUG - pfdUsbRecording[0].events = POLLIN; + mproxyRecordingHandle = configureDevice(PCM_OUT|channelFlag|PCM_MMAP, (char *)"hw:0,7", + msampleRateCapture, mchannelsCapture,2048,PROXY_PLAYBACK); + if (!mproxyRecordingHandle) { + ALOGE("ERROR: Could not configure Proxy for recording"); + err = closeDevice(musbRecordingHandle); + if(err == OK) { + musbRecordingHandle = NULL; + } + return; + } else { + ALOGD("Proxy Configured for recording"); + } - mproxyRecordingHandle = configureDevice(PCM_OUT|channelFlag|PCM_MMAP, (char *)"hw:0,7", - msampleRateCapture, mchannelsCapture,768,false); - if (!mproxyRecordingHandle) { - ALOGE("ERROR: Could not configure Proxy for recording"); - closeDevice(musbRecordingHandle); - return; - } else { - ALOGD("Proxy Configured for recording"); - } + bufsize = musbRecordingHandle->period_size; - bufsize = musbRecordingHandle->period_size; - pfdProxyRecording[0].fd = mproxyRecordingHandle->fd; - pfdProxyRecording[0].events = POLLOUT; - frames = (musbRecordingHandle->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4); - x.frames = (musbRecordingHandle->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4); + if(!mkillRecordingThread) { + pfdProxyRecording[0].fd = mproxyRecordingHandle->fd; + pfdProxyRecording[0].events = POLLOUT; + mProxypfdRecording = eventfd(0,0); + pfdUsbRecording[1].fd = mProxypfdRecording; + pfdUsbRecording[1].events = (POLLIN | POLLERR | POLLNVAL | POLLHUP); + pfdUsbRecording[1].revents = 0; + } + + frames = (musbRecordingHandle->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4); + x.frames = (musbRecordingHandle->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4); + } /***********************keep reading from usb and writing to proxy******************************************/ while (mkillRecordingThread != true) { if (!musbRecordingHandle->running) { @@ -480,8 +605,29 @@ void AudioUsbALSA::RecordingThreadEntry() { avail = pcm_avail(musbRecordingHandle); if (avail < musbRecordingHandle->sw_p->avail_min) { - poll(pfdUsbRecording, nfds, TIMEOUT_INFINITE); - continue; + int err_poll = poll(pfdUsbRecording, nfds, TIMEOUT_INFINITE); + //ALOGD("pfdUsbRecording[0].revents = %d, pfdUsbRecording[1].revents =%d", pfdUsbRecording[0].revents,pfdUsbRecording[1].revents); + if (err_poll == 0 ) { + ALOGD("POLL timedout"); + mkillRecordingThread = true; + pfdUsbRecording[0].revents = 0; + pfdUsbRecording[1].revents = 0; + } + + if (pfdUsbRecording[1].revents & POLLIN && !mkillRecordingThread) { + ALOGD("Info: Signalled from HAL about an event"); + uint64_t u; + read(musbpfdRecording, &u, sizeof(uint64_t)); + pfdUsbRecording[0].revents = 0; + pfdUsbRecording[1].revents = 0; + if (u == SIGNAL_EVENT_KILLTHREAD) { + ALOGD("kill thread"); + mkillRecordingThread = true; + } + } + if(!mkillRecordingThread) + continue; + break; } else { break; } @@ -516,8 +662,28 @@ void AudioUsbALSA::RecordingThreadEntry() { } avail = pcm_avail(mproxyRecordingHandle); if (avail < mproxyRecordingHandle->sw_p->avail_min) { - poll(pfdProxyRecording, nfds, TIMEOUT_INFINITE); - continue; + int err_poll = poll(pfdProxyRecording, nfds, TIMEOUT_INFINITE); + if (err_poll == 0 ) { + ALOGD("POLL timedout"); + mkillRecordingThread = true; + pfdProxyRecording[0].revents = 0; + pfdProxyRecording[1].revents = 0; + } + + if (pfdProxyRecording[1].revents & POLLIN && !mkillRecordingThread) { + ALOGD("Info:Proxy Signalled from HAL about an event"); + uint64_t u; + read(mProxypfdRecording, &u, sizeof(uint64_t)); + pfdProxyRecording[0].revents = 0; + pfdProxyRecording[1].revents = 0; + if (u == SIGNAL_EVENT_KILLTHREAD) { + ALOGD("kill thread"); + mkillRecordingThread = true; + } + } + if(!mkillRecordingThread) + continue; + break; } else { break; } @@ -530,6 +696,12 @@ void AudioUsbALSA::RecordingThreadEntry() { memset(dstProxy_addr, 0x0, bufsize); /**************End Proxy syncing before write *************/ +#ifdef OUTPUT_RECORD_PROXY_BUFFER_LOG + if (outputRecordBufferFile1) + { + fwrite (srcUsb_addr,1,bufsize,outputRecordBufferFile1); + } +#endif memcpy(dstProxy_addr, srcUsb_addr, bufsize ); @@ -558,7 +730,7 @@ void AudioUsbALSA::RecordingThreadEntry() { bytes_written = mproxyRecordingHandle->sync_ptr->c.control.appl_ptr - mproxyRecordingHandle->sync_ptr->s.status.hw_ptr; if ((bytes_written >= mproxyRecordingHandle->sw_p->start_threshold) && (!mproxyRecordingHandle->start)) { - if (!mkillPlayBackThread) { + if (!mkillRecordingThread) { err = startDevice(mproxyRecordingHandle, &mkillRecordingThread); if (err == EPIPE) { continue; @@ -570,10 +742,36 @@ void AudioUsbALSA::RecordingThreadEntry() { } } /*************** End sync up after write -- Proxy *********************/ - if (mkillRecordingThread) { - closeDevice(mproxyRecordingHandle); - closeDevice(musbRecordingHandle); + ALOGD("Thread dying = %d", mkillRecordingThread); +#ifdef OUTPUT_RECORD_PROXY_BUFFER_LOG + ALOGV("close file output"); + if(outputRecordBufferFile1) + fclose (outputRecordBufferFile1); +#endif + + { + Mutex::Autolock autoRecordLock(mRecordLock); + if(musbpfdRecording != -1) { + close(musbpfdRecording); + musbpfdRecording = -1; + } + if(mProxypfdRecording != -1) { + close(mProxypfdRecording); + mProxypfdRecording = -1; + } + + if (mkillRecordingThread) { + err = closeDevice(mproxyRecordingHandle); + if(err == OK) { + mproxyRecordingHandle = NULL; + } + err = closeDevice(musbRecordingHandle); + if(err == OK) { + musbRecordingHandle = NULL; + } + } } + mRecordingUsb = NULL; ALOGD("Exiting USB Recording thread"); } @@ -587,7 +785,9 @@ void *AudioUsbALSA::RecordingThreadWrapper(void *me) { return NULL; } -struct pcm * AudioUsbALSA::configureDevice(unsigned flags, char* hw, int sampleRate, int channelCount, int periodSize, bool playback){ +struct pcm * AudioUsbALSA::configureDevice(unsigned flags, char* hw, + int sampleRate, int channelCount, + int periodSize, UsbAudioPCMModes usbAudioPCMModes){ int err = NO_ERROR; struct pcm * handle = NULL; handle = pcm_open(flags, hw); @@ -603,32 +803,40 @@ struct pcm * AudioUsbALSA::configureDevice(unsigned flags, char* hw, int sampleR } ALOGD("Setting hardware params: sampleRate:%d, channels: %d",sampleRate, channelCount); - err = setHardwareParams(handle, sampleRate, channelCount,periodSize); + err = setHardwareParams(handle, sampleRate, channelCount,periodSize, usbAudioPCMModes); if (err != NO_ERROR) { ALOGE("ERROR: setHardwareParams failed"); - closeDevice(handle); - return NULL; + { + closeDevice(handle); + return NULL; + } } - err = setSoftwareParams(handle, playback); + err = setSoftwareParams(handle, usbAudioPCMModes); if (err != NO_ERROR) { ALOGE("ERROR: setSoftwareParams failed"); - closeDevice(handle); - return NULL; + { + closeDevice(handle); + return NULL; + } } err = mmap_buffer(handle); if (err) { ALOGE("ERROR: mmap_buffer failed"); - closeDevice(handle); - return NULL; + { + closeDevice(handle); + return NULL; + } } err = pcm_prepare(handle); if (err) { ALOGE("ERROR: pcm_prepare failed"); - closeDevice(handle); - return NULL; + { + closeDevice(handle); + return NULL; + } } return handle; @@ -756,7 +964,7 @@ void AudioUsbALSA::pollForUsbData(){ return; } - if (pfdUsbPlayback[0].revents & POLLERR || pfdProxyPlayback[0].revents & POLLHUP || + if (pfdUsbPlayback[0].revents & POLLERR || pfdUsbPlayback[0].revents & POLLHUP || pfdUsbPlayback[0].revents & POLLNVAL) { ALOGE("Info: usb throwing error"); mkillPlayBackThread = true; @@ -780,72 +988,106 @@ void AudioUsbALSA::PlaybackThreadEntry() { unsigned int tmp; int numOfBytesWritten; int err; - int filed; - const char *fn = "/data/test.pcm"; + char proxyDeviceName[10]; + mdstUsb_addr = NULL; msrcProxy_addr = NULL; int proxySizeRemaining = 0; int usbSizeFilled = 0; + int usbframes = 0; + u_int8_t *proxybuf = NULL; + u_int8_t *usbbuf = NULL; pid_t tid = gettid(); androidSetThreadPriority(tid, ANDROID_PRIORITY_URGENT_AUDIO); +#ifdef OUTPUT_PROXY_BUFFER_LOG + sprintf(outputfilename1, "%s%d%s", outputfilename, number,".pcm"); + outputBufferFile1 = fopen (outputfilename, "ab"); + number++; +#endif - err = getCap((char *)"Playback:", mchannelsPlayback, msampleRatePlayback); - if (err) { - ALOGE("ERROR: Could not get playback capabilities from usb device"); - return; - } + { + Mutex::Autolock autoLock(mLock); - musbPlaybackHandle = configureDevice(PCM_OUT|PCM_STEREO|PCM_MMAP, (char *)"hw:1,0", - msampleRatePlayback, mchannelsPlayback, USB_PERIOD_SIZE, true); - if (!musbPlaybackHandle) { - ALOGE("ERROR: configureUsbDevice failed, returning"); - closeDevice(musbPlaybackHandle); - return; - } else { - ALOGD("USB Configured for playback"); - } - - if (!mkillPlayBackThread) { - pfdUsbPlayback[0].fd = musbPlaybackHandle->timer_fd; - pfdUsbPlayback[0].events = POLLIN; - musbpfdPlayback = eventfd(0,0); - pfdUsbPlayback[1].fd = musbpfdPlayback; - pfdUsbPlayback[1].events = (POLLIN | POLLOUT | POLLERR | POLLNVAL | POLLHUP); - } + err = getCap((char *)"Playback:", mchannelsPlayback, msampleRatePlayback); + if (err) { + ALOGE("ERROR: Could not get playback capabilities from usb device"); + return; + } + musbPlaybackHandle = configureDevice(PCM_OUT|PCM_STEREO|PCM_MMAP, (char *)"hw:1,0", + msampleRatePlayback, mchannelsPlayback, + USB_PERIOD_SIZE, USB_PLAYBACK); + if (!musbPlaybackHandle || mkillPlayBackThread) { + ALOGE("ERROR: configureUsbDevice failed, returning"); + return; + } else { + ALOGD("USB Configured for playback"); + } - mproxyPlaybackHandle = configureDevice(PCM_IN|PCM_STEREO|PCM_MMAP, (char *)"hw:0,8", - msampleRatePlayback, mchannelsPlayback, PROXY_PERIOD_SIZE, false); - if (!mproxyPlaybackHandle) { - ALOGE("ERROR: Could not configure Proxy, returning"); - closeDevice(musbPlaybackHandle); - return; - } else { - ALOGD("Proxy Configured for playback"); - } + if (!mkillPlayBackThread) { + pfdUsbPlayback[0].fd = musbPlaybackHandle->timer_fd; + pfdUsbPlayback[0].events = POLLIN; + musbpfdPlayback = eventfd(0,0); + pfdUsbPlayback[1].fd = musbpfdPlayback; + pfdUsbPlayback[1].events = (POLLIN | POLLOUT | POLLERR | POLLNVAL | POLLHUP); + } - proxyPeriod = mproxyPlaybackHandle->period_size; - usbPeriod = musbPlaybackHandle->period_size; + snprintf(proxyDeviceName, sizeof(proxyDeviceName), "hw:%u,8", mProxySoundCard); + ALOGD("Configuring Proxy capture device %s", proxyDeviceName); + int ProxyOpenRetryCount=PROXY_OPEN_RETRY_COUNT; + while(ProxyOpenRetryCount){ + mproxyPlaybackHandle = configureDevice(PCM_IN|PCM_STEREO|PCM_MMAP, proxyDeviceName, + msampleRatePlayback, mchannelsPlayback, PROXY_PERIOD_SIZE, PROXY_RECORDING); + if(!mproxyPlaybackHandle){ + ProxyOpenRetryCount --; + usleep(PROXY_OPEN_WAIT_TIME * 1000); + ALOGD("openProxyDevice failed retrying = %d", ProxyOpenRetryCount); + } + else{ + break; + } + } + if (!mproxyPlaybackHandle || mkillPlayBackThread) { + ALOGE("ERROR: Could not configure Proxy, returning"); + err = closeDevice(musbPlaybackHandle); + if(err == OK) { + musbPlaybackHandle = NULL; + } + return; + } else { + ALOGD("Proxy Configured for playback"); + } - if (!mkillPlayBackThread) { - pfdProxyPlayback[0].fd = mproxyPlaybackHandle->fd; - pfdProxyPlayback[0].events = (POLLIN); // | POLLERR | POLLNVAL); - mproxypfdPlayback = eventfd(0,0); - pfdProxyPlayback[1].fd = mproxypfdPlayback; - pfdProxyPlayback[1].events = (POLLIN | POLLOUT| POLLERR | POLLNVAL); - } + proxyPeriod = mproxyPlaybackHandle->period_size; + usbPeriod = musbPlaybackHandle->period_size; - frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4); - x.frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4); - int usbframes = (musbPlaybackHandle->flags & PCM_MONO) ? (usbPeriod / 2) : (usbPeriod / 4); + if (!mkillPlayBackThread) { + pfdProxyPlayback[0].fd = mproxyPlaybackHandle->fd; + pfdProxyPlayback[0].events = (POLLIN); // | POLLERR | POLLNVAL); + mproxypfdPlayback = eventfd(0,0); + pfdProxyPlayback[1].fd = mproxypfdPlayback; + pfdProxyPlayback[1].events = (POLLIN | POLLERR | POLLNVAL); + } - u_int8_t *proxybuf = ( u_int8_t *) malloc(PROXY_PERIOD_SIZE); - u_int8_t *usbbuf = ( u_int8_t *) malloc(USB_PERIOD_SIZE); - memset(proxybuf, 0x0, PROXY_PERIOD_SIZE); - memset(usbbuf, 0x0, USB_PERIOD_SIZE); + frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4); + x.frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4); + usbframes = (musbPlaybackHandle->flags & PCM_MONO) ? (usbPeriod / 2) : (usbPeriod / 4); + proxybuf = ( u_int8_t *) malloc(PROXY_PERIOD_SIZE); + usbbuf = ( u_int8_t *) malloc(USB_PERIOD_SIZE); + if (proxybuf == NULL || usbbuf == NULL) { + ALOGE("ERROR: Unable to allocate USB audio buffer(s): proxybuf=%p, usbbuf=%p", + proxybuf, usbbuf); + /* Don't run the playback loop if we failed to allocate either of these buffers. + If either pointer is non-NULL they'll be freed after the end of the loop. */ + mkillPlayBackThread = true; + } else { + memset(proxybuf, 0x0, PROXY_PERIOD_SIZE); + memset(usbbuf, 0x0, USB_PERIOD_SIZE); + } + } /***********************keep reading from proxy and writing to USB******************************************/ while (mkillPlayBackThread != true) { if (!mproxyPlaybackHandle->running) { @@ -918,6 +1160,12 @@ void AudioUsbALSA::PlaybackThreadEntry() { msrcProxy_addr = dst_address(mproxyPlaybackHandle); memcpy(proxybuf, msrcProxy_addr, proxyPeriod ); +#ifdef OUTPUT_PROXY_BUFFER_LOG + if (outputBufferFile1) + { + fwrite (proxybuf,1,proxyPeriod,outputBufferFile1); + } +#endif x.frames -= frames; mproxyPlaybackHandle->sync_ptr->c.control.appl_ptr += frames; mproxyPlaybackHandle->sync_ptr->flags = 0; @@ -928,12 +1176,12 @@ void AudioUsbALSA::PlaybackThreadEntry() { err = syncPtr(mproxyPlaybackHandle, &mkillPlayBackThread); if (err == EPIPE) { continue; - } else if (err != NO_ERROR) { + } else if (err != NO_ERROR && err != ENODEV) { break; } } } - //ALOGE("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining); + //ALOGV("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining); if (usbPeriod - usbSizeFilled <= proxySizeRemaining) { memcpy(usbbuf + usbSizeFilled, proxybuf + proxyPeriod - proxySizeRemaining, usbPeriod - usbSizeFilled); proxySizeRemaining -= (usbPeriod - usbSizeFilled); @@ -1000,20 +1248,20 @@ void AudioUsbALSA::PlaybackThreadEntry() { err = syncPtr(musbPlaybackHandle, &mkillPlayBackThread); if (err == EPIPE) { continue; - } else if (err != NO_ERROR) { + } else if (err != NO_ERROR && err != ENODEV ) { break; } } bytes_written = musbPlaybackHandle->sync_ptr->c.control.appl_ptr - musbPlaybackHandle->sync_ptr->s.status.hw_ptr; - ALOGE("Appl ptr %d , hw_ptr %d, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written); + ALOGV("Appl ptr %lu , hw_ptr %lu, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written); /* Following is the check to prevent USB from going to bad state. This happens in case of an underrun where there is not enough data from the proxy */ - if (bytes_written <= usbPeriod && musbPlaybackHandle->start) { + if (bytes_written <= usbPeriod && musbPlaybackHandle->start) { ioctl(musbPlaybackHandle->fd, SNDRV_PCM_IOCTL_PAUSE,1); pcm_prepare(musbPlaybackHandle); musbPlaybackHandle->start = false; @@ -1033,16 +1281,41 @@ void AudioUsbALSA::PlaybackThreadEntry() { /*************** End sync up after write -- USB *********************/ } } - if (mkillPlayBackThread) { - if (proxybuf) - free(proxybuf); - if (usbbuf) - free(usbbuf); +#ifdef OUTPUT_PROXY_BUFFER_LOG + ALOGV("close file output"); + if(outputBufferFile1) + fclose (outputBufferFile1); +#endif + if (proxybuf) + free(proxybuf); + if (usbbuf) + free(usbbuf); + if(mproxypfdPlayback != -1) { + close(mproxypfdPlayback); mproxypfdPlayback = -1; + } + if(musbpfdPlayback != -1) { + close(musbpfdPlayback); musbpfdPlayback = -1; - closeDevice(mproxyPlaybackHandle); - closeDevice(musbPlaybackHandle); } + if(mkillPlayBackThread) { + { + Mutex::Autolock autoLock(mLock); + err = closeDevice(mproxyPlaybackHandle); + if(err == OK) { + mproxyPlaybackHandle = NULL; + } else { + ALOGE("mproxyPlaybackHandle - err = %d", err); + } + err = closeDevice(musbPlaybackHandle); + if(err == OK) { + musbPlaybackHandle = NULL; + } else { + ALOGE("musbPlaybackHandle - err = %d", err); + } + } + } + mPlaybackUsb = NULL; ALOGD("Exiting USB Playback Thread"); } diff --git a/legacy/alsa_sound/AudioUsbALSA.h b/legacy/alsa_sound/AudioUsbALSA.h index 4204eb011..af659ebff 100644 --- a/legacy/alsa_sound/AudioUsbALSA.h +++ b/legacy/alsa_sound/AudioUsbALSA.h @@ -1,6 +1,6 @@ /* AudioUsbALSA.h -Copyright (c) 2012, Code Aurora Forum. All rights reserved. + Copyright (c) 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 @@ -11,7 +11,7 @@ met: 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 Code Aurora Forum, Inc. nor the names of its + * 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. @@ -47,6 +47,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ #define SIGNAL_EVENT_TIMEOUT 1 #define SIGNAL_EVENT_KILLTHREAD 2 +#define PROXY_OPEN_RETRY_COUNT 100 +#define PROXY_OPEN_WAIT_TIME 20 #define BUFFSIZE 1000000 #define PATH "/proc/asound/card1/stream0" @@ -68,8 +70,11 @@ class AudioUsbALSA; class AudioUsbALSA { private: + int mProxySoundCard; int mproxypfdPlayback; int musbpfdPlayback; + int musbpfdRecording; + int mProxypfdRecording; int mnfdsPlayback; int mnfdsRecording; int mtimeOut; @@ -85,9 +90,18 @@ private: pthread_t mPlaybackUsb; pthread_t mRecordingUsb; snd_use_case_mgr_t *mUcMgr; + Mutex mLock; + Mutex mRecordLock; + + enum UsbAudioPCMModes { + USB_PLAYBACK = 0, + USB_RECORDING, + PROXY_PLAYBACK, + PROXY_RECORDING, + }; //Helper functions - struct pcm * configureDevice(unsigned flags, char* hw, int sampleRate, int channelCount, int periodSize, bool playback); + struct pcm * configureDevice(unsigned flags, char* hw, int sampleRate, int channelCount, int periodSize, UsbAudioPCMModes usbAudioPCMModes); status_t syncPtr(struct pcm *handle, bool *killThread); //playback @@ -106,9 +120,9 @@ private: void RecordingThreadEntry(); static void *RecordingThreadWrapper(void *me); - status_t setHardwareParams(pcm *local_handle, uint32_t sampleRate, uint32_t channels, int periodSize); + status_t setHardwareParams(pcm *local_handle, uint32_t sampleRate, uint32_t channels, int periodSize, UsbAudioPCMModes usbAudioPCMModes); - status_t setSoftwareParams(pcm *pcm, bool playback); + status_t setSoftwareParams(pcm *pcm, UsbAudioPCMModes usbAudioPCMModes); status_t closeDevice(pcm *handle); diff --git a/legacy/alsa_sound/AudioUtil.cpp b/legacy/alsa_sound/AudioUtil.cpp index 3549f24aa..7296543e3 100644 --- a/legacy/alsa_sound/AudioUtil.cpp +++ b/legacy/alsa_sound/AudioUtil.cpp @@ -1,6 +1,8 @@ /* AudioUtil.cpp * * Copyright (C) 2012 The Android Open Source Project + * Copyright (c) 2012-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. @@ -205,6 +207,66 @@ bool AudioUtil::getHDMIAudioSinkCaps(EDID_AUDIO_INFO* pInfo) { return bRet; } +bool AudioUtil::getHDMIAudioSinkCaps(EDID_AUDIO_INFO* pInfo, char *hdmiEDIDData) { + unsigned char channels[16]; + unsigned char formats[16]; + unsigned char frequency[16]; + unsigned char bitrate[16]; + unsigned char* data = NULL; + unsigned char* original_data_ptr = NULL; + if (pInfo && hdmiEDIDData) { + int length = 0, nCountDesc = 0; + + length = (int) *hdmiEDIDData++; + ALOGV("Total length is %d",length); + + nCountDesc = length/MIN_AUDIO_DESC_LENGTH; + + memset(pInfo, 0, sizeof(EDID_AUDIO_INFO)); + pInfo->nAudioBlocks = nCountDesc-1; + ALOGV("Total # of audio descriptors %d",nCountDesc); + + for(int i=0; i> 3; + frequency[i] = *hdmiEDIDData++; + bitrate [i] = *hdmiEDIDData++; + } + pInfo->nSpeakerAllocation[0] = *hdmiEDIDData++; + pInfo->nSpeakerAllocation[1] = *hdmiEDIDData++; + pInfo->nSpeakerAllocation[2] = *hdmiEDIDData++; + + updateChannelMap(pInfo); + updateChannelAllocation(pInfo); + updateChannelMapLPASS(pInfo); + + for (int i = 0; i < pInfo->nAudioBlocks; i++) { + ALOGV("AUDIO DESC BLOCK # %d\n",i); + + pInfo->AudioBlocksArray[i].nChannels = channels[i]; + ALOGV("pInfo->AudioBlocksArray[i].nChannels %d\n", pInfo->AudioBlocksArray[i].nChannels); + + ALOGV("Format Byte %d\n", formats[i]); + pInfo->AudioBlocksArray[i].nFormatId = (EDID_AUDIO_FORMAT_ID)printFormatFromEDID(formats[i]); + ALOGV("pInfo->AudioBlocksArray[i].nFormatId %d",pInfo->AudioBlocksArray[i].nFormatId); + + ALOGV("Frequency Byte %d\n", frequency[i]); + pInfo->AudioBlocksArray[i].nSamplingFreq = getSamplingFrequencyFromEDID(frequency[i]); + ALOGV("pInfo->AudioBlocksArray[i].nSamplingFreq %d",pInfo->AudioBlocksArray[i].nSamplingFreq); + + ALOGV("BitsPerSample Byte %d\n", bitrate[i]); + pInfo->AudioBlocksArray[i].nBitsPerSample = getBitsPerSampleFromEDID(bitrate[i],formats[i]); + ALOGV("pInfo->AudioBlocksArray[i].nBitsPerSample %d",pInfo->AudioBlocksArray[i].nBitsPerSample); + } + printSpeakerAllocation(pInfo); + return true; + } else { + ALOGE("No valid EDID"); + return false; + } +} + bool AudioUtil::getSpeakerAllocation(EDID_AUDIO_INFO* pInfo) { int count = 0; bool bRet = false; @@ -277,3 +339,401 @@ bool AudioUtil::getSpeakerAllocation(EDID_AUDIO_INFO* pInfo) { free(original_data_ptr); return bRet; } + +void AudioUtil::updateChannelMap(EDID_AUDIO_INFO* pInfo) +{ + if(pInfo) { + memset(pInfo->channelMap, 0, MAX_CHANNELS_SUPPORTED); + if(pInfo->nSpeakerAllocation[0] & BIT(0)) { + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + } + if(pInfo->nSpeakerAllocation[0] & BIT(1)) { + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + } + if(pInfo->nSpeakerAllocation[0] & BIT(2)) { + pInfo->channelMap[3] = PCM_CHANNEL_FC; + } + if(pInfo->nSpeakerAllocation[0] & BIT(3)) { + pInfo->channelMap[4] = PCM_CHANNEL_LB; + pInfo->channelMap[5] = PCM_CHANNEL_RB; + } + if(pInfo->nSpeakerAllocation[0] & BIT(4)) { + if(pInfo->nSpeakerAllocation[0] & BIT(3)) { + pInfo->channelMap[6] = PCM_CHANNEL_CS; + pInfo->channelMap[7] = 0; + } else if (pInfo->nSpeakerAllocation[1] & BIT(1)) { + pInfo->channelMap[6] = PCM_CHANNEL_CS; + pInfo->channelMap[7] = PCM_CHANNEL_TS; + } else if (pInfo->nSpeakerAllocation[1] & BIT(2)) { + pInfo->channelMap[6] = PCM_CHANNEL_CS; + pInfo->channelMap[7] = PCM_CHANNEL_CVH; + } else { + pInfo->channelMap[4] = PCM_CHANNEL_CS; + pInfo->channelMap[5] = 0; + } + } + if(pInfo->nSpeakerAllocation[0] & BIT(5)) { + pInfo->channelMap[6] = PCM_CHANNEL_FLC; + pInfo->channelMap[7] = PCM_CHANNEL_FRC; + } + if(pInfo->nSpeakerAllocation[0] & BIT(6)) { + pInfo->nSpeakerAllocation[0] &= 0xef; + // If RLC/RRC is present, RC is invalid as per specification + pInfo->channelMap[6] = PCM_CHANNEL_RLC; + pInfo->channelMap[7] = PCM_CHANNEL_RRC; + } + if(pInfo->nSpeakerAllocation[0] & BIT(7)) { + pInfo->channelMap[6] = 0; // PCM_CHANNEL_FLW; but not defined by LPASS + pInfo->channelMap[7] = 0; // PCM_CHANNEL_FRW; but not defined by LPASS + } + if(pInfo->nSpeakerAllocation[1] & BIT(0)) { + pInfo->channelMap[6] = 0; // PCM_CHANNEL_FLH; but not defined by LPASS + pInfo->channelMap[7] = 0; // PCM_CHANNEL_FRH; but not defined by LPASS + } + } +} + +void AudioUtil::printSpeakerAllocation(EDID_AUDIO_INFO* pInfo) { + if(pInfo) { + if (pInfo->nSpeakerAllocation[0] & BIT(7)) + ALOGV("FLW/FRW"); + if (pInfo->nSpeakerAllocation[0] & BIT(6)) + ALOGV("RLC/RRC"); + if (pInfo->nSpeakerAllocation[0] & BIT(5)) + ALOGV("FLC/FRC"); + if (pInfo->nSpeakerAllocation[0] & BIT(4)) + ALOGV("RC"); + if (pInfo->nSpeakerAllocation[0] & BIT(3)) + ALOGV("RL/RR"); + if (pInfo->nSpeakerAllocation[0] & BIT(2)) + ALOGV("FC"); + if (pInfo->nSpeakerAllocation[0] & BIT(1)) + ALOGV("LFE"); + if (pInfo->nSpeakerAllocation[0] & BIT(0)) + ALOGV("FL/FR"); + + if (pInfo->nSpeakerAllocation[1] & BIT(2)) + ALOGV("FCH"); + if (pInfo->nSpeakerAllocation[1] & BIT(1)) + ALOGV("TC"); + if (pInfo->nSpeakerAllocation[1] & BIT(0)) + ALOGV("FLH/FRH"); + } +} + +void AudioUtil::updateChannelAllocation(EDID_AUDIO_INFO* pInfo) +{ + if(pInfo) { + int16_t ca = 0; + int16_t spkAlloc = ((pInfo->nSpeakerAllocation[1]) << 8) | + (pInfo->nSpeakerAllocation[0]); + ALOGV("pInfo->nSpeakerAllocation %x %x\n", pInfo->nSpeakerAllocation[0], + pInfo->nSpeakerAllocation[1]); + ALOGV("spkAlloc: %x", spkAlloc); + + switch(spkAlloc) { + case (BIT(0)): ca = 0x00; break; + case (BIT(0)|BIT(1)): ca = 0x01; break; + case (BIT(0)|BIT(2)): ca = 0x02; break; + case (BIT(0)|BIT(1)|BIT(2)): ca = 0x03; break; + case (BIT(0)|BIT(4)): ca = 0x04; break; + case (BIT(0)|BIT(1)|BIT(4)): ca = 0x05; break; + case (BIT(0)|BIT(2)|BIT(4)): ca = 0x06; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(4)): ca = 0x07; break; + case (BIT(0)|BIT(3)): ca = 0x08; break; + case (BIT(0)|BIT(1)|BIT(3)): ca = 0x09; break; + case (BIT(0)|BIT(2)|BIT(3)): ca = 0x0A; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)): ca = 0x0B; break; + case (BIT(0)|BIT(3)|BIT(4)): ca = 0x0C; break; + case (BIT(0)|BIT(1)|BIT(3)|BIT(4)): ca = 0x0D; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(4)): ca = 0x0E; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)): ca = 0x0F; break; + case (BIT(0)|BIT(3)|BIT(6)): ca = 0x10; break; + case (BIT(0)|BIT(1)|BIT(3)|BIT(6)): ca = 0x11; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(6)): ca = 0x12; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(6)): ca = 0x13; break; + case (BIT(0)|BIT(5)): ca = 0x14; break; + case (BIT(0)|BIT(1)|BIT(5)): ca = 0x15; break; + case (BIT(0)|BIT(2)|BIT(5)): ca = 0x16; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(5)): ca = 0x17; break; + case (BIT(0)|BIT(4)|BIT(5)): ca = 0x18; break; + case (BIT(0)|BIT(1)|BIT(4)|BIT(5)): ca = 0x19; break; + case (BIT(0)|BIT(2)|BIT(4)|BIT(5)): ca = 0x1A; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(4)|BIT(5)): ca = 0x1B; break; + case (BIT(0)|BIT(3)|BIT(5)): ca = 0x1C; break; + case (BIT(0)|BIT(1)|BIT(3)|BIT(5)): ca = 0x1D; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(5)): ca = 0x1E; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(5)): ca = 0x1F; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(10)): ca = 0x20; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(10)): ca = 0x21; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(9)): ca = 0x22; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(9)): ca = 0x23; break; + case (BIT(0)|BIT(3)|BIT(8)): ca = 0x24; break; + case (BIT(0)|BIT(1)|BIT(3)|BIT(8)): ca = 0x25; break; + case (BIT(0)|BIT(3)|BIT(7)): ca = 0x26; break; + case (BIT(0)|BIT(1)|BIT(3)|BIT(7)): ca = 0x27; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(4)|BIT(9)): ca = 0x28; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(9)): ca = 0x29; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(4)|BIT(10)): ca = 0x2A; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(10)): ca = 0x2B; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(9)|BIT(10)): ca = 0x2C; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(9)|BIT(10)): ca = 0x2D; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(8)): ca = 0x2E; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(8)): ca = 0x2F; break; + case (BIT(0)|BIT(2)|BIT(3)|BIT(7)): ca = 0x30; break; + case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(7)): ca = 0x31; break; + default: ca = 0x0; break; + } + ALOGV("channel Allocation: %x", ca); + pInfo->channelAllocation = ca; + } +} + +void AudioUtil::updateChannelMapLPASS(EDID_AUDIO_INFO* pInfo) +{ + if(pInfo) { + if(pInfo->channelAllocation <= 0x1f) + memset(pInfo->channelMap, 0, MAX_CHANNELS_SUPPORTED); + switch(pInfo->channelAllocation) { + case 0x0: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + break; + case 0x1: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + break; + case 0x2: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + break; + case 0x3: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + break; + case 0x4: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_CS; + break; + case 0x5: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_CS; + break; + case 0x6: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_CS; + break; + case 0x7: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_CS; + break; + case 0x8: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LB; + pInfo->channelMap[3] = PCM_CHANNEL_RB; + break; + case 0x9: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + break; + case 0xa: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + break; + case 0xb: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_LB; + pInfo->channelMap[5] = PCM_CHANNEL_RB; + break; + case 0xc: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LB; + pInfo->channelMap[3] = PCM_CHANNEL_RB; + pInfo->channelMap[4] = PCM_CHANNEL_CS; + break; + case 0xd: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + pInfo->channelMap[5] = PCM_CHANNEL_CS; + break; + case 0xe: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + pInfo->channelMap[5] = PCM_CHANNEL_CS; + break; + case 0xf: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_LB; + pInfo->channelMap[5] = PCM_CHANNEL_RB; + pInfo->channelMap[6] = PCM_CHANNEL_CS; + break; + case 0x10: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LB; + pInfo->channelMap[3] = PCM_CHANNEL_RB; + pInfo->channelMap[4] = PCM_CHANNEL_RLC; + pInfo->channelMap[5] = PCM_CHANNEL_RRC; + break; + case 0x11: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + pInfo->channelMap[5] = PCM_CHANNEL_RLC; + pInfo->channelMap[6] = PCM_CHANNEL_RRC; + break; + case 0x12: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + pInfo->channelMap[5] = PCM_CHANNEL_RLC; + pInfo->channelMap[6] = PCM_CHANNEL_RRC; + break; + case 0x13: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_LB; + pInfo->channelMap[5] = PCM_CHANNEL_RB; + pInfo->channelMap[6] = PCM_CHANNEL_RLC; + pInfo->channelMap[7] = PCM_CHANNEL_RRC; + break; + case 0x14: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FLC; + pInfo->channelMap[3] = PCM_CHANNEL_FRC; + break; + case 0x15: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FLC; + pInfo->channelMap[4] = PCM_CHANNEL_FRC; + break; + case 0x16: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_FLC; + pInfo->channelMap[4] = PCM_CHANNEL_FRC; + break; + case 0x17: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_FLC; + pInfo->channelMap[5] = PCM_CHANNEL_FRC; + break; + case 0x18: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_CS; + pInfo->channelMap[3] = PCM_CHANNEL_FLC; + pInfo->channelMap[4] = PCM_CHANNEL_FRC; + break; + case 0x19: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_CS; + pInfo->channelMap[4] = PCM_CHANNEL_FLC; + pInfo->channelMap[5] = PCM_CHANNEL_FRC; + break; + case 0x1a: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_CS; + pInfo->channelMap[4] = PCM_CHANNEL_FLC; + pInfo->channelMap[5] = PCM_CHANNEL_FRC; + break; + case 0x1b: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_CS; + pInfo->channelMap[5] = PCM_CHANNEL_FLC; + pInfo->channelMap[6] = PCM_CHANNEL_FRC; + break; + case 0x1c: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LB; + pInfo->channelMap[3] = PCM_CHANNEL_RB; + pInfo->channelMap[4] = PCM_CHANNEL_FLC; + pInfo->channelMap[5] = PCM_CHANNEL_FRC; + break; + case 0x1d: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + pInfo->channelMap[5] = PCM_CHANNEL_FLC; + pInfo->channelMap[6] = PCM_CHANNEL_FRC; + break; + case 0x1e: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_FC; + pInfo->channelMap[3] = PCM_CHANNEL_LB; + pInfo->channelMap[4] = PCM_CHANNEL_RB; + pInfo->channelMap[5] = PCM_CHANNEL_FLC; + pInfo->channelMap[6] = PCM_CHANNEL_FRC; + break; + case 0x1f: + pInfo->channelMap[0] = PCM_CHANNEL_FL; + pInfo->channelMap[1] = PCM_CHANNEL_FR; + pInfo->channelMap[2] = PCM_CHANNEL_LFE; + pInfo->channelMap[3] = PCM_CHANNEL_FC; + pInfo->channelMap[4] = PCM_CHANNEL_LB; + pInfo->channelMap[5] = PCM_CHANNEL_RB; + pInfo->channelMap[6] = PCM_CHANNEL_FLC; + pInfo->channelMap[7] = PCM_CHANNEL_FRC; + break; + default: + break; + } + } +} diff --git a/legacy/alsa_sound/AudioUtil.h b/legacy/alsa_sound/AudioUtil.h index 6575315de..4799c2e0e 100644 --- a/legacy/alsa_sound/AudioUtil.h +++ b/legacy/alsa_sound/AudioUtil.h @@ -1,6 +1,8 @@ /* AudioUtil.h * * Copyright (C) 2012 The Android Open Source Project + * Copyright (c) 2012-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. @@ -23,6 +25,40 @@ #define MAX_SHORT_AUDIO_DESC_CNT 30 #define MIN_AUDIO_DESC_LENGTH 3 #define MIN_SPKR_ALLOCATION_DATA_LENGTH 3 +#define MAX_CHANNELS_SUPPORTED 8 + +/* Front left channel. */ +#define PCM_CHANNEL_FL 1 +/* Front right channel. */ +#define PCM_CHANNEL_FR 2 +/* Front center channel. */ +#define PCM_CHANNEL_FC 3 +/* Left surround channel.*/ +#define PCM_CHANNEL_LS 4 +/* Right surround channel.*/ +#define PCM_CHANNEL_RS 5 +/* Low frequency effect channel. */ +#define PCM_CHANNEL_LFE 6 +/* Center surround channel; Rear center channel. */ +#define PCM_CHANNEL_CS 7 +/* Left back channel; Rear left channel. */ +#define PCM_CHANNEL_LB 8 +/* Right back channel; Rear right channel. */ +#define PCM_CHANNEL_RB 9 +/* Top surround channel. */ +#define PCM_CHANNEL_TS 10 +/* Center vertical height channel.*/ +#define PCM_CHANNEL_CVH 11 +/* Mono surround channel.*/ +#define PCM_CHANNEL_MS 12 +/* Front left of center. */ +#define PCM_CHANNEL_FLC 13 +/* Front right of center. */ +#define PCM_CHANNEL_FRC 14 +/* Rear left of center. */ +#define PCM_CHANNEL_RLC 15 +/* Rear right of center. */ +#define PCM_CHANNEL_RRC 16 typedef enum EDID_AUDIO_FORMAT_ID { LPCM = 1, @@ -52,6 +88,8 @@ typedef struct EDID_AUDIO_INFO { int nAudioBlocks; unsigned char nSpeakerAllocation[MIN_SPKR_ALLOCATION_DATA_LENGTH]; EDID_AUDIO_BLOCK_INFO AudioBlocksArray[MAX_EDID_BLOCKS]; + char channelMap[MAX_CHANNELS_SUPPORTED]; + int channelAllocation; } EDID_AUDIO_INFO; class AudioUtil { @@ -59,13 +97,18 @@ public: //Parses EDID audio block when if HDMI is connected to determine audio sink capabilities. static bool getHDMIAudioSinkCaps(EDID_AUDIO_INFO*); + static bool getHDMIAudioSinkCaps(EDID_AUDIO_INFO*, char *hdmiEDIDData); private: static int printFormatFromEDID(unsigned char format); static int getSamplingFrequencyFromEDID(unsigned char byte); static int getBitsPerSampleFromEDID(unsigned char byte, - unsigned char format); + unsigned char format); static bool getSpeakerAllocation(EDID_AUDIO_INFO* pInfo); + static void updateChannelMap(EDID_AUDIO_INFO* pInfo); + static void updateChannelMapLPASS(EDID_AUDIO_INFO* pInfo); + static void updateChannelAllocation(EDID_AUDIO_INFO* pInfo); + static void printSpeakerAllocation(EDID_AUDIO_INFO* pInfo); }; #endif /* ALSA_SOUND_AUDIO_UTIL_H */ diff --git a/legacy/alsa_sound/alsa_default.cpp b/legacy/alsa_sound/alsa_default.cpp deleted file mode 100644 index 2f043bb57..000000000 --- a/legacy/alsa_sound/alsa_default.cpp +++ /dev/null @@ -1,1833 +0,0 @@ -/* alsa_default.cpp - ** - ** Copyright 2009 Wind River Systems - ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. - ** - ** 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 "ALSAModule" -//#define LOG_NDEBUG 0 -#define LOG_NDDEBUG 0 -#include -#include -#include -#include "AudioUtil.h" -#include "AudioHardwareALSA.h" -#include -#include -#ifdef QCOM_CSDCLIENT_ENABLED -extern "C" { -static int (*csd_disable_device)(); -static int (*csd_enable_device)(int, int, uint32_t); -static int (*csd_volume)(int); -static int (*csd_mic_mute)(int); -static int (*csd_wide_voice)(uint8_t); -static int (*csd_slow_talk)(uint8_t); -static int (*csd_fens)(uint8_t); -static int (*csd_start_voice)(); -static int (*csd_stop_voice)(); -} -#endif - -#ifndef ALSA_DEFAULT_SAMPLE_RATE -#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz -#endif - -#define BTSCO_RATE_16KHZ 16000 -#define USECASE_TYPE_RX 1 -#define USECASE_TYPE_TX 2 -#define MAX_HDMI_CHANNEL_CNT 6 - -namespace android_audio_legacy -{ - -static int s_device_open(const hw_module_t*, const char*, hw_device_t**); -static int s_device_close(hw_device_t*); -static status_t s_init(alsa_device_t *, ALSAHandleList &); -static status_t s_open(alsa_handle_t *); -static status_t s_close(alsa_handle_t *); -static status_t s_standby(alsa_handle_t *); -static status_t s_route(alsa_handle_t *, uint32_t, int); -static status_t s_start_voice_call(alsa_handle_t *); -static status_t s_start_voip_call(alsa_handle_t *); -static status_t s_start_fm(alsa_handle_t *); -static void s_set_voice_volume(int); -static void s_set_voip_volume(int); -static void s_set_mic_mute(int); -static void s_set_voip_mic_mute(int); -static void s_set_voip_config(int, int); -static status_t s_set_fm_vol(int); -static void s_set_btsco_rate(int); -static status_t s_set_lpa_vol(int); -static void s_enable_wide_voice(bool flag); -static void s_enable_fens(bool flag); -static void s_set_flags(uint32_t flags); -static status_t s_set_compressed_vol(int); -static void s_enable_slow_talk(bool flag); -static void s_set_voc_rec_mode(uint8_t mode); -static void s_set_volte_mic_mute(int state); -static void s_set_volte_volume(int vol); -static bool s_is_tmus(); -#ifdef SEPERATED_AUDIO_INPUT -static void s_setInput(int); - -static int input_source; -#endif -static int mccmnc; -#ifdef QCOM_CSDCLIENT_ENABLED -static void s_set_csd_handle(void*); -#endif - -static char mic_type[25]; -static char curRxUCMDevice[50]; -static char curTxUCMDevice[50]; -static int fluence_mode; -static int fmVolume; -#ifdef USES_FLUENCE_INCALL -static uint32_t mDevSettingsFlag = TTY_OFF | DMIC_FLAG; -#else -static uint32_t mDevSettingsFlag = TTY_OFF; -#endif -static int btsco_samplerate = 8000; -static ALSAUseCaseList mUseCaseList; -static void *csd_handle; - -static hw_module_methods_t s_module_methods = { - open : s_device_open -}; - -extern "C" { -hw_module_t HAL_MODULE_INFO_SYM = { - tag : HARDWARE_MODULE_TAG, - version_major : 1, - version_minor : 0, - id : ALSA_HARDWARE_MODULE_ID, - name : "QCOM ALSA module", - author : "QuIC Inc", - methods : &s_module_methods, - dso : 0, - reserved : {0,}, -}; -} - -static int s_device_open(const hw_module_t* module, const char* name, - hw_device_t** device) -{ - char value[128]; - alsa_device_t *dev; - dev = (alsa_device_t *) malloc(sizeof(*dev)); - if (!dev) return -ENOMEM; - - memset(dev, 0, sizeof(*dev)); - - /* initialize the procs */ - dev->common.tag = HARDWARE_DEVICE_TAG; - dev->common.version = 0; - dev->common.module = (hw_module_t *) module; - dev->common.close = s_device_close; - dev->init = s_init; - dev->open = s_open; - dev->close = s_close; - dev->route = s_route; - dev->standby = s_standby; - dev->startVoiceCall = s_start_voice_call; - dev->startVoipCall = s_start_voip_call; - dev->startFm = s_start_fm; - dev->setVoiceVolume = s_set_voice_volume; - dev->setVoipVolume = s_set_voip_volume; - dev->setMicMute = s_set_mic_mute; - dev->setVoipMicMute = s_set_voip_mic_mute; - dev->setVoipConfig = s_set_voip_config; - dev->setFmVolume = s_set_fm_vol; - dev->setBtscoRate = s_set_btsco_rate; - dev->setLpaVolume = s_set_lpa_vol; - dev->enableWideVoice = s_enable_wide_voice; - dev->enableFENS = s_enable_fens; - dev->setFlags = s_set_flags; - dev->setCompressedVolume = s_set_compressed_vol; - dev->enableSlowTalk = s_enable_slow_talk; - dev->setVocRecMode = s_set_voc_rec_mode; - dev->setVoLTEMicMute = s_set_volte_mic_mute; - dev->setVoLTEVolume = s_set_volte_volume; -#ifdef SEPERATED_AUDIO_INPUT - dev->setInput = s_setInput; -#endif -#ifdef QCOM_CSDCLIENT_ENABLED - dev->setCsdHandle = s_set_csd_handle; -#endif - *device = &dev->common; - - property_get("persist.audio.handset.mic",value,"0"); - strlcpy(mic_type, value, sizeof(mic_type)); - property_get("persist.audio.fluence.mode",value,"0"); - if (!strcmp("broadside", value)) { - fluence_mode = FLUENCE_MODE_BROADSIDE; - } else { - fluence_mode = FLUENCE_MODE_ENDFIRE; - } - strlcpy(curRxUCMDevice, "None", sizeof(curRxUCMDevice)); - strlcpy(curTxUCMDevice, "None", sizeof(curTxUCMDevice)); - ALOGV("ALSA module opened"); - - return 0; -} - -static int s_device_close(hw_device_t* device) -{ - free(device); - device = NULL; - return 0; -} - -// ---------------------------------------------------------------------------- - -static const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE; - -static void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode); -static char *getUCMDevice(uint32_t devices, int input, char *rxDevice); -static void disableDevice(alsa_handle_t *handle); -int getUseCaseType(const char *useCase); - -static int callMode = AudioSystem::MODE_NORMAL; -// ---------------------------------------------------------------------------- - -bool platform_is_Fusion3() -{ - char platform[128], baseband[128]; - property_get("ro.board.platform", platform, ""); - property_get("ro.baseband", baseband, ""); - if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) - return true; - else - return false; -} - -int deviceName(alsa_handle_t *handle, unsigned flags, char **value) -{ - int ret = 0; - char ident[70]; - - if (flags & PCM_IN) { - strlcpy(ident, "CapturePCM/", sizeof(ident)); - } else { - strlcpy(ident, "PlaybackPCM/", sizeof(ident)); - } - strlcat(ident, handle->useCase, sizeof(ident)); - ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value); - ALOGD("Device value returned is %s", (*value)); - return ret; -} - -status_t setHDMIChannelCount() -{ - status_t err = NO_ERROR; - int channel_count = 0; - const char *channel_cnt_str = NULL; - EDID_AUDIO_INFO info = { 0 }; - - ALSAControl control("/dev/snd/controlC0"); - if (AudioUtil::getHDMIAudioSinkCaps(&info)) { - for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) { - if (info.AudioBlocksArray[i].nChannels > channel_count && - info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) { - channel_count = info.AudioBlocksArray[i].nChannels; - } - } - } - - switch (channel_count) { - 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; - } - ALOGD("HDMI channel count: %s", channel_cnt_str); - control.set("HDMI_RX Channels", channel_cnt_str); - - return err; -} - -status_t setHardwareParams(alsa_handle_t *handle) -{ - struct snd_pcm_hw_params *params; - unsigned long bufferSize, reqBuffSize; - unsigned int periodTime, bufferTime; - unsigned int requestedRate = handle->sampleRate; - int status = 0; - int channels = handle->channels; - snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE; - - params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params)); - if (!params) { - ALOGE("Failed to allocate ALSA hardware parameters!"); - return NO_INIT; - } - - reqBuffSize = handle->bufferSize; - ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d", - (int) reqBuffSize, handle->channels, handle->sampleRate); - -#ifdef QCOM_SSR_ENABLED - if (channels == 6) { - if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) - || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { - ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase); - channels = 4; - } - } -#endif - - param_init(params); - param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS, - SNDRV_PCM_ACCESS_RW_INTERLEAVED); - if (handle->format != SNDRV_PCM_FORMAT_S16_LE) { - if (handle->format == AudioSystem::AMR_NB - || handle->format == AudioSystem::AMR_WB -#ifdef QCOM_QCHAT_ENABLED - || handle->format == AudioSystem::EVRC - || handle->format == AudioSystem::EVRCB - || handle->format == AudioSystem::EVRCWB -#endif - ) - format = SNDRV_PCM_FORMAT_SPECIAL; - } - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - format); - param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT, - SNDRV_PCM_SUBFORMAT_STD); - param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize); - param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16); - param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS, - channels * 16); - param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS, - channels); - param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate); - param_set_hw_refine(handle->handle, params); - - if (param_set_hw_params(handle->handle, params)) { - ALOGE("cannot set hw params"); - return NO_INIT; - } - param_dump(params); - - handle->handle->buffer_size = pcm_buffer_size(params); - handle->handle->period_size = pcm_period_size(params); - handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size; - ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d", - handle->handle->buffer_size, handle->handle->period_size, - handle->handle->period_cnt); - handle->handle->rate = handle->sampleRate; - handle->handle->channels = handle->channels; - handle->periodSize = handle->handle->period_size; - if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) && - strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) && - (6 != handle->channels)) { - //Do not update buffersize for 5.1 recording - handle->bufferSize = handle->handle->period_size; - } - - return NO_ERROR; -} - -status_t setSoftwareParams(alsa_handle_t *handle) -{ - struct snd_pcm_sw_params* params; - struct pcm* pcm = handle->handle; - - unsigned long periodSize = pcm->period_size; - int channels = handle->channels; - - params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params)); - if (!params) { - LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!"); - return NO_INIT; - } - -#ifdef QCOM_SSR_ENABLED - if (channels == 6) { - if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) - || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { - ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase); - channels = 4; - } - } -#endif - - // Get the current software parameters - params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; - params->period_step = 1; - if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) || - (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){ - ALOGV("setparam: start & stop threshold for Voip "); - params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2; - params->start_threshold = periodSize/2; - params->stop_threshold = INT_MAX; - } else { - params->avail_min = periodSize/(channels * 2); - params->start_threshold = periodSize/(channels * 2); - params->stop_threshold = INT_MAX; - } - params->silence_threshold = 0; - params->silence_size = 0; - - if (param_set_sw_params(handle->handle, params)) { - ALOGE("cannot set sw params"); - return NO_INIT; - } - return NO_ERROR; -} - -void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode) -{ - const char **mods_list; - use_case_t useCaseNode; - unsigned usecase_type = 0; - bool inCallDevSwitch = false; - char *rxDevice, *txDevice, ident[70], *use_case = NULL; - int err = 0, index, mods_size; - int rx_dev_id, tx_dev_id; - ALOGD("%s: device %d mode:%d", __FUNCTION__, devices, mode); - - if ((mode == AudioSystem::MODE_IN_CALL) || (mode == AudioSystem::MODE_IN_COMMUNICATION)) { - if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || - (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) { - devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET | - AudioSystem::DEVICE_IN_WIRED_HEADSET); - } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) { - devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE | - AudioSystem::DEVICE_IN_BUILTIN_MIC); - } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) { - if (mode == AudioSystem::MODE_IN_CALL) { - devices |= AudioSystem::DEVICE_OUT_EARPIECE; - } else if (mode == AudioSystem::MODE_IN_COMMUNICATION) { - if (!strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, MAX_LEN(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER))) { - devices &= ~AudioSystem::DEVICE_IN_BUILTIN_MIC; - devices |= AudioSystem::DEVICE_IN_BACK_MIC; - } - } - } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) { - devices = devices | AudioSystem::DEVICE_IN_BUILTIN_MIC; - } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) { - devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC | - AudioSystem::DEVICE_OUT_SPEAKER); - } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) || - (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) || - (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) { - devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AudioSystem::DEVICE_OUT_BLUETOOTH_SCO); -#ifdef QCOM_ANC_HEADSET_ENABLED - } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || - (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) { - devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET | - AudioSystem::DEVICE_IN_ANC_HEADSET); - } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) { - devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE | - AudioSystem::DEVICE_IN_BUILTIN_MIC); -#endif - } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) { - if (mode == AudioSystem::MODE_IN_CALL) - devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC | - AudioSystem::DEVICE_OUT_SPEAKER); - else - devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL | - AudioSystem::DEVICE_IN_BACK_MIC); -#ifdef QCOM_PROXY_DEVICE_ENABLED - } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) || - (devices & AudioSystem::DEVICE_IN_PROXY)) { - devices = devices | (AudioSystem::DEVICE_OUT_PROXY | - AudioSystem::DEVICE_IN_PROXY); -#endif - } - } -#ifdef QCOM_SSR_ENABLED - if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) { - if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) - || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { - ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase); - s_set_flags(SSRQMIC_FLAG); - } - } -#endif - - rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL); - txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice); - - if ((rxDevice != NULL) && (txDevice != NULL)) { - if (((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) || - (strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN))) && - ((mode == AudioSystem::MODE_IN_CALL) || - (mode == AudioSystem::MODE_IN_COMMUNICATION))) - inCallDevSwitch = true; - } - -#ifdef QCOM_CSDCLIENT_ENABLED - if (platform_is_Fusion3() && (inCallDevSwitch == true)) { - if (csd_disable_device == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror()); - } else { - err = csd_disable_device(); - if (err < 0) - { - ALOGE("csd_client_disable_device, failed, error %d", err); - } - } - } -#endif - - snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case); - mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list); - if (rxDevice != NULL) { - if ((strncmp(curRxUCMDevice, "None", 4)) && - ((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) { - if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, - strlen(SND_USE_CASE_VERB_INACTIVE)))) { - usecase_type = getUseCaseType(use_case); - if (usecase_type & USECASE_TYPE_RX) { - ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type); - strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN); - snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE); - mUseCaseList.push_front(useCaseNode); - } - } - if (mods_size) { - for(index = 0; index < mods_size; index++) { - usecase_type = getUseCaseType(mods_list[index]); - if (usecase_type & USECASE_TYPE_RX) { - ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type); - strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN); - snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]); - mUseCaseList.push_back(useCaseNode); - } - } - } - snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice); - } - } - if (txDevice != NULL) { - if ((strncmp(curTxUCMDevice, "None", 4)) && - ((strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) { - if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, - strlen(SND_USE_CASE_VERB_INACTIVE)))) { - usecase_type = getUseCaseType(use_case); - if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) { - ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type); - strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN); - snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE); - mUseCaseList.push_front(useCaseNode); - } - } - if (mods_size) { - for(index = 0; index < mods_size; index++) { - usecase_type = getUseCaseType(mods_list[index]); - if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) { - ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type); - strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN); - snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]); - mUseCaseList.push_back(useCaseNode); - } - } - } - snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice); - } - } - ALOGD("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, curRxUCMDevice, curTxUCMDevice); - - if (rxDevice != NULL) { - snd_use_case_set(handle->ucMgr, "_enadev", rxDevice); - strlcpy(curRxUCMDevice, rxDevice, sizeof(curRxUCMDevice)); -#ifdef QCOM_FM_ENABLED - if (devices & AudioSystem::DEVICE_OUT_FM) - s_set_fm_vol(fmVolume); -#endif - } - if (txDevice != NULL) { - snd_use_case_set(handle->ucMgr, "_enadev", txDevice); - strlcpy(curTxUCMDevice, txDevice, sizeof(curTxUCMDevice)); - } - for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) { - ALOGD("Route use case %s\n", it->useCase); - if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE, - strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) { - snd_use_case_set(handle->ucMgr, "_verb", it->useCase); - } else { - snd_use_case_set(handle->ucMgr, "_enamod", it->useCase); - } - } - if (!mUseCaseList.empty()) - mUseCaseList.clear(); - if (use_case != NULL) { - free(use_case); - use_case = NULL; - } - ALOGD("switchDevice: curTxUCMDevivce %s curRxDevDevice %s", curTxUCMDevice, curRxUCMDevice); - - if (platform_is_Fusion3() && (inCallDevSwitch == true)) { - /* get tx acdb id */ - memset(&ident,0,sizeof(ident)); - strlcpy(ident, "ACDBID/", sizeof(ident)); - strlcat(ident, curTxUCMDevice, sizeof(ident)); - tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL); - - /* get rx acdb id */ - memset(&ident,0,sizeof(ident)); - strlcpy(ident, "ACDBID/", sizeof(ident)); - strlcat(ident, curRxUCMDevice, sizeof(ident)); - rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL); - - if (((rx_dev_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID ) || (rx_dev_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID )) - && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) { - tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID; - } - -#ifdef QCOM_CSDCLIENT_ENABLED - ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id); - if (csd_enable_device == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_enable_device", dlerror()); - } else { - err = csd_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag); - if (err < 0) - { - ALOGE("csd_client_disable_device failed, error %d", err); - } - } -#endif - } - - if (rxDevice != NULL) { - free(rxDevice); - rxDevice = NULL; - } - if (txDevice != NULL) { - free(txDevice); - txDevice = NULL; - } -} - -// ---------------------------------------------------------------------------- - -static status_t s_init(alsa_device_t *module, ALSAHandleList &list) -{ - ALOGV("s_init: Initializing devices for ALSA module"); - - list.clear(); - - return NO_ERROR; -} - -static status_t s_open(alsa_handle_t *handle) -{ - char *devName; - unsigned flags = 0; - int err = NO_ERROR; - - if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) { - err = setHDMIChannelCount(); - if(err != OK) { - ALOGE("setHDMIChannelCount err = %d", err); - return err; - } - } - /* No need to call s_close for LPA as pcm device open and close is handled by LPAPlayer in stagefright */ - if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) - ||(!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { - ALOGV("s_open: Opening LPA /Tunnel playback"); - return NO_ERROR; - } - - s_close(handle); - - ALOGV("s_open: handle %p", handle); - - // ASoC multicomponent requires a valid path (frontend/backend) for - // the device to be opened - - // The PCM stream is opened in blocking mode, per ALSA defaults. The - // AudioFlinger seems to assume blocking mode too, so asynchronous mode - // should not be used. - if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) || - (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { - ALOGV("LPA/tunnel use case"); - flags |= PCM_MMAP; - flags |= DEBUG_ON; - } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) || - (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) || - (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) { - ALOGV("Music case"); - flags = PCM_OUT; - } else { - flags = PCM_IN; - } - if (handle->channels == 1) { - flags |= PCM_MONO; - } - else if (handle->channels == 4 ) { - flags |= PCM_QUAD; - } else if (handle->channels == 6 ) { -#ifdef QCOM_SSR_ENABLED - if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) - || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { - flags |= PCM_QUAD; - } else { - flags |= PCM_5POINT1; - } -#else - flags |= PCM_5POINT1; -#endif - } - else { - flags |= PCM_STEREO; - } - if (deviceName(handle, flags, &devName) < 0) { - ALOGE("Failed to get pcm device node: %s", devName); - return NO_INIT; - } - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - - if (!handle->handle) { - ALOGE("s_open: Failed to initialize ALSA device '%s'", devName); - free(devName); - return NO_INIT; - } - - handle->handle->flags = flags; - err = setHardwareParams(handle); - - if (err == NO_ERROR) { - err = setSoftwareParams(handle); - } - - if(err != NO_ERROR) { - ALOGE("Set HW/SW params failed: Closing the pcm stream"); - s_standby(handle); - } - - free(devName); - return NO_ERROR; -} - -static status_t s_start_voip_call(alsa_handle_t *handle) -{ - - char* devName; - char* devName1; - unsigned flags = 0; - int err = NO_ERROR; - uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE]; - - s_close(handle); - flags = PCM_OUT; - flags |= PCM_MONO; - ALOGV("s_open:s_start_voip_call handle %p", handle); - - if (deviceName(handle, flags, &devName) < 0) { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - - if (!handle->handle) { - free(devName); - ALOGE("s_open: Failed to initialize ALSA device '%s'", devName); - return NO_INIT; - } - - if (!pcm_ready(handle->handle)) { - ALOGE(" pcm ready failed"); - } - - handle->handle->flags = flags; - err = setHardwareParams(handle); - - if (err == NO_ERROR) { - err = setSoftwareParams(handle); - } - - err = pcm_prepare(handle->handle); - if(err != NO_ERROR) { - ALOGE("DEVICE_OUT_DIRECTOUTPUT: pcm_prepare failed"); - } - - /* first write required start dsp */ - memset(&voc_pkt,0,sizeof(voc_pkt)); - pcm_write(handle->handle,&voc_pkt,handle->handle->period_size); - handle->rxHandle = handle->handle; - free(devName); - ALOGV("s_open: DEVICE_IN_COMMUNICATION "); - flags = PCM_IN; - flags |= PCM_MONO; - handle->handle = 0; - - if (deviceName(handle, flags, &devName1) < 0) { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName1); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - - if (!handle->handle) { - free(devName); - ALOGE("s_open: Failed to initialize ALSA device '%s'", devName); - return NO_INIT; - } - - if (!pcm_ready(handle->handle)) { - ALOGE(" pcm ready in failed"); - } - - handle->handle->flags = flags; - - err = setHardwareParams(handle); - - if (err == NO_ERROR) { - err = setSoftwareParams(handle); - } - - - err = pcm_prepare(handle->handle); - if(err != NO_ERROR) { - ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed"); - } - - /* first read required start dsp */ - memset(&voc_pkt,0,sizeof(voc_pkt)); - pcm_read(handle->handle,&voc_pkt,handle->handle->period_size); - return NO_ERROR; -} - -static status_t s_start_voice_call(alsa_handle_t *handle) -{ - char* devName; - unsigned flags = 0; - int err = NO_ERROR; - - ALOGV("s_start_voice_call: handle %p", handle); - - // ASoC multicomponent requires a valid path (frontend/backend) for - // the device to be opened - - flags = PCM_OUT | PCM_MONO; - if (deviceName(handle, flags, &devName) < 0) { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - if (!handle->handle) { - ALOGE("s_start_voicecall: could not open PCM device"); - goto Error; - } - - handle->handle->flags = flags; - err = setHardwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_voice_call: setHardwareParams failed"); - goto Error; - } - - err = setSoftwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_voice_call: setSoftwareParams failed"); - goto Error; - } - - err = pcm_prepare(handle->handle); - if(err != NO_ERROR) { - ALOGE("s_start_voice_call: pcm_prepare failed"); - goto Error; - } - - if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { - ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n"); - goto Error; - } - - // Store the PCM playback device pointer in rxHandle - handle->rxHandle = handle->handle; - free(devName); - - // Open PCM capture device - flags = PCM_IN | PCM_MONO; - if (deviceName(handle, flags, &devName) < 0) { - ALOGE("Failed to get pcm device node"); - goto Error; - } - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - if (!handle->handle) { - free(devName); - goto Error; - } - - handle->handle->flags = flags; - err = setHardwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_voice_call: setHardwareParams failed"); - goto Error; - } - - err = setSoftwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_voice_call: setSoftwareParams failed"); - goto Error; - } - - err = pcm_prepare(handle->handle); - if(err != NO_ERROR) { - ALOGE("s_start_voice_call: pcm_prepare failed"); - goto Error; - } - - if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { - ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n"); - goto Error; - } - - if (platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_start_voice == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_start_voice", dlerror()); - } else { - err = csd_start_voice(); - if (err < 0){ - ALOGE("s_start_voice_call: csd_client error %d\n", err); - goto Error; - } - } -#endif - } - - free(devName); - return NO_ERROR; - -Error: - ALOGE("s_start_voice_call: Failed to initialize ALSA device '%s'", devName); - free(devName); - s_close(handle); - return NO_INIT; -} - -static status_t s_start_fm(alsa_handle_t *handle) -{ - char *devName; - unsigned flags = 0; - int err = NO_ERROR; - - ALOGV("s_start_fm: handle %p", handle); - - // ASoC multicomponent requires a valid path (frontend/backend) for - // the device to be opened - - flags = PCM_OUT | PCM_STEREO; - if (deviceName(handle, flags, &devName) < 0) { - ALOGE("Failed to get pcm device node"); - goto Error; - } - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - if (!handle->handle) { - ALOGE("s_start_fm: could not open PCM device"); - goto Error; - } - - handle->handle->flags = flags; - err = setHardwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_fm: setHardwareParams failed"); - goto Error; - } - - err = setSoftwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_fm: setSoftwareParams failed"); - goto Error; - } - - err = pcm_prepare(handle->handle); - if(err != NO_ERROR) { - ALOGE("s_start_fm: setSoftwareParams failed"); - goto Error; - } - - if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { - ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n"); - goto Error; - } - - // Store the PCM playback device pointer in rxHandle - handle->rxHandle = handle->handle; - free(devName); - - // Open PCM capture device - flags = PCM_IN | PCM_STEREO; - if (deviceName(handle, flags, &devName) < 0) { - ALOGE("Failed to get pcm device node"); - goto Error; - } - if (devName != NULL) { - handle->handle = pcm_open(flags, (char*)devName); - } else { - ALOGE("Failed to get pcm device node"); - return NO_INIT; - } - if (!handle->handle) { - goto Error; - } - - handle->handle->flags = flags; - err = setHardwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_fm: setHardwareParams failed"); - goto Error; - } - - err = setSoftwareParams(handle); - if(err != NO_ERROR) { - ALOGE("s_start_fm: setSoftwareParams failed"); - goto Error; - } - - err = pcm_prepare(handle->handle); - if(err != NO_ERROR) { - ALOGE("s_start_fm: pcm_prepare failed"); - goto Error; - } - - if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) { - ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n"); - goto Error; - } - - s_set_fm_vol(fmVolume); - free(devName); - return NO_ERROR; - -Error: - free(devName); - s_close(handle); - return NO_INIT; -} - -static status_t s_set_fm_vol(int value) -{ - status_t err = NO_ERROR; - - ALSAControl control("/dev/snd/controlC0"); - control.set("Internal FM RX Volume",value,0); - fmVolume = value; - - return err; -} - -static status_t s_set_lpa_vol(int value) -{ - status_t err = NO_ERROR; - - ALSAControl control("/dev/snd/controlC0"); - control.set("LPA RX Volume",value,0); - - return err; -} - -static status_t s_start(alsa_handle_t *handle) -{ - status_t err = NO_ERROR; - - if(!handle->handle) { - ALOGE("No active PCM driver to start"); - return err; - } - - err = pcm_prepare(handle->handle); - - return err; -} - -static status_t s_close(alsa_handle_t *handle) -{ - int ret; - status_t err = NO_ERROR; - struct pcm *h = handle->rxHandle; - - handle->rxHandle = 0; - ALOGV("s_close: handle %p h %p", handle, h); - if (h) { - if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) || - !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) && - platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_stop_voice == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror()); - } else { - err = csd_stop_voice(); - if (err < 0) { - ALOGE("s_close: csd_client error %d\n", err); - } - } -#endif - } - - ALOGV("s_close rxHandle\n"); - err = pcm_close(h); - if(err != NO_ERROR) { - ALOGE("s_close: pcm_close failed for rxHandle with err %d", err); - } - } - - h = handle->handle; - handle->handle = 0; - - if (h) { - ALOGV("s_close handle h %p\n", h); - err = pcm_close(h); - if(err != NO_ERROR) { - ALOGE("s_close: pcm_close failed for handle with err %d", err); - } - - disableDevice(handle); - } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) || - (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))){ - disableDevice(handle); - } - - return err; -} - -/* - this is same as s_close, but don't discard - the device/mode info. This way we can still - close the device, hit idle and power-save, reopen the pcm - for the same device/mode after resuming -*/ -static status_t s_standby(alsa_handle_t *handle) -{ - int ret; - status_t err = NO_ERROR; - struct pcm *h = handle->rxHandle; - handle->rxHandle = 0; - ALOGV("s_standby: handle %p h %p", handle, h); - if (h) { - ALOGD("s_standby rxHandle\n"); - err = pcm_close(h); - if(err != NO_ERROR) { - ALOGE("s_standby: pcm_close failed for rxHandle with err %d", err); - } - } - - h = handle->handle; - handle->handle = 0; - - if (h) { - ALOGV("s_standby handle h %p\n", h); - err = pcm_close(h); - if(err != NO_ERROR) { - ALOGE("s_standby: pcm_close failed for handle with err %d", err); - } - disableDevice(handle); - } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) || - (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || - (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) { - disableDevice(handle); - } - - return err; -} - -static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode) -{ - status_t status = NO_ERROR; - - ALOGD("s_route: devices 0x%x in mode %d", devices, mode); - callMode = mode; - switchDevice(handle, devices, mode); - return status; -} - -int getUseCaseType(const char *useCase) -{ - ALOGD("use case is %s\n", useCase); - if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) || - !strncmp(useCase, SND_USE_CASE_VERB_HIFI2, - MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) || - !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) || - !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) || - !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) || - !strncmp(useCase, SND_USE_CASE_VERB_HIFI2, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) || - !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, - MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, - MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) { - return USECASE_TYPE_RX; - } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) || - !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) || - !strncmp(useCase, SND_USE_CASE_VERB_FM_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) || - !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, - MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, - MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM, - MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, - MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) { - return USECASE_TYPE_TX; - } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL, - MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) || - !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL, - MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) || - !strncmp(useCase, SND_USE_CASE_VERB_DL_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) || - !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) || - !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC, - MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, - MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, - MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) || - !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, - MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) || - !strncmp(useCase, SND_USE_CASE_VERB_VOLTE, - MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) || - !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE, - MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) { - return (USECASE_TYPE_RX | USECASE_TYPE_TX); - } else { - ALOGE("unknown use case %s\n", useCase); - return 0; - } -} - -static void disableDevice(alsa_handle_t *handle) -{ - unsigned usecase_type = 0; - int i, mods_size; - char *useCase; - const char **mods_list; - - snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase); - if (useCase != NULL) { - if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) { - snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE); - } else { - snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase); - } - free(useCase); - snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase); - if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE, - strlen(SND_USE_CASE_VERB_INACTIVE))) - usecase_type |= getUseCaseType(useCase); - mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list); - ALOGV("Number of modifiers %d\n", mods_size); - if (mods_size) { - for(i = 0; i < mods_size; i++) { - ALOGV("index %d modifier %s\n", i, mods_list[i]); - usecase_type |= getUseCaseType(mods_list[i]); - } - } - ALOGV("usecase_type is %d\n", usecase_type); - if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(curTxUCMDevice, "None", 4))) - snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice); - if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(curRxUCMDevice, "None", 4))) - snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice); - } else { - ALOGE("Invalid state, no valid use case found to disable"); - } - free(useCase); -} - -char *getUCMDevice(uint32_t devices, int input, char *rxDevice) -{ - bool is_tmus = s_is_tmus(); - - if (!input) { - if (!(mDevSettingsFlag & TTY_OFF) && - (callMode == AudioSystem::MODE_IN_CALL) && - ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) { -#ifdef QCOM_ANC_HEADSET_ENABLED - || - (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) { -#endif - if (mDevSettingsFlag & TTY_VCO) { - return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX); - } else if (mDevSettingsFlag & TTY_FULL) { - return strdup(SND_USE_CASE_DEV_TTY_FULL_RX); - } else if (mDevSettingsFlag & TTY_HCO) { - return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */ - } - }else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) { - return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */ - } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && - ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) { - if (mDevSettingsFlag & ANC_FLAG) { - return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */ - } else { - return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */ - } - } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && - ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) { - return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER); -#ifdef QCOM_ANC_HEADSET_ENABLED - } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && - ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) { - return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */ - } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) && - (devices & AudioSystem::DEVICE_OUT_FM_TX)) { - return strdup(SND_USE_CASE_DEV_SPEAKER_FM_TX); /* COMBO SPEAKER+FM_TX RX */ -#endif - } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) { - if (callMode == AudioSystem::MODE_IN_CALL) { - if(is_tmus) - return strdup(SND_USE_CASE_DEV_VOC_EARPIECE_TMUS); /* Voice HANDSET RX for TMUS */ - else - return strdup(SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */ - } else - return strdup(SND_USE_CASE_DEV_EARPIECE); /* HANDSET RX */ - } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */ - } else - return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */ - } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) { - if (mDevSettingsFlag & ANC_FLAG) { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */ - } else - return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */ - } else { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */ - } else - return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */ - } -#ifdef QCOM_ANC_HEADSET_ENABLED - } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */ - } else - return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */ -#endif - } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) || - (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) || - (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) { - if (btsco_samplerate == BTSCO_RATE_16KHZ) - return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/ - else - return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/ - } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP) || - (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) || -#ifdef QCOM_VOIP_ENABLED - (devices & AudioSystem::DEVICE_OUT_DIRECTOUTPUT) || -#endif - (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) { - /* Nothing to be done, use current active device */ - if (strncmp(curRxUCMDevice, "None", 4)) { - return strdup(curRxUCMDevice); - } - } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) { - return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */ -#ifdef QCOM_PROXY_DEVICE_ENABLED - } else if (devices & AudioSystem::DEVICE_OUT_PROXY) { - return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */ -#endif -#ifdef QCOM_FM_TX_ENABLED - } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) { - return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */ -#endif - } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */ - } else - return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */ - } else { - ALOGD("No valid output device: %u", devices); - } - } else { - if (!(mDevSettingsFlag & TTY_OFF) && - (callMode == AudioSystem::MODE_IN_CALL) && - ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) -#ifdef QCOM_ANC_HEADSET_ENABLED - || (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) -#endif - )) { - if (mDevSettingsFlag & TTY_HCO) { - return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX); - } else if (mDevSettingsFlag & TTY_FULL) { - return strdup(SND_USE_CASE_DEV_TTY_FULL_TX); - } else if (mDevSettingsFlag & TTY_VCO) { - if (!strncmp(mic_type, "analog", 6)) { - return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX); - } else { - return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX); - } - } - } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) { - if (!strncmp(mic_type, "analog", 6)) { - return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */ - } else { - if (mDevSettingsFlag & DMIC_FLAG) { - if(callMode == AudioSystem::MODE_IN_CALL) { -#ifdef USES_FLUENCE_INCALL - if (fluence_mode == FLUENCE_MODE_ENDFIRE) { - if(is_tmus) - return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_TMUS); /* DUALMIC EF TX */ - else - return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */ - } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) { - return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */ - } else { - return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */ - } -#endif - } - if (((rxDevice != NULL) && - !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER, - (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) || - !strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, - (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) { - if (fluence_mode == FLUENCE_MODE_ENDFIRE) { - if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) { -// TODO: check if different ACDB settings are needed when speaker is enabled - return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC); - } else { - return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); - } - } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) { - if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) { - return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC); - } else { - return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); - } - } - } else { - if (fluence_mode == FLUENCE_MODE_ENDFIRE) { - if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) { - return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC); - } else { - return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); - } - } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) { - if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) { - return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC); - } else { - return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); - } - } - } - } else if (mDevSettingsFlag & QMIC_FLAG){ - return strdup(SND_USE_CASE_DEV_QUAD_MIC); - } -#ifdef QCOM_SSR_ENABLED - else if (mDevSettingsFlag & SSRQMIC_FLAG){ - ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices); - // Mapping for quad mic input device. - return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */ - } -#endif -#ifdef SEPERATED_AUDIO_INPUT - if(input_source == AUDIO_SOURCE_VOICE_RECOGNITION) { - return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */ - } -#endif - else { - return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */ - } - } - } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) { - return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */ -#ifdef QCOM_ANC_HEADSET_ENABLED - } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) { - return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */ -#endif - } else if (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_HEADSET); /* Voice HEADSET TX */ - } else - return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */ - } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) { - if (btsco_samplerate == BTSCO_RATE_16KHZ) - return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/ - else - return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/ -#ifdef QCOM_USBAUDIO_ENABLED - } else if ((devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) || - (devices & AudioSystem::DEVICE_IN_PROXY)) { - return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */ -#endif - } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) || - (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) { - /* Nothing to be done, use current active device */ - if (strncmp(curTxUCMDevice, "None", 4)) { - return strdup(curTxUCMDevice); - } -#ifdef QCOM_FM_ENABLED - } else if ((devices & AudioSystem::DEVICE_IN_FM_RX) || - (devices & AudioSystem::DEVICE_IN_FM_RX_A2DP)) { - /* Nothing to be done, use current tx device or set dummy device */ - if (strncmp(curTxUCMDevice, "None", 4)) { - return strdup(curTxUCMDevice); - } else { - return strdup(SND_USE_CASE_DEV_DUMMY_TX); - } -#endif - } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) || - (devices & AudioSystem::DEVICE_IN_BACK_MIC)) { - ALOGI("No proper mapping found with UCM device list, setting default"); - if (!strncmp(mic_type, "analog", 6)) { - return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */ - } else { - if (callMode == AudioSystem::MODE_IN_CALL) { - return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */ -#ifdef SEPERATED_AUDIO_INPUT - } else if(input_source == AUDIO_SOURCE_CAMCORDER) { - return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */ -#endif - } else - return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */ - } - } else { - ALOGD("No valid input device: %u", devices); - } - } - return NULL; -} - -void s_set_voice_volume(int vol) -{ - int err = 0; - ALOGV("s_set_voice_volume: volume %d", vol); - ALSAControl control("/dev/snd/controlC0"); - control.set("Voice Rx Volume", vol, 0); - - if (platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_volume == NULL) { - ALOGE("dlsym:Error:%s Loading csd_client_volume", dlerror()); - } else { - err = csd_volume(vol); - if (err < 0) { - ALOGE("s_set_voice_volume: csd_client error %d", err); - } - } -#endif - } -} - -void s_set_volte_volume(int vol) -{ - ALOGV("s_set_volte_volume: volume %d", vol); - ALSAControl control("/dev/snd/controlC0"); - control.set("VoLTE Rx Volume", vol, 0); -} - - -void s_set_voip_volume(int vol) -{ - ALOGV("s_set_voip_volume: volume %d", vol); - ALSAControl control("/dev/snd/controlC0"); - control.set("Voip Rx Volume", vol, 0); -} -void s_set_mic_mute(int state) -{ - int err = 0; - ALOGV("s_set_mic_mute: state %d", state); - ALSAControl control("/dev/snd/controlC0"); - control.set("Voice Tx Mute", state, 0); - - if (platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_mic_mute == NULL) { - ALOGE("dlsym:Error:%s Loading csd_mic_mute", dlerror()); - } else { - err=csd_mic_mute(state); - if (err < 0) { - ALOGE("s_set_mic_mute: csd_client error %d", err); - } - } -#endif - } -} -void s_set_volte_mic_mute(int state) -{ - ALOGV("s_set_volte_mic_mute: state %d", state); - ALSAControl control("/dev/snd/controlC0"); - control.set("VoLTE Tx Mute", state, 0); -} - -void s_set_voip_mic_mute(int state) -{ - ALOGV("s_set_voip_mic_mute: state %d", state); - ALSAControl control("/dev/snd/controlC0"); - control.set("Voip Tx Mute", state, 0); -} - -void s_set_voip_config(int mode, int rate) -{ - ALOGV("s_set_voip_config: mode %d,rate %d", mode, rate); - ALSAControl control("/dev/snd/controlC0"); - char** setValues; - setValues = (char**)malloc(2*sizeof(char*)); - if (setValues == NULL) { - return; - } - setValues[0] = (char*)malloc(4*sizeof(char)); - if (setValues[0] == NULL) { - free(setValues); - return; - } - - setValues[1] = (char*)malloc(8*sizeof(char)); - if (setValues[1] == NULL) { - free(setValues); - free(setValues[0]); - return; - } - - sprintf(setValues[0], "%d",mode); - sprintf(setValues[1], "%d",rate); - - control.setext("Voip Mode Rate Config", 2, setValues); - free(setValues[1]); - free(setValues[0]); - free(setValues); - return; -} - -void s_set_btsco_rate(int rate) -{ - btsco_samplerate = rate; -} - -void s_enable_wide_voice(bool flag) -{ - int err = 0; - - ALOGV("s_enable_wide_voice: flag %d", flag); - ALSAControl control("/dev/snd/controlC0"); - if(flag == true) { - control.set("Widevoice Enable", 1, 0); - } else { - control.set("Widevoice Enable", 0, 0); - } - - if (platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_wide_voice == NULL) { - ALOGE("dlsym:Error:%s Loading csd_wide_voice", dlerror()); - } else { - err = csd_wide_voice(flag); - if (err < 0) { - ALOGE("enableWideVoice: csd_client_wide_voice error %d", err); - } - } -#endif - } -} - -void s_set_voc_rec_mode(uint8_t mode) -{ - ALOGV("s_set_voc_rec_mode: mode %d", mode); - ALSAControl control("/dev/snd/controlC0"); - control.set("Incall Rec Mode", mode, 0); -} - -void s_enable_fens(bool flag) -{ - int err = 0; - - ALOGV("s_enable_fens: flag %d", flag); - ALSAControl control("/dev/snd/controlC0"); - if(flag == true) { - control.set("FENS Enable", 1, 0); - } else { - control.set("FENS Enable", 0, 0); - } - - if (platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_fens == NULL) { - ALOGE("dlsym:Error:%s Loading csd_fens", dlerror()); - } else { - err = csd_fens(flag); - if (err < 0) { - ALOGE("s_enable_fens: csd_client error %d", err); - } - } -#endif - } -} - -void s_enable_slow_talk(bool flag) -{ - int err = 0; - - ALOGV("s_enable_slow_talk: flag %d", flag); - ALSAControl control("/dev/snd/controlC0"); - if(flag == true) { - control.set("Slowtalk Enable", 1, 0); - } else { - control.set("Slowtalk Enable", 0, 0); - } - - if (platform_is_Fusion3()) { -#ifdef QCOM_CSDCLIENT_ENABLED - if (csd_slow_talk == NULL) { - ALOGE("dlsym:Error:%s Loading csd_slow_talk", dlerror()); - } else { - err = csd_slow_talk(flag); - if (err < 0) { - ALOGE("s_enable_slow_talk: csd_client error %d", err); - } - } -#endif - } -} - -void s_set_flags(uint32_t flags) -{ - ALOGV("s_set_flags: flags %d", flags); - mDevSettingsFlag = flags; -} - -static status_t s_set_compressed_vol(int value) -{ - status_t err = NO_ERROR; - - ALSAControl control("/dev/snd/controlC0"); - control.set("COMPRESSED RX Volume",value,0); - - return err; -} - -#ifdef SEPERATED_AUDIO_INPUT -void s_setInput(int input) -{ - input_source = input; - ALOGD("s_setInput() : input_source = %d",input_source); -} -#endif - -#ifdef QCOM_CSDCLIENT_ENABLED -static void s_set_csd_handle(void* handle) -{ - csd_handle = static_cast(handle); - ALOGI("%s csd_handle: %p", __func__, csd_handle); - - csd_disable_device = (int (*)())::dlsym(csd_handle,"csd_client_disable_device"); - csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(csd_handle,"csd_client_enable_device"); - csd_start_voice = (int (*)())::dlsym(csd_handle,"csd_client_start_voice"); - csd_stop_voice = (int (*)())::dlsym(csd_handle,"csd_client_stop_voice"); - csd_volume = (int (*)(int))::dlsym(csd_handle,"csd_client_volume"); - csd_mic_mute = (int (*)(int))::dlsym(csd_handle,"csd_client_mic_mute"); - csd_wide_voice = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_wide_voice"); - csd_fens = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_fens"); - csd_slow_talk = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_slow_talk"); -} -#endif - -static bool s_is_tmus() -{ - char value[128]; - bool ret = false; - - if (mccmnc == 0) { - property_get("gsm.sim.operator.numeric",value,"0"); - mccmnc = atoi(value); - } - - ALOGD("%s: mnc_mcc : %d", __FUNCTION__, mccmnc); - switch(mccmnc) - { - //TMUS MCC(310), MNC(490, 260, 026) - case 310490: - case 310260: - case 310026: - ret = true; - break; - default: - ret = false; - break; - } - - return ret; -} - -} diff --git a/legacy/alsa_sound/audio_hw_hal.cpp b/legacy/alsa_sound/audio_hw_hal.cpp index ab15e2744..3e5d21277 100644 --- a/legacy/alsa_sound/audio_hw_hal.cpp +++ b/legacy/alsa_sound/audio_hw_hal.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2011 The Android Open Source Project - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * 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. @@ -74,25 +75,24 @@ static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] = { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES }, { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER }, { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL }, +#ifdef QCOM_USBAUDIO_ENABLED { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET }, { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET }, - { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT }, + { AudioSystem::DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_ACCESSORY }, + { AudioSystem::DEVICE_OUT_USB_DEVICE, AUDIO_DEVICE_OUT_USB_DEVICE }, +#endif #ifdef QCOM_ANC_HEADSET_ENABLED { AudioSystem::DEVICE_OUT_ANC_HEADSET, AUDIO_DEVICE_OUT_ANC_HEADSET }, { AudioSystem::DEVICE_OUT_ANC_HEADPHONE, AUDIO_DEVICE_OUT_ANC_HEADPHONE }, #endif +#ifdef QCOM_PROXY_DEVICE_ENABLED + { AudioSystem::DEVICE_OUT_PROXY, AUDIO_DEVICE_OUT_PROXY }, +#endif #ifdef QCOM_FM_ENABLED { AudioSystem::DEVICE_OUT_FM, AUDIO_DEVICE_OUT_FM }, -#endif -#ifdef QCOM_FM_TX_ENABLED { AudioSystem::DEVICE_OUT_FM_TX, AUDIO_DEVICE_OUT_FM_TX }, #endif -#ifdef QCOM_VOIP_ENABLED - { AudioSystem::DEVICE_OUT_DIRECTOUTPUT, AUDIO_DEVICE_OUT_DIRECTOUTPUT }, -#endif -#ifdef QCOM_PROXY_DEVICE_ENABLED - { AudioSystem::DEVICE_OUT_PROXY, AUDIO_DEVICE_OUT_PROXY }, -#endif + { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT }, /* input devices */ { AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION }, { AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT }, @@ -102,16 +102,27 @@ static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] = { AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL }, { AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL }, { AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC }, - { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT }, +#ifdef QCOM_USBAUDIO_ENABLED + { AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET, AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET }, +#endif #ifdef QCOM_ANC_HEADSET_ENABLED { AudioSystem::DEVICE_IN_ANC_HEADSET, AUDIO_DEVICE_IN_ANC_HEADSET }, #endif +#ifdef QCOM_PROXY_DEVICE_ENABLED + { AudioSystem::DEVICE_IN_PROXY, AUDIO_DEVICE_IN_PROXY }, +#endif #ifdef QCOM_FM_ENABLED { AudioSystem::DEVICE_IN_FM_RX, AUDIO_DEVICE_IN_FM_RX }, { AudioSystem::DEVICE_IN_FM_RX_A2DP, AUDIO_DEVICE_IN_FM_RX_A2DP }, #endif + { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT }, }; +// the "audio_devices" enumeration defined in hardware/libhardware_legacy is obsolete, +// use type "audio_devices_t" and audio device enumeration from system/audio.h instead. +// Do not use convert_audio_device if audio hal uses device definition from system/core +// There's no need to conver audio device if HAL uses AUDIO_DEVICE_XXX defintions instead +// of AudioSystem::Device_XXX. static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev) { const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM; @@ -151,7 +162,7 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) struct qcom_stream_out *out = reinterpret_cast(stream); - ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); /* TODO: implement this */ return 0; } @@ -181,7 +192,7 @@ static int out_set_format(struct audio_stream *stream, audio_format_t format) { struct qcom_stream_out *out = reinterpret_cast(stream); - ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); /* TODO: implement me */ return 0; } @@ -269,6 +280,59 @@ static int out_get_render_position(const struct audio_stream_out *stream, reinterpret_cast(stream); return out->qcom_out->getRenderPosition(dsp_frames); } +#ifdef QCOM_TUNNEL_LPA_ENABLED +static int out_set_observer(const struct audio_stream_out *stream, + void *observer) +{ + const struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->setObserver(observer); +} + +static int out_get_buffer_info(const struct audio_stream_out *stream, + buf_info ** buf) +{ + const struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->getBufferInfo(buf); +} + +static int out_is_buffer_available(const struct audio_stream_out *stream, + int *isAvail) +{ + const struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->isBufferAvailable(isAvail); +} + +static status_t out_start(struct audio_stream_out *stream) +{ + struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->start(); +} + +static status_t out_pause(struct audio_stream_out *stream) +{ + struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->pause(); +} + +static status_t out_flush(struct audio_stream_out *stream) +{ + struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->flush(); +} + +static status_t out_stop(struct audio_stream_out *stream) +{ + struct qcom_stream_out *out = + reinterpret_cast(stream); + return out->qcom_out->stop(); +} +#endif //QCOM_TUNNEL_LPA_ENABLED static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { @@ -301,7 +365,7 @@ static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) struct qcom_stream_in *in = reinterpret_cast(stream); - ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); /* TODO: implement this */ return 0; } @@ -331,7 +395,7 @@ static int in_set_format(struct audio_stream *stream, audio_format_t format) { struct qcom_stream_in *in = reinterpret_cast(stream); - ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); + ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__); /* TODO: implement me */ return 0; } @@ -436,6 +500,69 @@ static inline const struct qcom_audio_device * to_cladev(const struct audio_hw_d return reinterpret_cast(dev); } +static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) +{ + /* XXX: The old AudioHardwareInterface interface is not smart enough to + * tell us this, so we'll lie and basically tell AF that we support the + * below input/output devices and cross our fingers. To do things properly, + * audio hardware interfaces that need advanced features (like this) should + * convert to the new HAL interface and not use this wrapper. */ + return (/* OUT */ + AUDIO_DEVICE_OUT_EARPIECE | + AUDIO_DEVICE_OUT_SPEAKER | + AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | + AUDIO_DEVICE_OUT_AUX_DIGITAL | + AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | + AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | + AUDIO_DEVICE_OUT_USB_ACCESSORY | + AUDIO_DEVICE_OUT_USB_DEVICE | + AUDIO_DEVICE_OUT_REMOTE_SUBMIX | +#ifdef QCOM_ANC_HEADSET_ENABLED + AUDIO_DEVICE_OUT_ANC_HEADSET | + AUDIO_DEVICE_OUT_ANC_HEADPHONE | +#endif +#ifdef QCOM_PROXY_DEVICE_ENABLED + AUDIO_DEVICE_OUT_PROXY | +#endif +#ifdef QCOM_FM_ENABLED + AUDIO_DEVICE_OUT_FM | + AUDIO_DEVICE_OUT_FM_TX | +#endif + AUDIO_DEVICE_OUT_DEFAULT | + /* IN */ + AUDIO_DEVICE_IN_COMMUNICATION | + AUDIO_DEVICE_IN_AMBIENT | + AUDIO_DEVICE_IN_BUILTIN_MIC | + AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | + AUDIO_DEVICE_IN_WIRED_HEADSET | + AUDIO_DEVICE_IN_AUX_DIGITAL | + AUDIO_DEVICE_IN_VOICE_CALL | + AUDIO_DEVICE_IN_BACK_MIC | + AUDIO_DEVICE_IN_REMOTE_SUBMIX | + AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET | + AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET | + AUDIO_DEVICE_IN_USB_ACCESSORY | + AUDIO_DEVICE_IN_USB_DEVICE | +#ifdef QCOM_ANC_HEADSET_ENABLED + AUDIO_DEVICE_IN_ANC_HEADSET | +#endif +#ifdef QCOM_PROXY_DEVICE_ENABLED + AUDIO_DEVICE_IN_PROXY | +#endif +#ifdef QCOM_FM_ENABLED + AUDIO_DEVICE_IN_FM_RX | + AUDIO_DEVICE_IN_FM_RX_A2DP | +#endif + AUDIO_DEVICE_IN_DEFAULT); +} + static int adev_init_check(const struct audio_hw_device *dev) { const struct qcom_audio_device *qadev = to_cladev(dev); @@ -511,44 +638,6 @@ static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, return qadev->hwif->getInputBufferSize(config->sample_rate, config->format, channelCount); } -#ifdef QCOM_TUNNEL_LPA_ENABLED -static int adev_open_output_session(struct audio_hw_device *dev, - uint32_t devices, - int *format, - int sessionId, - uint32_t samplingRate, - uint32_t channels, - struct audio_stream_out **stream_out) -{ - struct qcom_audio_device *qadev = to_ladev(dev); - status_t status; - struct qcom_stream_out *out; - int ret; - - out = (struct qcom_stream_out *)calloc(1, sizeof(*out)); - if (!out) - return -ENOMEM; - - out->qcom_out = qadev->hwif->openOutputSession(devices, format,&status,sessionId,samplingRate,channels); - if (!out->qcom_out) { - ret = status; - goto err_open; - } - - out->stream.common.standby = out_standby; - out->stream.common.set_parameters = out_set_parameters; - out->stream.set_volume = out_set_volume; - - *stream_out = &out->stream; - return 0; - -err_open: - free(out); - *stream_out = NULL; - return ret; -} -#endif - static int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, @@ -595,7 +684,15 @@ static int adev_open_output_stream(struct audio_hw_device *dev, 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; - +#ifdef QCOM_TUNNEL_LPA_ENABLED + out->stream.start = out_start; + out->stream.pause = out_pause; + out->stream.flush = out_flush; + out->stream.stop = out_stop; + out->stream.set_observer = out_set_observer; + out->stream.get_buffer_info = out_get_buffer_info; + out->stream.is_buffer_available = out_is_buffer_available; +#endif *stream_out = &out->stream; return 0; @@ -721,6 +818,7 @@ static int qcom_adev_open(const hw_module_t* module, const char* name, qadev->device.common.module = const_cast(module); qadev->device.common.close = qcom_adev_close; + qadev->device.get_supported_devices = adev_get_supported_devices; qadev->device.init_check = adev_init_check; qadev->device.set_voice_volume = adev_set_voice_volume; qadev->device.set_master_volume = adev_set_master_volume; @@ -735,9 +833,6 @@ static int qcom_adev_open(const hw_module_t* module, const char* name, qadev->device.get_parameters = adev_get_parameters; qadev->device.get_input_buffer_size = adev_get_input_buffer_size; qadev->device.open_output_stream = adev_open_output_stream; -#ifdef QCOM_TUNNEL_LPA_ENABLED - qadev->device.open_output_session = adev_open_output_session; -#endif qadev->device.close_output_stream = adev_close_output_stream; qadev->device.open_input_stream = adev_open_input_stream; qadev->device.close_input_stream = adev_close_input_stream; @@ -770,7 +865,7 @@ struct qcom_audio_module HAL_MODULE_INFO_SYM = { hal_api_version: HARDWARE_HAL_API_VERSION, id: AUDIO_HARDWARE_MODULE_ID, name: "QCOM Audio HW HAL", - author: "Code Aurora Forum", + author: "The Linux Foundation", methods: &qcom_audio_module_methods, dso : NULL, reserved : {0}, diff --git a/legacy/alsa_sound/audio_policy_hal.cpp b/legacy/alsa_sound/audio_policy_hal.cpp index 5363e2824..722910dfc 100644 --- a/legacy/alsa_sound/audio_policy_hal.cpp +++ b/legacy/alsa_sound/audio_policy_hal.cpp @@ -1,5 +1,7 @@ /* * Copyright (C) 2011 The Android Open Source Project + * Copyright (c) 2012-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. @@ -68,7 +70,7 @@ static int ap_set_device_connection_state(struct audio_policy *pol, { struct qcom_audio_policy *qap = to_qap(pol); return qap->apm->setDeviceConnectionState( - (AudioSystem::audio_devices)device, + device, (AudioSystem::device_connection_state)state, device_address); } @@ -80,15 +82,14 @@ static audio_policy_dev_state_t ap_get_device_connection_state( { const struct qcom_audio_policy *qap = to_cqap(pol); return (audio_policy_dev_state_t)qap->apm->getDeviceConnectionState( - (AudioSystem::audio_devices)device, + device, device_address); } static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state) { struct qcom_audio_policy *qap = to_qap(pol); - // as this is the legacy API, don't change it to use audio_mode_t instead of int - qap->apm->setPhoneState((int) state); + qap->apm->setPhoneState(state); } /* indicate a change in ringer mode */ @@ -133,18 +134,19 @@ static int ap_init_check(const struct audio_policy *pol) return qap->apm->initCheck(); } + static audio_io_handle_t ap_get_output(struct audio_policy *pol, audio_stream_type_t stream, uint32_t sampling_rate, audio_format_t format, - audio_channel_mask_t channelMask, + uint32_t channels, audio_output_flags_t flags) { struct qcom_audio_policy *qap = to_qap(pol); ALOGV("%s: tid %d", __func__, gettid()); return qap->apm->getOutput((AudioSystem::stream_type)stream, - sampling_rate, (int) format, channelMask, + sampling_rate, format, channels, (AudioSystem::output_flags)flags); } @@ -174,11 +176,11 @@ static void ap_release_output(struct audio_policy *pol, static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource, uint32_t sampling_rate, audio_format_t format, - audio_channel_mask_t channelMask, + uint32_t channels, audio_in_acoustics_t acoustics) { struct qcom_audio_policy *qap = to_qap(pol); - return qap->apm->getInput((int) inputSource, sampling_rate, (int) format, channelMask, + return qap->apm->getInput(inputSource, sampling_rate, format, channels, (AudioSystem::audio_in_acoustics)acoustics); } @@ -229,6 +231,13 @@ static int ap_get_stream_volume_index(const struct audio_policy *pol, AUDIO_DEVICE_OUT_DEFAULT); } +static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol, + audio_stream_type_t stream) +{ + const struct qcom_audio_policy *qap = to_cqap(pol); + return qap->apm->getStrategyForStream((AudioSystem::stream_type)stream); +} + static int ap_set_stream_volume_index_for_device(struct audio_policy *pol, audio_stream_type_t stream, int index, @@ -248,14 +257,7 @@ static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol, const struct qcom_audio_policy *qap = to_cqap(pol); return qap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream, index, - device); -} - -static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol, - audio_stream_type_t stream) -{ - const struct qcom_audio_policy *qap = to_cqap(pol); - return qap->apm->getStrategyForStream((AudioSystem::stream_type)stream); + AUDIO_DEVICE_OUT_DEFAULT); } static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol, @@ -295,19 +297,12 @@ static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled) return qap->apm->setEffectEnabled(id, enabled); } -static bool ap_is_stream_active(const struct audio_policy *pol, +static bool ap_is_stream_active(const struct audio_policy *pol, audio_stream_type_t stream, uint32_t in_past_ms) { const struct qcom_audio_policy *qap = to_cqap(pol); - return qap->apm->isStreamActive((int) stream, in_past_ms); -} - -static bool ap_is_stream_active_remotely(const struct audio_policy *pol, - audio_stream_type_t stream, uint32_t in_past_ms) -{ - const struct qcom_audio_policy *qap = to_cqap(pol); - return qap->apm->isStreamActiveRemotely((int) stream, in_past_ms); + return qap->apm->isStreamActive(stream, in_past_ms); } static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source) @@ -366,7 +361,6 @@ static int create_qcom_ap(const struct audio_policy_device *device, qap->policy.unregister_effect = ap_unregister_effect; qap->policy.set_effect_enabled = ap_set_effect_enabled; qap->policy.is_stream_active = ap_is_stream_active; - qap->policy.is_stream_active_remotely = ap_is_stream_active_remotely; qap->policy.is_source_active = ap_is_source_active; qap->policy.dump = ap_dump; @@ -455,7 +449,7 @@ struct qcom_ap_module HAL_MODULE_INFO_SYM = { version_minor: 0, id: AUDIO_POLICY_HARDWARE_MODULE_ID, name: "QCOM Audio Policy HAL", - author: "Code Aurora Forum", + author: "The Linux Foundation", methods: &qcom_ap_module_methods, dso : NULL, reserved : {0}, diff --git a/legacy/audiod/Android.mk b/legacy/audiod/Android.mk new file mode 100644 index 000000000..dd3b65aae --- /dev/null +++ b/legacy/audiod/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + audiod_main.cpp \ + AudioDaemon.cpp \ + +LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libmedia \ + +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +LOCAL_MODULE:= audiod +LOCAL_MODULE_TAGS:= debug + +include $(BUILD_EXECUTABLE) diff --git a/legacy/audiod/AudioDaemon.cpp b/legacy/audiod/AudioDaemon.cpp new file mode 100644 index 000000000..6cc8de84a --- /dev/null +++ b/legacy/audiod/AudioDaemon.cpp @@ -0,0 +1,148 @@ +/* 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 +#include + +#include "AudioDaemon.h" + +int pil_fd; +#define NUM_FD 1 +int bootup_complete = 0; +char adsp_pil_state_file[] = "/sys/kernel/audio_voice_service/status"; + +namespace android { + + AudioDaemon::AudioDaemon() : Thread(false) { + } + + AudioDaemon::~AudioDaemon() { + } + + void AudioDaemon::onFirstRef() { + ALOGV("Start audiod daemon"); + run("AudioDaemon", PRIORITY_AUDIO); + } + + void AudioDaemon::binderDied(const wp& who) + { + requestExit(); + } + + + status_t AudioDaemon::readyToRun() { + + ALOGV("readyToRun: open adsp sysfs node file: %s", adsp_pil_state_file); + + pil_fd = open(adsp_pil_state_file, O_RDONLY); + + if (pil_fd < 0) { + ALOGE("File %s open failed (%s)", adsp_pil_state_file, strerror(errno)); + return errno; + } + return NO_ERROR; + } + + bool AudioDaemon::threadLoop() + { + int max = -1; + int ret; + adsp_status cur_state = adsp_offline; + struct pollfd pfd[NUM_FD]; + char rd_buf[9]; + + ALOGV("Start threadLoop()"); + + if (pil_fd < 0) + pil_fd = open(adsp_pil_state_file, O_RDONLY); + + if (pil_fd < 0) { + ALOGE("File %s open failed (%s)", adsp_pil_state_file, strerror(errno)); + return false; + } + + pfd[0].fd = pil_fd; + pfd[0].events = POLLPRI; + + while (1) { + ALOGD("poll() for adsp state change "); + if (poll(pfd, 1, -1) < 0) { + ALOGE("poll() failed (%s)", strerror(errno)); + return false; + } + + ALOGD("out of poll() for adsp state change "); + if (pfd[0].revents & POLLPRI) { + if (!read(pil_fd, (void *)rd_buf, 8)) { + ALOGE("Error receiving adsp_state event (%s)", strerror(errno)); + } else { + rd_buf[8] = '\0'; + ALOGV("adsp state file content: %s",rd_buf); + lseek(pil_fd, 0, SEEK_SET); + + if (!strncmp(rd_buf, "OFFLINE", strlen("OFFLINE"))) { + cur_state = adsp_offline; + } else if (!strncmp(rd_buf, "ONLINE", strlen("ONLINE"))) { + cur_state = adsp_online; + } + + if (bootup_complete) { + notifyAudioSystem(cur_state); + } + + if (cur_state == adsp_online && !bootup_complete) { + bootup_complete = 1; + ALOGV("adsp is up, device bootup time"); + } + } + } + } + + ALOGV("Exiting Poll ThreadLoop"); + return true; + } + + void AudioDaemon::notifyAudioSystem(adsp_status status) { + + ALOGV("notifyAudioSystem : %d", status); + switch (status) { + case adsp_online: + ALOGV("notifyAudioSystem : ADSP_STATUS=ONLINE"); + AudioSystem::setParameters(0, String8("ADSP_STATUS=ONLINE")); + break; + case adsp_offline: + ALOGV("notifyAudioSystem : ADSP_STATUS=OFFLINE"); + AudioSystem::setParameters(0, String8("ADSP_STATUS=OFFLINE")); + break; + } + } +} diff --git a/legacy/audiod/AudioDaemon.h b/legacy/audiod/AudioDaemon.h new file mode 100644 index 000000000..0862d442a --- /dev/null +++ b/legacy/audiod/AudioDaemon.h @@ -0,0 +1,59 @@ +/* AudioDaemon.h + +Copyright (c) 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 "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 +#include +#include +#include +#include + +namespace android { + +enum adsp_status { adsp_online, adsp_offline}; + +enum uevent_action { action_online, action_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(adsp_status status); + int mUeventSock; + +public: + AudioDaemon(); + virtual ~AudioDaemon(); +}; + +} diff --git a/legacy/audiod/audiod_main.cpp b/legacy/audiod/audiod_main.cpp new file mode 100644 index 000000000..f28c36642 --- /dev/null +++ b/legacy/audiod/audiod_main.cpp @@ -0,0 +1,60 @@ +/* Copyright (C) 2007 The Android Open Source Project + +Copyright (c) 2012, 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 + +#include +#include +#include + +#include +#include + +#if defined(HAVE_PTHREADS) +# include +# include +#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 proc(ProcessState::self()); + ProcessState::self()->startThreadPool(); + + sp audioService = new AudioDaemon(); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} diff --git a/legacy/libalsa-intf/Android.mk b/legacy/libalsa-intf/Android.mk index 5d509b322..9fad5c8df 100644 --- a/legacy/libalsa-intf/Android.mk +++ b/legacy/libalsa-intf/Android.mk @@ -2,20 +2,25 @@ LOCAL_PATH:= $(call my-dir) ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true) # Any prebuilt files with default TAGS can use the below: - include $(CLEAR_VARS) #LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c LOCAL_SRC_FILES:= aplay.c LOCAL_MODULE:= aplay LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE_TAGS:= debug include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) #LOCAL_SRC_FILES:= arec.c alsa_pcm.c LOCAL_SRC_FILES:= arec.c +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE:= arec LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE_TAGS:= debug include $(BUILD_EXECUTABLE) @@ -23,6 +28,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= amix.c LOCAL_MODULE:= amix LOCAL_SHARED_LIBRARIES := libc libcutils libalsa-intf +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE_TAGS:= debug include $(BUILD_EXECUTABLE) @@ -30,6 +37,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= alsaucm_test.c LOCAL_MODULE:= alsaucm_test LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE_TAGS:= debug include $(BUILD_EXECUTABLE) @@ -42,8 +51,15 @@ LOCAL_SRC_FILES:= alsa_mixer.c alsa_pcm.c alsa_ucm.c LOCAL_MODULE:= libalsa-intf LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES:= libc libcutils #libutils #libmedia libhardware_legacy +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true) LOCAL_CFLAGS := -DQC_PROP -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\" - +LOCAL_CFLAGS += -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\" +LOCAL_SHARED_LIBRARIES += libacdbloader +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-acdb-util +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audcal +endif +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr ifeq ($(TARGET_SIMULATOR),true) LOCAL_LDLIBS += -ldl else diff --git a/legacy/libalsa-intf/Makefile.am b/legacy/libalsa-intf/Makefile.am index a05d07324..8485d75dc 100644 --- a/legacy/libalsa-intf/Makefile.am +++ b/legacy/libalsa-intf/Makefile.am @@ -27,15 +27,26 @@ libalsa_intf_la_SOURCES = $(c_sources) $(h_sources) libalsa_intfdir = $(prefix)/snd_soc_msm dist_libalsa_intf_DATA = snd_soc_msm/snd_soc_msm \ snd_soc_msm/snd_soc_msm_2x \ + snd_soc_msm/snd_soc_msm_2x_mpq \ snd_soc_msm/snd_soc_msm_2x_Fusion3 \ - snd_soc_msm/snd_soc_msm_Sitar + snd_soc_msm/snd_soc_msm_Sitar \ + snd_soc_msm/snd_soc_msm_Sitar_Sglte \ + snd_soc_msm/snd_soc_msm_I2S \ + snd_soc_msm/snd_soc_msm_auxpcm \ + snd_soc_msm/snd_soc_msm_2x_auxpcm \ + snd_soc_msm/snd_soc_msm_2x_mpq_auxpcm \ + snd_soc_msm/snd_soc_msm_2x_Fusion3_auxpcm \ + snd_soc_msm/snd_soc_msm_Sitar_auxpcm \ + snd_soc_msm/snd_soc_msm_I2SFusion \ + snd_soc_msm/snd_soc_msm_Taiko \ + snd_soc_msm/snd_soc_msm_Taiko_liquid libalsa_intf_la_CFLAGS = $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@ -DCONFIG_DIR=\"/etc/snd_soc_msm/\" libalsa_intf_la_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_GLIB @GLIB_CFLAGS@ libalsa_intf_la_LDFLAGS = $(ACDBLOADER_LIBS) -lm -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0 requiredlibs = libalsa_intf.la -bin_PROGRAMS = aplay amix arec +bin_PROGRAMS = aplay amix arec alsaucm_test aplay_SOURCES = aplay.c aplay_LDADD = -lpthread $(requiredlibs) @@ -45,3 +56,6 @@ amix_LDADD = -lpthread $(requiredlibs) arec_SOURCES = arec.c arec_LDADD = -lpthread $(requiredlibs) + +alsaucm_test_SOURCES = alsaucm_test.c +alsaucm_test_LDADD = -lpthread $(requiredlibs) diff --git a/legacy/libalsa-intf/alsa_audio.h b/legacy/libalsa-intf/alsa_audio.h index 7f2acf0d2..b4c033dde 100644 --- a/legacy/libalsa-intf/alsa_audio.h +++ b/legacy/libalsa-intf/alsa_audio.h @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -43,12 +43,6 @@ struct pcm { int device_no; int start; }; - -enum decoder_alias { - FORMAT_MP3, - FORMAT_AC3_PASS_THROUGH = 2, -}; - #define FORMAT(v) SNDRV_PCM_FORMAT_##v #define PCM_OUT 0x00000000 @@ -58,6 +52,7 @@ enum decoder_alias { #define PCM_MONO 0x01000000 #define PCM_QUAD 0x02000000 #define PCM_5POINT1 0x04000000 +#define PCM_7POINT1 0x08000000 #define PCM_44100HZ 0x00000000 #define PCM_48000HZ 0x00100000 @@ -149,9 +144,12 @@ void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val); int param_set_hw_refine(struct pcm *pcm, struct snd_pcm_hw_params *params); int param_set_hw_params(struct pcm *pcm, struct snd_pcm_hw_params *params); int param_set_sw_params(struct pcm *pcm, struct snd_pcm_sw_params *sparams); +int get_compressed_format(const char *format); void param_dump(struct snd_pcm_hw_params *p); int pcm_prepare(struct pcm *pcm); long pcm_avail(struct pcm *pcm); +int pcm_set_channel_map(struct pcm *pcm, struct mixer *mixer, + int max_channels, char *chmap); /* Returns a human readable reason for the last error. */ const char *pcm_error(struct pcm *pcm); @@ -183,109 +181,10 @@ struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n); int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent); int mixer_ctl_select(struct mixer_ctl *ctl, const char *value); void mixer_ctl_get(struct mixer_ctl *ctl, unsigned *value); +void mixer_ctl_get_mulvalues(struct mixer_ctl *ctl, unsigned **value, unsigned *count); int mixer_ctl_set_value(struct mixer_ctl *ctl, int count, char ** argv); #define MAX_NUM_CODECS 32 -/* compressed audio support */ -#ifdef QCOM_COMPRESSED_AUDIO_ENABLED -struct snd_compr_caps { - __u32 num_codecs; - __u32 min_fragment_size; - __u32 max_fragment_size; - __u32 min_fragments; - __u32 max_fragments; - __u32 codecs[MAX_NUM_CODECS]; - __u32 reserved[11]; -}; - -struct snd_enc_wma { - __u32 super_block_align; /* WMA Type-specific data */ - __u32 bits_per_sample; - __u32 channelmask; - __u32 encodeopt; -}; - -struct snd_enc_vorbis { - int quality; - __u32 managed; - __u32 max_bit_rate; - __u32 min_bit_rate; - __u32 downmix; -}; - -struct snd_enc_real { - __u32 quant_bits; - __u32 start_region; - __u32 num_regions; -}; - -struct snd_enc_flac { - __u32 num; - __u32 gain; -}; - -struct snd_enc_generic { - __u32 bw; /* encoder bandwidth */ - int reserved[15]; -}; - -union snd_codec_options { - struct snd_enc_wma wma; - struct snd_enc_vorbis vorbis; - struct snd_enc_real real; - struct snd_enc_flac flac; - struct snd_enc_generic generic; -}; - -struct snd_codec { - __u32 id; - __u32 ch_in; - __u32 ch_out; - __u32 sample_rate; - __u32 bit_rate; - __u32 rate_control; - __u32 profile; - __u32 level; - __u32 ch_mode; - __u32 format; - __u32 align; - union snd_codec_options options; - __u32 reserved[3]; -}; - -struct snd_compressed_buffer { - size_t fragment_size; - int fragments; -}; - -/* */ -struct snd_compr_params { - struct snd_compressed_buffer buffer; - struct snd_codec codec; -}; - -struct snd_compr_tstamp { - size_t copied_bytes; - size_t copied_total; - size_t decoded; - size_t rendered; - __u32 sampling_rate; - uint64_t timestamp; -}; - -#define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x00, struct snd_compr_caps *) -#define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x01, struct snd_compr_codec_caps *) -#define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x02, struct snd_compr_params *) -#define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x03, struct snd_compr_params *) -#define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x10, struct snd_compr_tstamp *) -#define SNDRV_COMPRESS_AVAIL _IOR('C', 0x11, struct snd_compr_avail *) -#define SNDRV_COMPRESS_PAUSE _IO('C', 0x20) -#define SNDRV_COMPRESS_RESUME _IO('C', 0x21) -#define SNDRV_COMPRESS_START _IO('C', 0x22) -#define SNDRV_COMPRESS_STOP _IO('C', 0x23) -#define SNDRV_COMPRESS_DRAIN _IO('C', 0x24) -#endif - #endif diff --git a/legacy/libalsa-intf/alsa_mixer.c b/legacy/libalsa-intf/alsa_mixer.c index cdcdcea25..46b7eea55 100644 --- a/legacy/libalsa-intf/alsa_mixer.c +++ b/legacy/libalsa-intf/alsa_mixer.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -448,6 +448,64 @@ void mixer_ctl_get(struct mixer_ctl *ctl, unsigned *value) ALOGV("\n"); } +void mixer_ctl_get_mulvalues(struct mixer_ctl *ctl, unsigned **value, unsigned *count) +{ + struct snd_ctl_elem_value ev; + unsigned int n; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev)) + return; + ALOGV("%s:", ctl->info->id.name); + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BYTES: + for (n = 0; n < ctl->info->count; n++) + ALOGV(" %ld", ev.value.bytes.data[n]); + for (n = 0; n < ctl->info->count; n++) + *(value[n]) = ev.value.bytes.data[n]; + *count = ctl->info->count; + break; + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + for (n = 0; n < ctl->info->count; n++) + ALOGV(" %s", ev.value.integer.value[n] ? "on" : "off"); + for (n=0; n < ctl->info->count; n++) + *(value[n]) = ev.value.integer.value[n]; + *count = ctl->info->count; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER: { + for (n = 0; n < ctl->info->count; n++) + ALOGV(" %ld", ev.value.integer.value[n]); + for (n = 0; n < ctl->info->count; n++) + *(value[n]) = ev.value.integer.value[n]; + *count = ctl->info->count; + break; + } + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + for (n = 0; n < ctl->info->count; n++) + ALOGV(" %lld", ev.value.integer64.value[n]); + for (n = 0; n < ctl->info->count; n++) + *(value[n]) = ev.value.integer64.value[n]; + *count = ctl->info->count; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + for (n = 0; n < ctl->info->count; n++) { + unsigned v = ev.value.enumerated.item[n]; + ALOGV(" %d (%s)", v, + (v < ctl->info->value.enumerated.items) ? ctl->ename[v] : "???"); + } + for (n = 0; n < ctl->info->count; n++) + *(value[n]) = ev.value.enumerated.item[n]; + *count = ctl->info->count; + break; + default: + *count = 0; + ALOGV(" ???"); + } + ALOGV("\n"); +} + static long scale_int(struct snd_ctl_elem_info *ei, unsigned _percent) { long percent; @@ -488,7 +546,6 @@ int mixer_ctl_mulvalues(struct mixer_ctl *ctl, int count, char ** argv) if (count < ctl->info->count || count > ctl->info->count) return -EINVAL; - memset(&ev, 0, sizeof(ev)); ev.id.numid = ctl->info->id.numid; switch (ctl->info->type) { @@ -511,6 +568,13 @@ int mixer_ctl_mulvalues(struct mixer_ctl *ctl, int count, char ** argv) } break; } + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: { + for (n = 0; n < ctl->info->count; n++) { + fprintf( stderr, "Value: %d idx:%d\n", atoi(argv[n]), n); + ev.value.enumerated.item[n] = (unsigned int)atoi(argv[n]); + } + break; + } default: errno = EINVAL; return errno; @@ -595,6 +659,12 @@ int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent) memcpy(ev.value.iec958.status,iec958->status,SPDIF_CHANNEL_STATUS_SIZE); break; } + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: { + for (n = 0; n < ctl->info->count; n++) { + ev.value.enumerated.item[n] = (unsigned int)percent; + } + break; + } default: errno = EINVAL; return errno; diff --git a/legacy/libalsa-intf/alsa_pcm.c b/legacy/libalsa-intf/alsa_pcm.c index a814ae809..a844eb6e4 100644 --- a/legacy/libalsa-intf/alsa_pcm.c +++ b/legacy/libalsa-intf/alsa_pcm.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ #include #include #include - +#include #include "alsa_audio.h" #define __force @@ -78,7 +78,7 @@ enum format_alias { IMA_ADPCM, MPEG, GSM, - SPECIAL = 31, + SPECIAL = 31, S24_3LE, S24_3BE, U24_3LE, @@ -118,7 +118,7 @@ const char *formats_list[][2] = { {"A_LAW", "A-Law"}, {"IMA_ADPCM", "Ima-ADPCM"}, {"MPEG", "MPEG"}, - {"GSM", "GSM"}, + {"GSM", "GSM"}, [31] = {"SPECIAL", "Special"}, {"S24_3LE", "Signed 24 bit Little Endian in 3bytes"}, {"S24_3BE", "Signed 24 bit Big Endian in 3bytes"}, @@ -133,6 +133,18 @@ const char *formats_list[][2] = { {"U18_3LE", "Unsigned 18 bit Little Endian in 3bytes"}, {"U18_3BE", "Unsigned 18 bit Big Endian in 3bytes"}, }; +enum decoder_alias { + FORMAT_MP3 = SND_AUDIOCODEC_MP3, + FORMAT_AAC = SND_AUDIOCODEC_AAC, + FORMAT_AC3_PASS_THROUGH = SND_AUDIOCODEC_AC3_PASS_THROUGH, + FORMAT_WMA = SND_AUDIOCODEC_WMA, + FORMAT_WMA_PRO = SND_AUDIOCODEC_WMA_PRO, + FORMAT_DTS = SND_AUDIOCODEC_DTS, + FORMAT_DTS_LBR = SND_AUDIOCODEC_DTS_LBR, + FORMAT_DTS_PASS_THROUGH = SND_AUDIOCODEC_DTS_PASS_THROUGH, + FORMAT_AMRWB = SND_AUDIOCODEC_AMRWB, + FORMAT_AMRWB_PLUS = SND_AUDIOCODEC_AMRWBPLUS +}; int get_compressed_format(const char *format) { @@ -143,6 +155,30 @@ int get_compressed_format(const char *format) } else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) { printf("AC3 PASS THROUGH is selected\n"); return FORMAT_AC3_PASS_THROUGH; + } else if (strcmp(ch, "AAC") == 0) { + printf("AAC is selected\n"); + return FORMAT_AAC; + } else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) { + printf("AC3_PASS_THROUGH is selected\n"); + return FORMAT_AC3_PASS_THROUGH; + } else if (strcmp(ch, "WMA") == 0) { + printf("WMA is selected\n"); + return FORMAT_WMA; + }else if (strcmp(ch, "WMA_PRO") == 0) { + printf("WMA_PRO is selected\n"); + return FORMAT_WMA_PRO; + }else if (strcmp(ch, "DTS") == 0) { + printf("DTS is selected\n"); + return FORMAT_DTS; + } else if (strcmp(ch, "DTS_LBR") == 0) { + printf("DTS_LBR is selected\n"); + return FORMAT_DTS_LBR; + } else if (strcmp(ch, "AMR_WB") == 0) { + printf("AMR_WB is selected\n"); + return FORMAT_AMRWB; + }else if (strcmp(ch, "AMR_WB_PLUS") == 0) { + printf("FORMAT_AMRWB_PLUS is selected\n"); + return FORMAT_AMRWB_PLUS; } else { printf("invalid format\n"); return -1; @@ -409,7 +445,20 @@ long pcm_avail(struct pcm *pcm) avail += pcm->sw_p->boundary; return avail; } else { - long avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + ((pcm->flags & PCM_MONO) ? pcm->buffer_size/2 : pcm->buffer_size/4); + int buffer_size = 0; + long avail; + if(pcm->flags & PCM_MONO) + buffer_size = pcm->buffer_size/2; + else if(pcm->flags & PCM_QUAD) + buffer_size = pcm->buffer_size/8; + else if(pcm->flags & PCM_5POINT1) + buffer_size = pcm->buffer_size/12; + else if(pcm->flags & PCM_7POINT1) + buffer_size = pcm->buffer_size/16; + else + buffer_size = pcm->buffer_size/4; + + avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + buffer_size; if (avail < 0) avail += pcm->sw_p->boundary; else if ((unsigned long) avail >= pcm->sw_p->boundary) @@ -437,7 +486,18 @@ int mmap_buffer(struct pcm *pcm) char *ptr; unsigned size; struct snd_pcm_channel_info ch; - int channels = (pcm->flags & PCM_MONO) ? 1 : 2; + int channels; + + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; size = pcm->buffer_size; if (pcm->flags & DEBUG_ON) @@ -461,8 +521,19 @@ u_int8_t *dst_address(struct pcm *pcm) unsigned long pcm_offset = 0; struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr; unsigned int appl_ptr = 0; + int channels; + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; - appl_ptr = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4; + appl_ptr = sync_ptr->c.control.appl_ptr*2*channels; pcm_offset = (appl_ptr % (unsigned long)pcm->buffer_size); return pcm->addr + pcm_offset; @@ -475,7 +546,17 @@ int mmap_transfer(struct pcm *pcm, void *data, unsigned offset, unsigned size; u_int8_t *dst_addr, *mmaped_addr; u_int8_t *src_addr = data; - int channels = (pcm->flags & PCM_MONO) ? 1 : 2; + int channels; + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; dst_addr = dst_address(pcm); @@ -497,9 +578,20 @@ int mmap_transfer_capture(struct pcm *pcm, void *data, unsigned offset, unsigned size; u_int8_t *dst_addr, *mmaped_addr; u_int8_t *src_addr; - int channels = (pcm->flags & PCM_MONO) ? 1 : 2; - unsigned int tmp = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4; - + int channels; + unsigned int tmp; + + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; + tmp = sync_ptr->c.control.appl_ptr*2*channels; pcm_offset = (tmp % (unsigned long)pcm->buffer_size); dst_addr = data; src_addr = pcm->addr + pcm_offset; @@ -528,8 +620,18 @@ static int pcm_write_mmap(struct pcm *pcm, void *data, unsigned count) long frames; int err; int bytes_written; - - frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4); + int channels; + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; + frames = count / (2*channels); pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN; err = sync_ptr(pcm); @@ -576,7 +678,17 @@ static int pcm_write_mmap(struct pcm *pcm, void *data, unsigned count) static int pcm_write_nmmap(struct pcm *pcm, void *data, unsigned count) { struct snd_xferi x; - int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 ); + int channels; + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; if (pcm->flags & PCM_IN) return -EINVAL; @@ -626,6 +738,8 @@ int pcm_read(struct pcm *pcm, void *data, unsigned count) x.frames = (count / 8); } else if (pcm->flags & PCM_5POINT1) { x.frames = (count / 12); + } else if (pcm->flags & PCM_7POINT1) { + x.frames = (count / 16); } else { x.frames = (count / 4); } @@ -647,6 +761,20 @@ int pcm_read(struct pcm *pcm, void *data, unsigned count) pcm->underruns++; pcm->running = 0; continue; + } else if (errno == ESTRPIPE) { + ALOGV("Resume from suspended\n"); + for (;;) { + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_RESUME)) { + if (errno == EAGAIN ) { + if (pcm_prepare(pcm)) + return -errno; + } + /* send resume command again */ + continue; + } else + break; + } + continue; } ALOGE("Arec: error%d\n", errno); return -errno; @@ -854,3 +982,48 @@ int pcm_ready(struct pcm *pcm) { return pcm->fd >= 0; } + +int pcm_set_channel_map(struct pcm *pcm, struct mixer *mixer, + int max_channels, char *chmap) +{ + struct mixer_ctl *ctl; + char control_name[44]; // max length of name is 44 as defined + char device_num[3]; // device number upto 2 digit + char **set_values; + int i; + + ALOGV("pcm_set_channel_map"); + set_values = (char**)malloc(max_channels*sizeof(char*)); + if(set_values) { + for(i=0; i< max_channels; i++) { + set_values[i] = (char*)malloc(4*sizeof(char)); + if(set_values[i]) { + sprintf(set_values[i],"%d",chmap[i]); + } else { + ALOGE("memory allocation for set channel map failed"); + return -1; + } + } + } else { + ALOGE("memory allocation for set channel map failed"); + return -1; + } + strlcpy(control_name, "Playback Channel Map", sizeof(control_name)); + if(pcm != NULL) { + sprintf(device_num, "%d", pcm->device_no); + strcat(control_name, device_num); + } + ALOGV("pcm_set_channel_map: control name:%s", control_name); + ctl = mixer_get_control(mixer, control_name, 0); + if(ctl == NULL) { + ALOGE("Could not get the mixer control\n"); + return -1; + } + mixer_ctl_set_value(ctl, max_channels, set_values); + for(i=0; i< max_channels; i++) + if(set_values[i]) + free(set_values[i]); + if(set_values) + free(set_values); + return 0; +} diff --git a/legacy/libalsa-intf/alsa_ucm.c b/legacy/libalsa-intf/alsa_ucm.c index e53211f98..7783fcc8b 100644 --- a/legacy/libalsa-intf/alsa_ucm.c +++ b/legacy/libalsa-intf/alsa_ucm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-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 @@ -10,7 +10,7 @@ * 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 Code Aurora Forum, Inc. nor the names of its + * * 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. * @@ -27,7 +27,7 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "alsa_ucm" -//#define LOG_NDDEBUG 0 +#define LOG_NDDEBUG 0 #ifdef ANDROID /* definitions for Android logging */ @@ -58,13 +58,15 @@ #include #include #include -#include #include #include "msm8960_use_cases.h" #if defined(QC_PROP) - static void (*acdb_send_audio_cal)(int,int); - static void (*acdb_send_voice_cal)(int,int); + #include "acdb-loader.h" +#else + #define acdb_loader_send_voice_cal(rxacdb_id, txacdb_id) (-EPERM) + #define acdb_loader_send_audio_cal(acdb_id, capability) (-EPERM) + #define acdb_loader_send_anc_cal(acdb_id) (-EPERM) #endif #define PARSE_DEBUG 0 @@ -269,6 +271,10 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr; int index, verb_index = 0, ret = 0; + if (value != NULL) { + *value = NULL; + } + pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock); if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) { @@ -370,6 +376,50 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, *value = NULL; ret = -ENODEV; } + } else if (!strncmp(ident1, "PlaybackVolume", 14)) { + ident2 = strtok_r(NULL, "/", &temp_ptr); + index = 0; + if (ident2 != NULL) { + verb_index = uc_mgr->card_ctxt_ptr->current_verb_index; + verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list; + if((get_usecase_type(uc_mgr, ident2)) == CTRL_LIST_VERB) { + ctrl_list = verb_list[verb_index].verb_ctrls; + } else { + ctrl_list = verb_list[verb_index].mod_ctrls; + } + if((verb_index < 0) || + (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, + SND_UCM_END_OF_LIST, 3)) || (ctrl_list == NULL)) { + ALOGE("Invalid current verb value: %s - %d", + uc_mgr->card_ctxt_ptr->current_verb, verb_index); + pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock); + return -EINVAL; + } + while(strncmp(ctrl_list[index].case_name, ident2, + (strlen(ident2)+1))) { + if (!strncmp(ctrl_list[index].case_name, + SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){ + *value = NULL; + ret = -EINVAL; + break; + } else { + index++; + } + } + } else { + ret = -EINVAL; + } + if (ret < 0) { + ALOGE("No valid device/modifier found with given identifier: %s", + ident2); + } else { + if (ctrl_list[index].volume_mixer_ctl) { + *value = strdup(ctrl_list[index].volume_mixer_ctl); + } else { + *value = NULL; + ret = -ENODEV; + } + } } else if (!strncmp(ident1, "ACDBID", 11)) { ident2 = strtok_r(NULL, "/", &temp_ptr); index = 0; verb_index = 0; @@ -406,6 +456,42 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, ret = -ENODEV; } } + } else if (!strncmp(ident1, "CAPABILITY", 11)) { + ident2 = strtok_r(NULL, "/", &temp_ptr); + index = 0; verb_index = 0; + verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list; + if((verb_index < 0) || + (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, + SND_UCM_END_OF_LIST, 3)) || + (verb_list[verb_index].verb_ctrls == NULL)) { + ALOGE("Invalid current verb value: %s - %d", + uc_mgr->card_ctxt_ptr->current_verb, verb_index); + pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock); + return -EINVAL; + } + ctrl_list = verb_list[verb_index].device_ctrls; + if (ident2 != NULL) { + while(strncmp(ctrl_list[index].case_name, ident2, + MAX_LEN(ctrl_list[index].case_name,ident2))) { + if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST, + strlen(SND_UCM_END_OF_LIST))){ + ret = -EINVAL; + break; + } else { + index++; + } + } + } + if (ret < 0) { + ALOGE("No valid device/modifier found with given identifier: %s", + ident2); + } else { + if (verb_list[verb_index].device_ctrls[index].capability) { + ret = verb_list[verb_index].device_ctrls[index].capability; + } else { + ret = -ENODEV; + } + } } else if (!strncmp(ident1, "EffectsMixerCTL", 11)) { ident2 = strtok_r(NULL, "/", &temp_ptr); index = 0; verb_index = 0; @@ -442,6 +528,42 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, ret = -ENODEV; } } + } else if (!strncmp(ident1, "EC_REF_RXMixerCTL", 17)) { + ident2 = strtok_r(NULL, "/", &temp_ptr); + index = 0; verb_index = 0; + verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list; + if((verb_index < 0) || + (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, + SND_UCM_END_OF_LIST, 3)) || + (verb_list[verb_index].verb_ctrls == NULL)) { + ALOGE("Invalid current verb value: %s - %d", + uc_mgr->card_ctxt_ptr->current_verb, verb_index); + pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock); + return -EINVAL; + } + ctrl_list = verb_list[verb_index].device_ctrls; + if (ident2 != NULL) { + while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) { + if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST, + strlen(SND_UCM_END_OF_LIST))){ + ret = -EINVAL; + break; + } else { + index++; + } + } + } + if (ret < 0) { + ALOGE("No valid device/modifier found with given identifier: %s", + ident2); + } else { + if (verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl) { + *value = strdup(verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl); + } else { + *value = NULL; + ret = -ENODEV; + } + } } else { ALOGE("Unsupported identifier value: %s", ident1); *value = NULL; @@ -543,10 +665,18 @@ const char *use_case) if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) || + (!strncmp(use_case, SND_USE_CASE_VERB_VOICE2, + strlen(SND_USE_CASE_VERB_VOICE2))) || + (!strncmp(use_case, SND_USE_CASE_VERB_VOLTE, + strlen(SND_USE_CASE_VERB_VOLTE))) || (!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE, strlen(SND_USE_CASE_MOD_PLAY_VOICE))) || + (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE2, + strlen(SND_USE_CASE_MOD_PLAY_VOICE2))) || + (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOLTE, + strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) || (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { ALOGV("check_devices_for_voice_call(): voice cap detected\n"); @@ -581,11 +711,16 @@ int use_case_index) card_mctrl_t *ctrl_list; int list_size, index, verb_index, ret = 0, voice_acdb = 0, rx_id, tx_id; char *ident_value = NULL; + char current_mod[MAX_STR_LEN]; /* Check if voice call use case/modifier exists */ if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb, + SND_USE_CASE_VERB_VOLTE, strlen(SND_USE_CASE_VERB_VOLTE))) || + (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) || (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, + SND_USE_CASE_VERB_VOICE2, strlen(SND_USE_CASE_VERB_VOICE2))) || + (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL)))) { voice_acdb = 1; @@ -597,11 +732,16 @@ int use_case_index) if ((ident_value = snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head, index))) { - if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE, + if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOLTE, + strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) || + (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE, strlen(SND_USE_CASE_MOD_PLAY_VOICE))) || + (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE2, + strlen(SND_USE_CASE_MOD_PLAY_VOICE2))) || (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { voice_acdb = 1; + strlcpy(current_mod, ident_value, MAX_STR_LEN); free(ident_value); ident_value = NULL; break; @@ -670,18 +810,18 @@ int use_case_index) (tx_id != uc_mgr->current_tx_device)) { uc_mgr->current_rx_device = rx_id; uc_mgr->current_tx_device = tx_id; - ALOGD("Voice acdb: rx id %d tx id %d", + ALOGD("Voice acdb: rx id %d tx id %d verb:%s modifier:%s", uc_mgr->current_rx_device, - uc_mgr->current_tx_device); - if (uc_mgr->acdb_handle && !uc_mgr->isFusion3Platform) { - acdb_send_voice_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_voice_cal"); - if (acdb_send_voice_cal == NULL) { - ALOGE("ucm: dlsym: Error:%s Loading acdb_loader_send_voice_cal", dlerror()); - }else { - acdb_send_voice_cal(uc_mgr->current_rx_device, - uc_mgr->current_tx_device); - } - } + uc_mgr->current_tx_device, + uc_mgr->card_ctxt_ptr->current_verb, current_mod); + if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb, + SND_USE_CASE_VERB_IP_VOICECALL, + strlen(SND_USE_CASE_VERB_IP_VOICECALL)) || + (!strncmp(current_mod, SND_USE_CASE_MOD_PLAY_VOIP, + strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) || + (!uc_mgr->isFusion3Platform)) + acdb_loader_send_voice_cal(uc_mgr->current_rx_device, + uc_mgr->current_tx_device); } else { ALOGV("Voice acdb: Required acdb already pushed \ rx id %d tx id %d", uc_mgr->current_rx_device, @@ -708,6 +848,12 @@ int ctrl_list_type) verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list; verb_index = uc_mgr->card_ctxt_ptr->current_verb_index; + + if (verb_index < 0) { + ALOGE("Invalid verb_index %d", verb_index); + return -EINVAL; + } + if (ctrl_list_type == CTRL_LIST_VERB) { ctrl_list = uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls; @@ -720,9 +866,9 @@ int ctrl_list_type) } else { ctrl_list = NULL; } - if((verb_index < 0) || - (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3)) || - (ctrl_list == NULL) || (ctrl_list[index].case_name == NULL)) { + + if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3) || + (ctrl_list == NULL) || (ctrl_list[index].case_name == NULL)) { ALOGE("Invalid current verb value: %s - %d", uc_mgr->card_ctxt_ptr->current_verb, verb_index); return -EINVAL; @@ -792,22 +938,15 @@ const char *use_case, int enable, int ctrl_list_type, int uc_index) (check_devices_for_voice_call(uc_mgr, use_case) != NULL)) return ret; ALOGD("Set mixer controls for %s enable %d", use_case, enable); - if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) { + if ((ctrl_list[uc_index].acdb_id >= 0) && ctrl_list[uc_index].capability) { if (enable) { - if (snd_use_case_apply_voice_acdb(uc_mgr, uc_index)) { - ALOGV("acdb_id %d cap %d enable %d", - ctrl_list[uc_index].acdb_id, + snd_use_case_apply_voice_acdb(uc_mgr, uc_index); + ALOGD("acdb_id %d cap %d enable %d", + ctrl_list[uc_index].acdb_id, ctrl_list[uc_index].capability, enable); - if (uc_mgr->acdb_handle) { - acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal"); - if (acdb_send_audio_cal == NULL) { - ALOGE("ucm:dlsym:Error:%s Loading acdb_loader_send_audio_cal", dlerror()); - } else { - acdb_send_audio_cal(ctrl_list[uc_index].acdb_id, - ctrl_list[uc_index].capability); - } - } - } + acdb_loader_send_audio_cal( + ctrl_list[uc_index].acdb_id, + ctrl_list[uc_index].capability); } } if (enable) { @@ -826,7 +965,7 @@ const char *use_case, int enable, int ctrl_list_type, int uc_index) mixer_list[index].control_name, 0); if (ctl) { if (mixer_list[index].type == TYPE_INT) { - ALOGV("Setting mixer control: %s, value: %d", + ALOGD("Setting mixer control: %s, value: %d", mixer_list[index].control_name, mixer_list[index].value); ret = mixer_ctl_set(ctl, mixer_list[index].value); @@ -839,7 +978,7 @@ const char *use_case, int enable, int ctrl_list_type, int uc_index) ALOGE("Failed to set multi value control %s\n", mixer_list[index].control_name); } else { - ALOGV("Setting mixer control: %s, value: %s", + ALOGD("Setting mixer control: %s, value: %s", mixer_list[index].control_name, mixer_list[index].string); ret = mixer_ctl_select(ctl, mixer_list[index].string); @@ -885,8 +1024,12 @@ int getUseCaseType(const char *useCase) MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) || !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL2, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL2)) || !strncmp(useCase, SND_USE_CASE_VERB_HIFI2, MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI3, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI3)) || !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC, @@ -895,25 +1038,41 @@ int getUseCaseType(const char *useCase) MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC3, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC3)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA, MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL2, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL2)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM, - MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) { + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))|| + !strncmp(useCase, SND_USE_CASE_MOD_PSEUDO_TUNNEL, + MAX_LEN(useCase,SND_USE_CASE_MOD_PSEUDO_TUNNEL))|| + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL))) { return CAP_RX; } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC2, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC2)) || + !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, + MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) || !strncmp(useCase, SND_USE_CASE_VERB_FM_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) || !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) || !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC2, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC2)) || !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) || !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) || !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM, MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) || !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, @@ -921,22 +1080,34 @@ int getUseCaseType(const char *useCase) return CAP_TX; } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL, MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) || + !strncmp(useCase, SND_USE_CASE_VERB_VOICE2, + MAX_LEN(useCase,SND_USE_CASE_VERB_VOICE2)) || !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL, MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) || !strncmp(useCase, SND_USE_CASE_VERB_DL_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) || !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) || + !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL, + MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) || + !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL, + MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) || !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC, MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE, MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) || + !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE2, + MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE2)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP, MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) || !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) || !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) || + !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL, + MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) || !strncmp(useCase, SND_USE_CASE_VERB_VOLTE, MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) || !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE, @@ -960,7 +1131,7 @@ const char *ident, int enable, int ctrl_list_type) card_mctrl_t *dev_list, *uc_list; char *current_device, use_case[MAX_UC_LEN]; int list_size, index, uc_index, ret = 0, intdev_flag = 0; - int verb_index, capability = 0, ident_cap = 0, dev_cap =0; + int verb_index, capability = 0, ident_cap = 0, dev_cap = 0; ALOGV("set_use_case_ident_for_all_devices(): %s", ident); if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0) @@ -982,49 +1153,51 @@ const char *ident, int enable, int ctrl_list_type) current_device = snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index); if (current_device != NULL) { - uc_index = get_use_case_index(uc_mgr, current_device, - CTRL_LIST_DEVICE); + if ((uc_index = get_use_case_index(uc_mgr, current_device, + CTRL_LIST_DEVICE)) < 0) { + ALOGE("No valid device found: %s", current_device); + free(current_device); + continue; + } dev_cap = dev_list[uc_index].capability; if (!capability) { capability = dev_list[uc_index].capability; } else if (capability != dev_list[uc_index].capability) { capability = CAP_VOICE; } - if (ident_cap == CAP_VOICE || ident_cap == dev_cap) { + if (ident_cap == CAP_VOICE || dev_cap == ident_cap) { if (enable) { if (!snd_ucm_get_status_at_index( uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) { if (uc_index >= 0) { ALOGV("Applying mixer controls for device: %s", - current_device); + current_device); ret = snd_use_case_apply_mixer_controls(uc_mgr, - current_device, enable, CTRL_LIST_DEVICE, uc_index); + current_device, enable, CTRL_LIST_DEVICE, + uc_index); if (!ret) snd_ucm_set_status_at_index( uc_mgr->card_ctxt_ptr->dev_list_head, current_device, enable, dev_cap); } - } else if (ident_cap == CAP_VOICE) { + } else if (ident_cap == CAP_VOICE) { snd_use_case_apply_voice_acdb(uc_mgr, uc_index); - } - } - strlcpy(use_case, ident, sizeof(use_case)); - strlcat(use_case, current_device, sizeof(use_case)); - ALOGV("Applying mixer controls for use case: %s", use_case); - if ((uc_index = - get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) { - ALOGV("No valid use case found: %s", use_case); - intdev_flag++; - } else { - if (capability == CAP_VOICE || ident_cap == CAP_VOICE || - capability == ident_cap) { - ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, - enable, ctrl_list_type, uc_index); - } - } - use_case[0] = 0; - free(current_device); - } + } + } + strlcpy(use_case, ident, sizeof(use_case)); + strlcat(use_case, current_device, sizeof(use_case)); + ALOGV("Applying mixer controls for use case: %s", use_case); + if ((uc_index = + get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) { + ALOGV("No valid use case found: %s", use_case); + intdev_flag++; + } else { + ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, + enable, ctrl_list_type, uc_index); + } + use_case[0] = 0; + } + free(current_device); } } if (intdev_flag) { @@ -1064,7 +1237,11 @@ const char *ident, const char *device, int enable, int ctrl_list_type) uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls; if (device != NULL) { if (enable) { - dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE); + if ((dev_index = + get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) { + ALOGE("No valid device found: %s", device); + return dev_index; + } capability = dev_list[dev_index].capability; if (!snd_ucm_get_status_at_index( uc_mgr->card_ctxt_ptr->dev_list_head, device)) { @@ -1078,10 +1255,14 @@ const char *ident, const char *device, int enable, int ctrl_list_type) } strlcpy(use_case, ident, sizeof(use_case)); strlcat(use_case, device, sizeof(use_case)); - ALOGV("Applying mixer controls for use case: %s", use_case); + ALOGV("Applying mixer controls for use case: %s", use_case); if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) { ALOGV("No valid use case found: %s", use_case ); - uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type); + if ((uc_index = + get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) { + ALOGE("No valid use case found: %s", ident); + return uc_index; + } if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable, ctrl_list_type, uc_index) < 0) { ALOGV("use case %s not valid without device combination also", @@ -1092,7 +1273,11 @@ const char *ident, const char *device, int enable, int ctrl_list_type) ctrl_list_type, uc_index); } } else { - uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type); + if ((uc_index = + get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) { + ALOGE("No valid use case found: %s", ident); + return uc_index; + } if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable, ctrl_list_type, uc_index) < 0) { ALOGV("use case %s not valid without device combination also", @@ -1121,7 +1306,11 @@ const char *device, int enable) verb_index = 0; dev_list = uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls; - dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE); + if ((dev_index = + get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) { + ALOGE("No valid device %s found", device); + return dev_index; + } if (dev_index >= 0) capability = dev_list[dev_index].capability; if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE, @@ -1175,8 +1364,10 @@ const char *device, int enable) use_case[0] = 0; strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb, sizeof(use_case)); - uc_index = get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB); - if (capability == CAP_VOICE || + if ((uc_index = + get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) { + ALOGE("No valid use case %s found", use_case); + } else if (capability == CAP_VOICE || capability == getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) || getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) == @@ -1246,9 +1437,11 @@ const char *device, int enable) } use_case[0] = 0; strlcpy(use_case, ident_value, sizeof(use_case)); - uc_index = - get_use_case_index(uc_mgr, ident_value, CTRL_LIST_MODIFIER); - if (capability == CAP_VOICE || + if ((uc_index = + get_use_case_index(uc_mgr, ident_value, + CTRL_LIST_MODIFIER)) < 0) { + ALOGE("No valid use case %s found", ident_value); + } else if (capability == CAP_VOICE || capability == getUseCaseType(ident_value) || getUseCaseType(ident_value) == CAP_VOICE) { ALOGV("set %d for use case value: %s", enable, use_case); @@ -1318,14 +1511,29 @@ static int set_controls_of_device_for_usecase(snd_use_case_mgr_t *uc_mgr, verb_index = 0; dev_list = uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls; - dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE); + if ((dev_index = + get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) { + ALOGE("No valid device %s found", device); + return dev_index; + } capability = dev_list[dev_index].capability; if (usecase != NULL) { strlcpy(use_case, usecase, sizeof(use_case)); strlcat(use_case, device, sizeof(use_case)); if ((uc_index = get_use_case_index(uc_mgr, use_case, get_usecase_type(uc_mgr, usecase))) < 0) { - ALOGV("No valid use case found: %s", use_case); + ALOGV("No valid use case found: %s,\ + set %d for use case value: %s",use_case, enable, usecase); + if ((uc_index = + get_use_case_index(uc_mgr, usecase, get_usecase_type(uc_mgr, usecase))) < 0) { + ALOGE("No valid use case found: %s", usecase); + } else { + ret = snd_use_case_apply_mixer_controls(uc_mgr, usecase, enable, + get_usecase_type(uc_mgr, usecase), uc_index); + if (ret != 0) + ALOGE("No valid controls exists for usecase %s and device %s, \ + enable: %d", usecase, device, enable); + } } else { if (enable) { if (!snd_ucm_get_status_at_index( @@ -1539,10 +1747,15 @@ int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, ALOGE("Invalid device: Device not part of enabled device list"); } else { ALOGV("disdev: device value to be disabled: %s", value); - index = get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE); - /* Apply Mixer controls for corresponding device and modifier */ - ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0, + if ((index = + get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE)) < 0) { + ALOGE("Device %s not found", value); + ret = -EINVAL; + } else { + /* Apply Mixer controls for device and modifier */ + ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0, CTRL_LIST_DEVICE, index); + } } } } else if (!strncmp(identifier, "_enamod", 7)) { @@ -2297,13 +2510,14 @@ static int snd_ucm_parse(snd_use_case_mgr_t **uc_mgr) close(fd); return -EINVAL; } - read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE, + read_buf = (char *) mmap(0, st.st_size+1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (read_buf == MAP_FAILED) { ALOGE("failed to mmap file error %d\n", errno); close(fd); return -EINVAL; } + read_buf[st.st_size] = '\0'; current_str = read_buf; verb_count = get_verb_count(current_str); (*uc_mgr)->card_ctxt_ptr->use_case_verb_list = @@ -3243,6 +3457,8 @@ char **nxt_str, int verb_index, int ctrl_list_type) list->acdb_id = 0; list->capability = 0; list->effects_mixer_ctl = NULL; + list->volume_mixer_ctl = NULL; + list->ec_ref_rx_mixer_ctl = NULL; current_str = *cur_str; next_str = *nxt_str; while(strncasecmp(current_str, "EndSection", 10)) { current_str = next_str; @@ -3300,7 +3516,20 @@ char **nxt_str, int verb_index, int ctrl_list_type) &list->effects_mixer_ctl); if (ret < 0) break; - ALOGV("Effects mixer ctl: %s: %d\n", list->effects_mixer_ctl); + ALOGV("Effects mixer ctl: %s:\n", list->effects_mixer_ctl); + } else if (strcasestr(current_str, "PlaybackVolume") != NULL) { + ret = snd_ucm_extract_volume_mixer_ctl(current_str, + &list->volume_mixer_ctl); + if (ret < 0) + break; + ALOGV("Volume mixer ctl: %s:\n", list->volume_mixer_ctl); + } else if (strcasestr(current_str, "EC_REF_RXMixerCTL") != NULL) { + ret = snd_ucm_extract_ec_ref_rx_mixer_ctl(current_str, + &list->ec_ref_rx_mixer_ctl); + ALOGV("EC_REF_RX mixer ctl: ret:%d\n", ret); + if (ret < 0) + break; + ALOGE("EC_REF_RX mixer ctl: %s\n", list->ec_ref_rx_mixer_ctl); } if (strcasestr(current_str, "EnableSequence") != NULL) { controls_count = get_controls_count(next_str); @@ -3420,6 +3649,56 @@ static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name) return ret; } +/* Extract Volume Mixer ID string of usecase from config file + * Returns 0 on sucess, negative error code otherwise + */ +static int snd_ucm_extract_volume_mixer_ctl(char *buf, char **mixer_name) +{ + int ret = 0; + char *p, *name = *mixer_name, *temp_ptr; + + p = strtok_r(buf, "\"", &temp_ptr); + while (p != NULL) { + p = strtok_r(NULL, "\"", &temp_ptr); + if (p == NULL) + break; + name = (char *)malloc((strlen(p)+1)*sizeof(char)); + if(name == NULL) { + ret = -ENOMEM; + break; + } + strlcpy(name, p, (strlen(p)+1)*sizeof(char)); + *mixer_name = name; + break; + } + return ret; +} + +/* Extract Effects Mixer ID of device from config file + * Returns 0 on sucess, negative error code otherwise + */ +static int snd_ucm_extract_ec_ref_rx_mixer_ctl(char *buf, char **mixer_name) +{ + int ret = 0; + char *p, *name = *mixer_name, *temp_ptr; + + p = strtok_r(buf, "\"", &temp_ptr); + while (p != NULL) { + p = strtok_r(NULL, "\"", &temp_ptr); + if (p == NULL) + break; + name = (char *)malloc((strlen(p)+1)*sizeof(char)); + if(name == NULL) { + ret = -ENOMEM; + break; + } + strlcpy(name, p, (strlen(p)+1)*sizeof(char)); + *mixer_name = name; + break; + } + return ret; +} + /* Extract a playback and capture device name of use case from config file * Returns 0 on sucess, negative error code otherwise */ @@ -3639,6 +3918,12 @@ void free_list(card_mctrl_t *list, int verb_index, int count) if(list[case_index].effects_mixer_ctl) { list[case_index].effects_mixer_ctl = NULL; } + if(list[case_index].volume_mixer_ctl) { + list[case_index].volume_mixer_ctl = NULL; + } + if(list[case_index].ec_ref_rx_mixer_ctl) { + list[case_index].ec_ref_rx_mixer_ctl = NULL; + } } } diff --git a/legacy/libalsa-intf/alsaucm_test.c b/legacy/libalsa-intf/alsaucm_test.c index e01cf59c1..04d38682d 100644 --- a/legacy/libalsa-intf/alsaucm_test.c +++ b/legacy/libalsa-intf/alsaucm_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 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 @@ -10,7 +10,7 @@ * 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 Code Aurora Forum, Inc. nor the names of its + * * 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. * @@ -36,6 +36,11 @@ #include #include +#ifndef ANDROID +#include +#define strlcat g_strlcat +#endif + #include "alsa_ucm.h" #include "msm8960_use_cases.h" @@ -208,7 +213,6 @@ static int process_cmd(char *cmdStr) fprintf(stderr, "%s: error failed to open sound card %s: %d\n", cmd->cmd_str, identifier, err); return err; } - snd_use_case_mgr_wait_for_parsing(uc_mgr); break; case UCM_LISTCARDS: diff --git a/legacy/libalsa-intf/amix.c b/legacy/libalsa-intf/amix.c index 40f38077a..b425ed572 100644 --- a/legacy/libalsa-intf/amix.c +++ b/legacy/libalsa-intf/amix.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/legacy/libalsa-intf/aplay.c b/legacy/libalsa-intf/aplay.c index c0602775c..e82582ceb 100644 --- a/legacy/libalsa-intf/aplay.c +++ b/legacy/libalsa-intf/aplay.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -27,6 +27,8 @@ #include #include +#include +#include #include "alsa_audio.h" #ifndef ANDROID @@ -41,14 +43,28 @@ #define FORMAT_PCM 1 #define LOG_NDEBUG 1 + +struct output_metadata_handle_t { + uint32_t metadataLength; + uint32_t bufferLength; + uint64_t timestamp; + uint32_t reserved[12]; +}; + +static struct output_metadata_handle_t outputMetadataTunnel; + static pcm_flag = 1; static debug = 0; static uint32_t play_max_sz = 2147483648LL; static int format = SNDRV_PCM_FORMAT_S16_LE; static int period = 0; static int compressed = 0; +static int set_channel_map = 0; +static char channel_map[8]; static char *compr_codec; static int piped = 0; +static int outputMetadataLength = 0; +static int eosSet = 0; static struct option long_options[] = { @@ -61,6 +77,7 @@ static struct option long_options[] = {"format", 1, 0, 'F'}, {"period", 1, 0, 'B'}, {"compressed", 0, 0, 'T'}, + {"channelMap", 0, 0, 'X'}, {0, 0, 0, 0} }; @@ -80,6 +97,13 @@ struct wav_header { uint32_t data_sz; }; + +void updateMetaData(size_t bytes) { + outputMetadataTunnel.metadataLength = sizeof(outputMetadataTunnel); + outputMetadataTunnel.timestamp = 0; + outputMetadataTunnel.bufferLength = bytes; + fprintf(stderr, "bytes = %d\n", bytes); +} static int set_params(struct pcm *pcm) { struct snd_pcm_hw_params *params; @@ -88,7 +112,17 @@ static int set_params(struct pcm *pcm) unsigned long periodSize, bufferSize, reqBuffSize; unsigned int periodTime, bufferTime; unsigned int requestedRate = pcm->rate; - int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 ); + int channels; + if(pcm->flags & PCM_MONO) + channels = 1; + else if(pcm->flags & PCM_QUAD) + channels = 4; + else if(pcm->flags & PCM_5POINT1) + channels = 6; + else if(pcm->flags & PCM_7POINT1) + channels = 8; + else + channels = 2; params = (struct snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params)); if (!params) { @@ -161,6 +195,25 @@ static int set_params(struct pcm *pcm) return 0; } +void send_channel_map_driver(struct pcm *pcm) +{ + int i, ret; + struct mixer *mixer; + const char* device = "/dev/snd/controlC0"; + + mixer = mixer_open(device); + if (!mixer) { + fprintf(stderr,"oops: %s: %d\n", strerror(errno), __LINE__); + return; + } + ret = pcm_set_channel_map(pcm, mixer, 8, channel_map); + if (ret < 0) + fprintf(stderr, "could not set channel mask\n"); + mixer_close(mixer); + + return; +} + static int play_file(unsigned rate, unsigned channels, int fd, unsigned flags, const char *device, unsigned data_sz) { @@ -183,8 +236,12 @@ static int play_file(unsigned rate, unsigned channels, int fd, if (channels == 1) flags |= PCM_MONO; + else if (channels == 4) + flags |= PCM_QUAD; else if (channels == 6) flags |= PCM_5POINT1; + else if (channels == 8) + flags |= PCM_7POINT1; else flags |= PCM_STEREO; @@ -202,7 +259,6 @@ static int play_file(unsigned rate, unsigned channels, int fd, return -EBADFD; } -#ifdef QCOM_COMPRESSED_AUDIO_ENABLED if (compressed) { struct snd_compr_caps compr_cap; struct snd_compr_params compr_params; @@ -214,12 +270,16 @@ static int play_file(unsigned rate, unsigned channels, int fd, if (!period) period = compr_cap.min_fragment_size; switch (get_compressed_format(compr_codec)) { - case FORMAT_MP3: - compr_params.codec.id = compr_cap.codecs[FORMAT_MP3]; + case SND_AUDIOCODEC_MP3: + compr_params.codec.id = SND_AUDIOCODEC_MP3; + break; + case SND_AUDIOCODEC_AC3_PASS_THROUGH: + compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH; + printf("codec -d = %x\n", SND_AUDIOCODEC_AC3_PASS_THROUGH); break; - case FORMAT_AC3_PASS_THROUGH: - compr_params.codec.id = compr_cap.codecs[FORMAT_AC3_PASS_THROUGH]; - printf("codec -d = %x\n", compr_params.codec.id); + case SND_AUDIOCODEC_AAC: + compr_params.codec.id = SND_AUDIOCODEC_AAC; + printf("codec -d = %x\n", SND_AUDIOCODEC_AAC); break; default: break; @@ -229,8 +289,12 @@ static int play_file(unsigned rate, unsigned channels, int fd, pcm_close(pcm); return -errno; } + outputMetadataLength = sizeof(struct output_metadata_handle_t); + } else if (channels > 2) { + if(set_channel_map) { + send_channel_map_driver(pcm); + } } -#endif pcm->channels = channels; pcm->rate = rate; pcm->flags = flags; @@ -278,7 +342,7 @@ static int play_file(unsigned rate, unsigned channels, int fd, pfd[0].fd = pcm->timer_fd; pfd[0].events = POLLIN; - frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4); + frames = bufsize / (2*channels); for (;;) { if (!pcm->running) { if (pcm_prepare(pcm)) { @@ -338,16 +402,23 @@ static int play_file(unsigned rate, unsigned channels, int fd, if (data_sz && !piped) { if (remainingData < bufsize) { bufsize = remainingData; - frames = (pcm->flags & PCM_MONO) ? (remainingData / 2) : (remainingData / 4); + frames = remainingData / (2*channels); } } + fprintf(stderr, "addr = %d, size = %d \n", (dst_addr + outputMetadataLength),(bufsize - outputMetadataLength)); + err = read(fd, (dst_addr + outputMetadataLength) , (bufsize - outputMetadataLength)); + if(compressed) { + updateMetaData(err); + memcpy(dst_addr, &outputMetadataTunnel, outputMetadataLength); + } - err = read(fd, dst_addr , bufsize); if (debug) fprintf(stderr, "read %d bytes from file\n", err); - if (err <= 0) + if (err <= 0 ) { + fprintf(stderr," EOS set\n "); + eosSet = 1; break; - + } if (data_sz && !piped) { remainingData -= bufsize; if (remainingData <= 0) @@ -374,15 +445,13 @@ static int play_file(unsigned rate, unsigned channels, int fd, fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld sync_ptr->c.control.appl_ptr %ld\n", pcm->sync_ptr->s.status.hw_ptr, pcm->sync_ptr->c.control.appl_ptr); -#ifdef QCOM_COMPRESSED_AUDIO_ENABLED if (compressed && start) { struct snd_compr_tstamp tstamp; - if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp)) - fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n"); + if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp)) + fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n"); else - fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp); - } -#endif + fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp); + } } /* * If we have reached start threshold of buffer prefill, @@ -409,6 +478,7 @@ static int play_file(unsigned rate, unsigned channels, int fd, start_done: offset += frames; } + while(1) { pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC; sync_ptr(pcm); @@ -420,6 +490,14 @@ start_done: fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld sync_ptr->c.control.appl_ptr %ld\n", pcm->sync_ptr->s.status.hw_ptr, pcm->sync_ptr->c.control.appl_ptr); + + if(compressed && eosSet) { + fprintf(stderr,"Audio Drain DONE ++\n"); + if ( ioctl(pcm->fd, SNDRV_COMPRESS_DRAIN) < 0 ) { + fprintf(stderr,"Audio Drain failed\n"); + } + fprintf(stderr,"Audio Drain DONE --\n"); + } break; } else poll(pfd, nfds, TIMEOUT_INFINITE); @@ -491,7 +569,7 @@ int play_raw(const char *fg, int rate, int ch, const char *device, const char *f flag = PCM_NMMAP; fprintf(stderr, "aplay: Playing '%s': format %s ch = %d\n", - fn, get_format_desc(format), ch ); + fn, get_format_desc(format), ch ); return play_file(rate, ch, fd, flag, device, 0); } @@ -556,6 +634,45 @@ ignore_header: return play_file(hdr.sample_rate, hdr.num_channels, fd, flag, device, hdr.data_sz); } +char get_channel_map_val(char *string) +{ + char retval = 0; + if( !strncmp(string, "RRC", sizeof(string)) ) + retval = 16; + else if( !strncmp(string, "RLC", sizeof(string)) ) + retval = 15; + else if( !strncmp(string, "FRC", sizeof(string)) ) + retval = 14; + else if( !strncmp(string, "FLC", sizeof(string)) ) + retval = 13; + else if( !strncmp(string, "MS", sizeof(string)) ) + retval = 12; + else if( !strncmp(string, "CVH", sizeof(string)) ) + retval = 11; + else if( !strncmp(string, "TS", sizeof(string)) ) + retval = 10; + else if( !strncmp(string, "RB", sizeof(string)) ) + retval = 9; + else if( !strncmp(string, "LB", sizeof(string)) ) + retval = 8; + else if( !strncmp(string, "CS", sizeof(string)) ) + retval = 7; + else if( !strncmp(string, "LFE", sizeof(string)) ) + retval = 6; + else if( !strncmp(string, "RS", sizeof(string)) ) + retval = 5; + else if( !strncmp(string, "LS", sizeof(string)) ) + retval = 4; + else if( !strncmp(string, "FC", sizeof(string)) ) + retval = 3; + else if( !strncmp(string, "FR", sizeof(string)) ) + retval = 2; + else if( !strncmp(string, "FL", sizeof(string)) ) + retval = 1; + + return retval; +} + int main(int argc, char **argv) { int option_index = 0; @@ -565,20 +682,25 @@ int main(int argc, char **argv) char *mmap = "N"; char *device = "hw:0,0"; char *filename; + char *ptr; int rc = 0; if (argc <2) { printf("\nUsage: aplay [options] \n" "options:\n" - "-D -- Alsa PCM by name\n" - "-M -- Mmap stream\n" - "-P -- Hostless steam[No PCM]\n" - "-C -- Channels\n" - "-R -- Rate\n" - "-V -- verbose\n" - "-F -- Format\n" + "-D -- Alsa PCM by name\n" + "-M -- Mmap stream\n" + "-P -- Hostless steam[No PCM]\n" + "-C -- Channels\n" + "-R -- Rate\n" + "-V -- verbose\n" + "-F -- Format\n" "-B -- Period\n" "-T -- Compressed\n" + "-X <\"FL,FR,FC,Ls,Rs,LFE\" for 5.1 configuration\n" + " supported channels: \n" + " FL, FR, FC, LS, RS, LFE, CS, TS \n" + " LB, RB, FLC, FRC, RLC, RRC, CVH, MS\n" " \n"); fprintf(stderr, "Formats Supported:\n"); for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; ++i) @@ -587,7 +709,7 @@ int main(int argc, char **argv) fprintf(stderr, "\nSome of these may not be available on selected hardware\n"); return 0; } - while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:X:", long_options, &option_index)) != -1) { switch (c) { case 'P': pcm_flag = 0; @@ -619,18 +741,35 @@ int main(int argc, char **argv) printf("compressed codec type requested = %s\n", optarg); compr_codec = optarg; break; + case 'X': + set_channel_map = 1; i = 0; + memset(channel_map, 0, sizeof(channel_map)); + ptr = strtok(optarg, ","); + while((ptr != NULL) && (i < sizeof(channel_map))) { + channel_map[i] = get_channel_map_val(ptr); + if (channel_map[i] < 0 || channel_map[i] > 16) { + set_channel_map = 0; + break; + } + ptr = strtok(NULL,","); i++; + } + break; default: printf("\nUsage: aplay [options] \n" "options:\n" - "-D -- Alsa PCM by name\n" - "-M -- Mmap stream\n" - "-P -- Hostless steam[No PCM]\n" - "-V -- verbose\n" - "-C -- Channels\n" - "-R -- Rate\n" - "-F -- Format\n" + "-D -- Alsa PCM by name\n" + "-M -- Mmap stream\n" + "-P -- Hostless steam[No PCM]\n" + "-V -- verbose\n" + "-C -- Channels\n" + "-R -- Rate\n" + "-F -- Format\n" "-B -- Period\n" "-T -- Compressed\n" + "-X <\"FL,FR,FC,Ls,Rs,LFE\" for 5.1 configuration\n" + " supported channels: \n" + " FL, FR, FC, LS, RS, LFE, CS, TS \n" + " LB, RB, FLC, FRC, RLC, RRC, CVH, MS\n" " \n"); fprintf(stderr, "Formats Supported:\n"); for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i) @@ -654,7 +793,7 @@ int main(int argc, char **argv) } if (pcm_flag) { - if (format == SNDRV_PCM_FORMAT_S16_LE) + if (format == SNDRV_PCM_FORMAT_S16_LE) rc = play_wav(mmap, rate, ch, device, filename); else rc = play_raw(mmap, rate, ch, device, filename); diff --git a/legacy/libalsa-intf/arec.c b/legacy/libalsa-intf/arec.c index cab88f119..edd4af404 100644 --- a/legacy/libalsa-intf/arec.c +++ b/legacy/libalsa-intf/arec.c @@ -1,6 +1,6 @@ /* ** Copyright 2010, The Android Open-Source Project -** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. +** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -28,6 +28,10 @@ #include #include +#include +#include +#include + #include "alsa_audio.h" #define ID_RIFF 0x46464952 @@ -42,17 +46,20 @@ #define strlcpy g_strlcpy #endif +#define COMPR_META_DATA_SIZE 64 static struct wav_header hdr; static int fd; static struct pcm *pcm; -static int debug = 0; -static int pcm_flag = 1; -static int duration = 0; +static debug = 0; +static pcm_flag = 1; +static duration = 0; static char *filename; static char *data; static int format = SNDRV_PCM_FORMAT_S16_LE; static int period = 0; static int piped = 0; +static int compressed = 0; +static char *compr_codec; static struct option long_options[] = { @@ -65,6 +72,7 @@ static struct option long_options[] = {"duration", 1, 0, 'T'}, {"format", 1, 0, 'F'}, {"period", 1, 0, 'B'}, + {"compressed", 1, 0, 'K'}, {0, 0, 0, 0} }; @@ -177,7 +185,7 @@ static int set_params(struct pcm *pcm) int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsigned flags, const char *device) { - unsigned xfer, bufsize; + unsigned xfer, bufsize, framesize; int r, avail; int nfds = 1; static int start = 0; @@ -187,7 +195,7 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig int err; struct pollfd pfd[1]; int rec_size = 0; - + framesize = 0; flags |= PCM_IN; if (channels == 1) @@ -204,6 +212,41 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig pcm_close(pcm); goto fail; } + + if (compressed) { + struct snd_compr_caps compr_cap; + struct snd_compr_params compr_params; + printf("SNDRV_COMPRESS_GET_CAPS= 0x%X\n", SNDRV_COMPRESS_GET_CAPS); + if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) { + fprintf(stderr, "AREC: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno); + pcm_close(pcm); + return -errno; + } + if (!period) + period = compr_cap.min_fragment_size; + switch (get_compressed_format(compr_codec)) { + case SND_AUDIOCODEC_MP3: + compr_params.codec.id = SND_AUDIOCODEC_MP3; + break; + case SND_AUDIOCODEC_AC3_PASS_THROUGH: + compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH; + printf("codec -d = %x\n", compr_params.codec.id); + break; + case SND_AUDIOCODEC_AMRWB: + compr_params.codec.id = SND_AUDIOCODEC_AMRWB; + compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/ + compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/ + printf("codec -d = %x\n", compr_params.codec.id); + break; + default: + break; + } + if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) { + fprintf(stderr, "AREC: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno); + pcm_close(pcm); + return -errno; + } + } pcm->channels = channels; pcm->rate = rate; pcm->flags = flags; @@ -248,17 +291,18 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig } bufsize = pcm->period_size; + if (debug) - fprintf(stderr, "Arec:bufsize = %d\n", bufsize); + fprintf(stderr, "Arec:bufsize = %d\n", bufsize); if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) { - if (errno == EPIPE) { + if (errno == EPIPE) { fprintf(stderr, "Arec:Failed in SNDRV_PCM_IOCTL_START\n"); /* we failed to make our window -- try to restart */ pcm->running = 0; - } else { - fprintf(stderr, "Arec:Error no %d \n", errno); - return -errno; - } + } else { + fprintf(stderr, "Arec:Error no %d \n", errno); + return -errno; + } } pfd[0].fd = pcm->fd; @@ -276,20 +320,20 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig } x.frames = frames; for(;;) { - if (!pcm->running) { - if (pcm_prepare(pcm)) - return --errno; - start = 0; - } - /* Sync the current Application pointer from the kernel */ - pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC; - err = sync_ptr(pcm); - if (err == EPIPE) { - fprintf(stderr, "Arec:Failed in sync_ptr \n"); - /* we failed to make our window -- try to restart */ - //pcm->overruns++; - pcm->running = 0; - continue; + if (!pcm->running) { + if (pcm_prepare(pcm)) + return --errno; + start = 0; + } + /* Sync the current Application pointer from the kernel */ + pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;/*SNDRV_PCM_SYNC_PTR_HWSYNC;*/ + err = sync_ptr(pcm); + if (err == EPIPE) { + fprintf(stderr, "Arec:Failed in sync_ptr \n"); + /* we failed to make our window -- try to restart */ + //pcm->overruns++; + pcm->running = 0; + continue; } /* * Check for the available data in driver. If available data is @@ -297,14 +341,16 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig */ avail = pcm_avail(pcm); if (debug) - fprintf(stderr, "Arec:avail 1 = %d frames = %ld\n",avail, frames); + fprintf(stderr, "Arec:avail 1 = %d frames = %ld, avail_min = %d," + "x.frames = %d, bufsize = %d, dst_addr = %p\n",avail, frames, + (int)pcm->sw_p->avail_min, (int)x.frames, bufsize, dst_addr); if (avail < 0) return avail; if (avail < pcm->sw_p->avail_min) { poll(pfd, nfds, TIMEOUT_INFINITE); continue; } - if (x.frames > avail) + if (x.frames > avail) frames = avail; /* * Now that we have data size greater than avail_min available to @@ -312,18 +358,31 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig * start reading from. */ dst_addr = dst_address(pcm); + if (compressed) { + framesize = (unsigned)(dst_addr[3] << 24) + (unsigned)(dst_addr[2] << 16) + + (unsigned) (dst_addr[1] << 8) + (unsigned)dst_addr[0]; + if (debug) + fprintf(stderr, "Arec:dst_addr[0] = %d, dst_addr[1] = %d," + "dst_addr[2] = %d, dst_addr[3] = %d, dst_addr[4] = %d," + "dst_addr[5] = %d, dst_addr = %p, bufsize = %d, framesize = %d\n", + dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3], dst_addr[4], + dst_addr[5],dst_addr, bufsize, framesize); + dst_addr += COMPR_META_DATA_SIZE; + } else { + framesize = bufsize; + } /* * Write to the file at the destination address from kernel mmaped buffer * This reduces a extra copy of intermediate buffer. */ - if (write(fd, dst_addr, bufsize) != bufsize) { - fprintf(stderr, "Arec:could not write %d bytes\n", bufsize); + if (write(fd, dst_addr, framesize) != framesize) { + fprintf(stderr, "Arec:could not write %d bytes\n", framesize); return -errno; } x.frames -= frames; pcm->sync_ptr->c.control.appl_ptr += frames; - pcm->sync_ptr->flags = 0; + pcm->sync_ptr->flags = 0; err = sync_ptr(pcm); if (err == EPIPE) { fprintf(stderr, "Arec:Failed in sync_ptr \n"); @@ -332,12 +391,14 @@ int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsig continue; } rec_size += bufsize; - hdr.data_sz += bufsize; - hdr.riff_sz = hdr.data_sz + 44 - 8; - if (!piped) { - lseek(fd, 0, SEEK_SET); - write(fd, &hdr, sizeof(hdr)); - lseek(fd, 0, SEEK_END); + if (!compressed) { + hdr.data_sz += bufsize; + hdr.riff_sz = hdr.data_sz + 44 - 8; + if (!piped) { + lseek(fd, 0, SEEK_SET); + write(fd, &hdr, sizeof(hdr)); + lseek(fd, 0, SEEK_END); + } } if (rec_size >= count) break; @@ -391,7 +452,7 @@ int rec_raw(const char *fg, const char *device, int rate, int ch, uint32_t rec_max_sz = 2147483648LL; uint32_t count; int i = 0; - + printf("rec_raw-> pcm_flag = %d\n", pcm_flag); if (!fn) { fd = fileno(stdout); piped = 1; @@ -427,53 +488,60 @@ int rec_wav(const char *fg, const char *device, int rate, int ch, const char *fn uint32_t rec_max_sz = 2147483648LL; uint32_t count = 0; int i = 0; - + printf("rec_wav-> pcm_flag = %d\n", pcm_flag); if (pcm_flag) { - if (!fn) { - fd = fileno(stdout); - piped = 1; - } else { - fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); - if (fd < 0) { - fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn); - return -EBADFD; - } + if (!fn) { + fd = fileno(stdout); + piped = 1; + } else { + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); + if (fd < 0) { + fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn); + return -EBADFD; } - memset(&hdr, 0, sizeof(struct wav_header)); - hdr.riff_id = ID_RIFF; - hdr.riff_fmt = ID_WAVE; - hdr.fmt_id = ID_FMT; - hdr.fmt_sz = 16; - hdr.audio_format = FORMAT_PCM; - hdr.num_channels = ch; - hdr.sample_rate = rate; - hdr.bits_per_sample = 16; - hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8; - hdr.block_align = ( hdr.bits_per_sample * ch ) / 8; - hdr.data_id = ID_DATA; - hdr.data_sz = 0; - - if (duration == 0) { - count = rec_max_sz; - } else { - count = rate * ch * 2; - count *= (uint32_t)duration; - } - hdr.riff_sz = hdr.data_sz + 44 - 8; - if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { - if (debug) - fprintf(stderr, "arec: cannot write header\n"); - return -errno; - } - if (debug) - fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n", - hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample, - hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown"); - } else { + } + if (compressed) { + + printf("rec_wav-> compressed = %d\n", compressed); hdr.sample_rate = rate; hdr.num_channels = ch; + goto ignore_header; + } + memset(&hdr, 0, sizeof(struct wav_header)); + hdr.riff_id = ID_RIFF; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = ch; + hdr.sample_rate = rate; + hdr.bits_per_sample = 16; + hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8; + hdr.block_align = ( hdr.bits_per_sample * ch ) / 8; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + hdr.riff_sz = hdr.data_sz + 44 - 8; + if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + if (debug) + fprintf(stderr, "arec: cannot write header\n"); + return -errno; + } + if (debug) + fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n", + hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample, + hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown"); + } else { + hdr.sample_rate = rate; + hdr.num_channels = ch; } +ignore_header: + if (duration == 0) { + count = rec_max_sz; + } else { + count = rate * ch * 2; + count *= (uint32_t)duration; + } if (!strncmp(fg, "M", sizeof("M"))) { flag = PCM_MMAP; } else if (!strncmp(fg, "N", sizeof("N"))) { @@ -521,25 +589,26 @@ int main(int argc, char **argv) int rc = 0; if (argc < 2) { - printf("\nUsage: arec [options] \n" - "options:\n" - "-D -- Alsa PCM by name\n" - "-M -- Mmap stream\n" - "-P -- Hostless steam[No PCM]\n" - "-V -- verbose\n" - "-C -- Channels\n" - "-R -- Rate\n" - "-T -- Time in seconds for recording\n" - "-F -- Format\n" - "-B -- Period\n" - " \n"); + printf("\nUsage: arec [options] \n" + "options:\n" + "-D -- Alsa PCM by name\n" + "-M -- Mmap stream\n" + "-P -- Hostless steam[No PCM]\n" + "-V -- verbose\n" + "-C -- Channels\n" + "-R -- Rate\n" + "-T -- Time in seconds for recording\n" + "-F -- Format\n" + "-B -- Period\n" + "-K -- compressed\n" + " \n"); for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i) if (get_format_name(i)) fprintf(stderr, "%s ", get_format_name(i)); fprintf(stderr, "\nSome of these may not be available on selected hardware\n"); return 0; } - while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:K:", long_options, &option_index)) != -1) { switch (c) { case 'P': pcm_flag = 0; @@ -568,18 +637,24 @@ int main(int argc, char **argv) case 'B': period = (int)strtol(optarg, NULL, 0); break; + case 'K': + compressed = 1; + printf("compressed codec type requested = %s\n", optarg); + compr_codec = optarg; + break; default: printf("\nUsage: arec [options] \n" "options:\n" - "-D -- Alsa PCM by name\n" - "-M -- Mmap stream\n" - "-P -- Hostless steam[No PCM]\n" - "-V -- verbose\n" - "-C -- Channels\n" - "-R -- Rate\n" - "-T -- Time in seconds for recording\n" - "-F -- Format\n" - "-B -- Period\n" + "-D -- Alsa PCM by name\n" + "-M -- Mmap stream\n" + "-P -- Hostless steam[No PCM]\n" + "-V -- verbose\n" + "-C -- Channels\n" + "-R -- Rate\n" + "-T -- Time in seconds for recording\n" + "-F -- Format\n" + "-B -- Period\n" + "-K -- compressed\n" " \n"); for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i) if (get_format_name(i)) diff --git a/legacy/libalsa-intf/msm8960_use_cases.h b/legacy/libalsa-intf/msm8960_use_cases.h index 4c37cd077..cdaba8692 100644 --- a/legacy/libalsa-intf/msm8960_use_cases.h +++ b/legacy/libalsa-intf/msm8960_use_cases.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-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 @@ -10,7 +10,7 @@ * 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 Code Aurora Forum, Inc. nor the names of its + * * 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. * @@ -35,8 +35,8 @@ extern "C" { #include "alsa_ucm.h" #include "alsa_audio.h" -#include #include +#include #define SND_UCM_END_OF_LIST "end" /* ACDB Device ID macros */ @@ -44,18 +44,20 @@ extern "C" { #define CAP_TX 0x2 #define CAP_VOICE 0x4 #define DEVICE_HANDSET_RX_ACDB_ID 7 // HANDSET_SPKR -#define DEVICE_HANDSET_RX_TMUS_ACDB_ID 81// HANDSET_SPKR #define DEVICE_HANDSET_TX_ACDB_ID 4 // HANDSET_MIC +#define DEVICE_SPEAKER_RX_ACDB_ID 15// SPKR_PHONE_SPKR_STEREO #define DEVICE_SPEAKER_MONO_RX_ACDB_ID 14// SPKR_PHONE_SPKR_MONO #define DEVICE_SPEAKER_STEREO_RX_ACDB_ID 15// SPKR_PHONE_SPKR_STEREO #define DEVICE_SPEAKER_TX_ACDB_ID 11// SPKR_PHONE_MIC #define DEVICE_HEADSET_RX_ACDB_ID 10// HEADSET_SPKR_STEREO +#define DEVICE_HEADSET_MONO_RX_ACDB_ID 9 // HEADSET_SPKR_MONO #define DEVICE_HEADSET_TX_ACDB_ID 8 // HEADSET_MIC #define DEVICE_DUALMIC_HANDSET_TX_BROADSIDE_ACDB_ID 5 // HANDSET_MIC_BROADSIDE #define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_ACDB_ID 6 // HANDSET_MIC_ENDFIRE -#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_TMUS_ACDB_ID 91// HANDSET_MIC_ENDFIRE #define DEVICE_DUALMIC_SPEAKER_TX_BROADSIDE_ACDB_ID 12// SPKR_PHONE_MIC_BROADSIDE #define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_ACDB_ID 13// SPKR_PHONE_MIC_ENDFIRE +#define DEVICE_DUALMIC_HANDSET_STEREO_ACDB_ID 34 +#define DEVICE_DUALMIC_SPEAKER_PHONE_STEREO_ACDB_ID 35 #define DEVICE_TTY_HEADSET_MONO_RX_ACDB_ID 17// TTY_HEADSET_SPKR #define DEVICE_TTY_HEADSET_MONO_TX_ACDB_ID 16// TTY_HEADSET_MIC #define DEVICE_BT_SCO_RX_ACDB_ID 22// BT_SCO_SPKR @@ -69,13 +71,12 @@ extern "C" { #define DEVICE_PROXY_RX_ACDB_ID DEVICE_HDMI_STEREO_RX_ACDB_ID #define DEVICE_TTY_VCO_HANDSET_TX_ACDB_ID 36// TTY_VCO_HANDSET_MIC #define DEVICE_TTY_HCO_HANDSET_RX_ACDB_ID 37// TTY_HCO_HANDSET_SPRK -#define DEVICE_HANDSET_TX_FV5_ACDB_ID 50 -#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_FV5_ACDB_ID 51 -#define DEVICE_SPEAKER_TX_FV5_ACDB_ID 52 -#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_FV5_ACDB_ID 53 -#define DEVICE_INCALL_VOICE_RECORD_STEREO_ACDB_ID 45 -#define DEVICE_INCALL_MUSIC_DELIVERY_MONO_ACDB_ID 46 -#define DEVICE_INCALL_VOICE_RECORD_MONO_ACDB_ID 47 +#define DEVICE_HANDSET_TX_FV5_ACDB_ID 40 +#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_FV5_ACDB_ID 41 +#define DEVICE_SPEAKER_TX_FV5_ACDB_ID 42 +#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_FV5_ACDB_ID 43 +#define DEVICE_USB_RX_ACDB_ID 45// USB_Rx +#define DEVICE_USB_TX_ACDB_ID 44// USB_Tx #define DEVICE_CAMCORDER_TX_ACDB_ID 61// CAMCORDER_TX #define DEVICE_VOICE_RECOGNITION_ACDB_ID 62// VOICE_RECOGNITION @@ -120,6 +121,8 @@ typedef struct card_mctrl { int acdb_id; int capability; char *effects_mixer_ctl; + char *volume_mixer_ctl; + char *ec_ref_rx_mixer_ctl; }card_mctrl_t; /* identifier node structure for identifier list*/ @@ -171,7 +174,6 @@ struct snd_use_case_mgr { int current_rx_device; card_ctxt_t *card_ctxt_ptr; pthread_t thr; - void *acdb_handle; bool isFusion3Platform; }; @@ -181,8 +183,17 @@ struct snd_use_case_mgr { static const char *card_list[] = { "snd_soc_msm", "snd_soc_msm_2x", + "snd_soc_msm_2x_mpq", "snd_soc_msm_2x_Fusion3", "snd_soc_msm_Sitar", + "snd_soc_msm_Sitar_Sglte", + "snd_soc_msm_I2S", + "snd_soc_msm_Taiko", + "snd_soc_msm_Taiko_CDP", + "snd_soc_msm_Taiko_Fluid", + "snd_soc_msm_Taiko_liquid", + "snd_soc_msm_I2SFusion", + "us_soc_msm", }; typedef struct card_mapping { @@ -194,8 +205,17 @@ typedef struct card_mapping { static card_mapping_t card_mapping_list[] = { {"snd_soc_msm", 0}, {"snd_soc_msm_2x", 0}, + {"snd_soc_msm_2x_mpq", 0}, {"snd_soc_msm_2x_Fusion3", 0}, {"snd_soc_msm_Sitar", 0}, + {"snd_soc_msm_Sitar_Sglte", 0}, + {"snd_soc_msm_I2S", 0}, + {"snd_soc_msm_Taiko", 0}, + {"snd_soc_msm_Taiko_CDP", 0}, + {"snd_soc_msm_Taiko_Fluid", 0}, + {"snd_soc_msm_Taiko_liquid", 0}, + {"snd_soc_msm_I2SFusion", 0}, + {"us_soc_msm", 0}, }; /* New use cases, devices and modifiers added @@ -207,6 +227,8 @@ static card_mapping_t card_mapping_list[] = { #define SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC "HiFi Lowlatency Rec" #define SND_USE_CASE_VERB_DL_REC "DL REC" #define SND_USE_CASE_VERB_UL_DL_REC "UL DL REC" +#define SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL "Compressed DL REC" +#define SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL "Compressed UL DL REC" #define SND_USE_CASE_VERB_HIFI_TUNNEL "HiFi Tunnel" #define SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC "HiFi Lowlatency" #define SND_USE_CASE_VERB_HIFI2 "HiFi2" @@ -214,9 +236,16 @@ static card_mapping_t card_mapping_list[] = { #define SND_USE_CASE_VERB_MI2S "MI2S" #define SND_USE_CASE_VERB_VOLTE "VoLTE" #define SND_USE_CASE_VERB_ADSP_TESTFWK "ADSP testfwk" +#define SND_USE_CASE_VERB_HIFI_REC2 "HiFi Rec2" +#define SND_USE_CASE_VERB_HIFI_REC_COMPRESSED "HiFi Rec Compressed" +#define SND_USE_CASE_VERB_HIFI3 "HiFi3" +#define SND_USE_CASE_VERB_HIFI_TUNNEL2 "HiFi Tunnel2" +#define SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL "HiFi Pseudo Tunnel" +#define SND_USE_CASE_VERB_VOICE2 "Voice2" #define SND_USE_CASE_DEV_FM_TX "FM Tx" #define SND_USE_CASE_DEV_ANC_HEADSET "ANC Headset" +#define SND_USE_CASE_DEV_ANC_HANDSET "ANC Handset" #define SND_USE_CASE_DEV_BTSCO_NB_RX "BT SCO Rx" #define SND_USE_CASE_DEV_BTSCO_NB_TX "BT SCO Tx" #define SND_USE_CASE_DEV_BTSCO_WB_RX "BT SCO WB Rx" @@ -232,20 +261,26 @@ static card_mapping_t card_mapping_list[] = { #define SND_USE_CASE_DEV_TTY_HANDSET_TX "TTY Handset Tx" #define SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX "TTY Handset Analog Tx" #define SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE "DMIC Broadside" -#define SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC "DMIC Broadside Voice Rec" #define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE "DMIC Endfire" -#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_TMUS "DMIC Endfire TMUS" -#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC "DMIC Endfire Voice Rec" +#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_SGLTE "DMIC Endfire Voice2" +#define SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO "Handset DMIC Stereo" +#define SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO_SGLTE "Handset DMIC Stereo Voice2" #define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE "Speaker DMIC Broadside" #define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE "Speaker DMIC Endfire" +#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE_SGLTE "Speaker DMIC Endfire Voice2" +#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO "Speaker DMIC Stereo" +#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO_SGLTE "Speaker DMIC Stereo Voice2" #define SND_USE_CASE_DEV_HDMI_TX "HDMI Tx" #define SND_USE_CASE_DEV_HDMI_SPDIF "HDMI SPDIF" +#define SND_USE_CASE_DEV_HDMI_SPDIF_SPEAKER "HDMI SPDIF Speaker" #define SND_USE_CASE_DEV_QUAD_MIC "QMIC" #define SND_USE_CASE_DEV_SSR_QUAD_MIC "SSR QMIC" #define SND_USE_CASE_DEV_PROXY_RX "PROXY Rx" #define SND_USE_CASE_DEV_PROXY_TX "PROXY Tx" -#define SND_USE_CASE_DEV_HDMI_SPEAKER "HDMI Speaker" +#define SND_USE_CASE_DEV_USB_PROXY_RX "USB PROXY Rx" +#define SND_USE_CASE_DEV_USB_PROXY_TX "USB PROXY Tx" #define SND_USE_CASE_DEV_SPDIF_SPEAKER "SPDIF Speaker" +#define SND_USE_CASE_DEV_HDMI_SPEAKER "HDMI Speaker" #define SND_USE_CASE_DEV_SPDIF_HANDSET "SPDIF Earpiece" #define SND_USE_CASE_DEV_SPDIF_HEADSET "SPDIF Headphones" #define SND_USE_CASE_DEV_SPDIF_ANC_HEADSET "SPDIF ANC Headset" @@ -253,6 +288,7 @@ static card_mapping_t card_mapping_list[] = { #define SND_USE_CASE_DEV_SPDIF_SPEAKER_ANC_HEADSET "SPDIF Speaker ANC Headset" #define SND_USE_CASE_DEV_DUMMY_TX "Dummy Tx" #define SND_USE_CASE_DEV_PROXY_RX_SPEAKER "PROXY Rx Speaker" +#define SND_USE_CASE_DEV_USB_PROXY_RX_SPEAKER "USB PROXY Rx Speaker" #define SND_USE_CASE_DEV_PROXY_RX_HANDSET "PROXY Rx Earpiece" #define SND_USE_CASE_DEV_PROXY_RX_HEADSET "PROXY Rx Headphones" #define SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET "PROXY Rx ANC Headset" @@ -261,12 +297,13 @@ static card_mapping_t card_mapping_list[] = { #define SND_USE_CASE_DEV_CAMCORDER_TX "Camcorder Tx" #define SND_USE_CASE_DEV_VOICE_RECOGNITION "Voice Recognition" #define SND_USE_CASE_DEV_VOC_EARPIECE "Voice Earpiece" -#define SND_USE_CASE_DEV_VOC_EARPIECE_TMUS "Voice Earpiece TMUS" #define SND_USE_CASE_DEV_VOC_HEADPHONE "Voice Headphones" #define SND_USE_CASE_DEV_VOC_HEADSET "Voice Headset" #define SND_USE_CASE_DEV_VOC_ANC_HEADSET "Voice ANC Headset" #define SND_USE_CASE_DEV_VOC_SPEAKER "Voice Speaker" #define SND_USE_CASE_DEV_VOC_LINE "Voice Line" +#define SND_USE_CASE_DEV_AANC_LINE "AANC Line" +#define SND_USE_CASE_DEV_AANC_DMIC_ENDFIRE "AANC DMIC Endfire" #define SND_USE_CASE_MOD_PLAY_FM "Play FM" #define SND_USE_CASE_MOD_CAPTURE_FM "Capture FM" @@ -277,11 +314,21 @@ static card_mapping_t card_mapping_list[] = { #define SND_USE_CASE_MOD_CAPTURE_VOIP "Capture VOIP" #define SND_USE_CASE_MOD_CAPTURE_VOICE_DL "Capture Voice Downlink" #define SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL "Capture Voice Uplink Downlink" +#define SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL "Capture Compressed Voice DL" +#define SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL "Capture Compressed Voice UL DL" #define SND_USE_CASE_MOD_PLAY_TUNNEL "Play Tunnel" #define SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC "Play Lowlatency Music" #define SND_USE_CASE_MOD_PLAY_MUSIC2 "Play Music2" #define SND_USE_CASE_MOD_PLAY_MI2S "Play MI2S" #define SND_USE_CASE_MOD_PLAY_VOLTE "Play VoLTE" +#define SND_USE_CASE_MOD_CAPTURE_MUSIC2 "Capture Music2" +#define SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED "Capture Music Compressed" +#define SND_USE_CASE_MOD_PLAY_MUSIC3 "Play Music3" +#define SND_USE_CASE_MOD_PLAY_TUNNEL1 "Play Tunnel1" +#define SND_USE_CASE_MOD_PLAY_TUNNEL2 "Play Tunnel2" +#define SND_USE_CASE_MOD_PSEUDO_TUNNEL "Pseudo Tunnel" +#define SND_USE_CASE_MOD_PLAY_VOICE2 "Play Voice2" + /* List utility functions for maintaining enabled devices and modifiers */ static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head, const char *value); @@ -310,8 +357,10 @@ static int snd_ucm_parse_section(snd_use_case_mgr_t **uc_mgr, char **cur_str, ch static int snd_ucm_extract_name(char *buf, char **case_name); static int snd_ucm_extract_acdb(char *buf, int *id, int *cap); static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name); +static int snd_ucm_extract_ec_ref_rx_mixer_ctl(char *buf, char **mixer_name); static int snd_ucm_extract_dev_name(char *buf, char **dev_name); static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list, int count); +static int snd_ucm_extract_volume_mixer_ctl(char *buf, char **mixer_name); static int snd_ucm_print(snd_use_case_mgr_t *uc_mgr); static void snd_ucm_free_mixer_list(snd_use_case_mgr_t **uc_mgr); #ifdef __cplusplus diff --git a/legacy/mm-audio/Android.mk b/legacy/mm-audio/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/legacy/mm-audio/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/legacy/mm-audio/Makefile b/legacy/mm-audio/Makefile new file mode 100644 index 000000000..2be93e922 --- /dev/null +++ b/legacy/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/legacy/mm-audio/Makefile.am b/legacy/mm-audio/Makefile.am new file mode 100644 index 000000000..e423acbb9 --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-aac/Android.mk b/legacy/mm-audio/adec-aac/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/legacy/mm-audio/adec-aac/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/legacy/mm-audio/adec-aac/Makefile b/legacy/mm-audio/adec-aac/Makefile new file mode 100644 index 000000000..169fdc6df --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-aac/Makefile.am b/legacy/mm-audio/adec-aac/Makefile.am new file mode 100644 index 000000000..24c1af26d --- /dev/null +++ b/legacy/mm-audio/adec-aac/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qdsp6 diff --git a/legacy/mm-audio/adec-aac/sw/Android.mk b/legacy/mm-audio/adec-aac/sw/Android.mk new file mode 100644 index 000000000..12a91b1ef --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c b/legacy/mm-audio/adec-aac/sw/test/omx_aac_dec_test.c new file mode 100644 index 000000000..e591cdda6 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#include +#include +#include +#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; ipBuffer+((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/legacy/mm-audio/adec-amr/Android.mk b/legacy/mm-audio/adec-amr/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/legacy/mm-audio/adec-amr/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/legacy/mm-audio/adec-amr/sw/Android.mk b/legacy/mm-audio/adec-amr/sw/Android.mk new file mode 100644 index 000000000..ffa9789d6 --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c b/legacy/mm-audio/adec-amr/sw/test/omx_amr_dec_test.c new file mode 100644 index 000000000..2ce789636 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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; ipBuffer+((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= 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/legacy/mm-audio/adec-amrwb/Android.mk b/legacy/mm-audio/adec-amrwb/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/legacy/mm-audio/adec-amrwb/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/legacy/mm-audio/adec-amrwb/sw/Android.mk b/legacy/mm-audio/adec-amrwb/sw/Android.mk new file mode 100644 index 000000000..5de1d9d3b --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c b/legacy/mm-audio/adec-amrwb/sw/test/omx_amrwb_dec_test.c new file mode 100644 index 000000000..5e9d7489d --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +#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; ipBuffer+((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/legacy/mm-audio/adec-mp3/Android.mk b/legacy/mm-audio/adec-mp3/Android.mk new file mode 100644 index 000000000..5053e7d64 --- /dev/null +++ b/legacy/mm-audio/adec-mp3/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/legacy/mm-audio/adec-mp3/Makefile b/legacy/mm-audio/adec-mp3/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-mp3/Makefile.am b/legacy/mm-audio/adec-mp3/Makefile.am new file mode 100644 index 000000000..24c1af26d --- /dev/null +++ b/legacy/mm-audio/adec-mp3/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qdsp6 diff --git a/legacy/mm-audio/adec-mp3/sw/Android.mk b/legacy/mm-audio/adec-mp3/sw/Android.mk new file mode 100644 index 000000000..3773a889f --- /dev/null +++ b/legacy/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/legacy/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c b/legacy/mm-audio/adec-mp3/sw/test/omx_mp3_dec_test.c new file mode 100644 index 000000000..31931d759 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include + +#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; ipcm_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 (inFilledLen) + { + 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/legacy/mm-audio/aenc-aac/Android.mk b/legacy/mm-audio/aenc-aac/Android.mk new file mode 100644 index 000000000..e6ceb72df --- /dev/null +++ b/legacy/mm-audio/aenc-aac/Android.mk @@ -0,0 +1,16 @@ +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 + +endif diff --git a/legacy/mm-audio/aenc-aac/Makefile b/legacy/mm-audio/aenc-aac/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-aac/Makefile.am b/legacy/mm-audio/aenc-aac/Makefile.am new file mode 100644 index 000000000..24c1af26d --- /dev/null +++ b/legacy/mm-audio/aenc-aac/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qdsp6 diff --git a/legacy/mm-audio/aenc-aac/qdsp6/Android.mk b/legacy/mm-audio/aenc-aac/qdsp6/Android.mk new file mode 100644 index 000000000..e339f5d09 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-aac/qdsp6/Makefile b/legacy/mm-audio/aenc-aac/qdsp6/Makefile new file mode 100644 index 000000000..5421d45b9 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-aac/qdsp6/Makefile.am b/legacy/mm-audio/aenc-aac/qdsp6/Makefile.am new file mode 100644 index 000000000..5af028a0d --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-aac/qdsp6/inc/Map.h b/legacy/mm-audio/aenc-aac/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/legacy/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 +using namespace std; + +template +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 *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 +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::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 +bool Map::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 +bool Map::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 +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/legacy/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h b/legacy/mm-audio/aenc-aac/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..72bfebed2 --- /dev/null +++ b/legacy/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 +#include +#include + +#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/legacy/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h b/legacy/mm-audio/aenc-aac/qdsp6/inc/omx_aac_aenc.h new file mode 100644 index 000000000..276eaa351 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#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 +#include +#include +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 + input_buffer_map; + + typedef Map + 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/legacy/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c b/legacy/mm-audio/aenc-aac/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..a7c2a42b7 --- /dev/null +++ b/legacy/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 +#include +#include + +#include +#include + +#include + +/** + @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/legacy/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/legacy/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp new file mode 100644 index 000000000..874a4eb3e --- /dev/null +++ b/legacy/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp @@ -0,0 +1,5003 @@ +/*-------------------------------------------------------------------------- +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 +#include +#include +#include "omx_aac_aenc.h" +#include + +using namespace std; + +// 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() +{ + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + pthread_cond_wait(&cond, &m_event_lock); + } + 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 + . + +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 + . + +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. + +PARAMETERS + . + +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. + +PARAMETERS + . + +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. + +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 + . + +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 . + +PARAMETERS + . + +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 + . + +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> 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/legacy/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c b/legacy/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c new file mode 100644 index 000000000..c3e4b0ab8 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif +#include + +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/legacy/mm-audio/aenc-amrnb/Android.mk b/legacy/mm-audio/aenc-amrnb/Android.mk new file mode 100644 index 000000000..4a32117b3 --- /dev/null +++ b/legacy/mm-audio/aenc-amrnb/Android.mk @@ -0,0 +1,16 @@ +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 + +endif diff --git a/legacy/mm-audio/aenc-amrnb/Makefile b/legacy/mm-audio/aenc-amrnb/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-amrnb/qdsp6/Android.mk b/legacy/mm-audio/aenc-amrnb/qdsp6/Android.mk new file mode 100644 index 000000000..b97e2e5bc --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-amrnb/qdsp6/Makefile b/legacy/mm-audio/aenc-amrnb/qdsp6/Makefile new file mode 100644 index 000000000..0abd31cff --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-amrnb/qdsp6/inc/Map.h b/legacy/mm-audio/aenc-amrnb/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/legacy/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 +using namespace std; + +template +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 *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 +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::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 +bool Map::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 +bool Map::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 +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/legacy/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h b/legacy/mm-audio/aenc-amrnb/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..782641b59 --- /dev/null +++ b/legacy/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 +#include +#include + +#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/legacy/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h b/legacy/mm-audio/aenc-amrnb/qdsp6/inc/omx_amr_aenc.h new file mode 100644 index 000000000..4b8976531 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#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 +#include +#include +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 + input_buffer_map; + + typedef Map + 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/legacy/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c b/legacy/mm-audio/aenc-amrnb/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..199358ffb --- /dev/null +++ b/legacy/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 +#include +#include + +#include +#include + +#include + +/** + @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/legacy/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp b/legacy/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp new file mode 100644 index 000000000..90dd8c6c2 --- /dev/null +++ b/legacy/mm-audio/aenc-amrnb/qdsp6/src/omx_amr_aenc.cpp @@ -0,0 +1,4519 @@ +/*-------------------------------------------------------------------------- +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 +#include +#include +#include "omx_amr_aenc.h" +#include + +using namespace std; + +// 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() +{ + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + pthread_cond_wait(&cond, &m_event_lock); + } + 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 + . + +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 + . + +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. + +PARAMETERS + . + +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. + +PARAMETERS + . + +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. + +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 + . + +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 . + +PARAMETERS + . + +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 + . + +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/legacy/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c b/legacy/mm-audio/aenc-amrnb/qdsp6/test/omx_amr_enc_test.c new file mode 100644 index 000000000..a3c91b1ac --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif + + +#include + +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/legacy/mm-audio/aenc-evrc/Android.mk b/legacy/mm-audio/aenc-evrc/Android.mk new file mode 100644 index 000000000..133e1a7b6 --- /dev/null +++ b/legacy/mm-audio/aenc-evrc/Android.mk @@ -0,0 +1,16 @@ +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 + +endif diff --git a/legacy/mm-audio/aenc-evrc/Makefile b/legacy/mm-audio/aenc-evrc/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-evrc/qdsp6/Android.mk b/legacy/mm-audio/aenc-evrc/qdsp6/Android.mk new file mode 100644 index 000000000..d38d004f2 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-evrc/qdsp6/Makefile b/legacy/mm-audio/aenc-evrc/qdsp6/Makefile new file mode 100644 index 000000000..d0871dea2 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-evrc/qdsp6/inc/Map.h b/legacy/mm-audio/aenc-evrc/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/legacy/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 +using namespace std; + +template +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 *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 +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::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 +bool Map::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 +bool Map::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 +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/legacy/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h b/legacy/mm-audio/aenc-evrc/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..46f40ee32 --- /dev/null +++ b/legacy/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 +#include +#include + +#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/legacy/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h b/legacy/mm-audio/aenc-evrc/qdsp6/inc/omx_evrc_aenc.h new file mode 100644 index 000000000..fa83230b7 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#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 +#include +#include +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 + input_buffer_map; + + typedef Map + 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/legacy/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c b/legacy/mm-audio/aenc-evrc/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..212871867 --- /dev/null +++ b/legacy/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 +#include +#include + +#include +#include + +#include + +/** + @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/legacy/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp b/legacy/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp new file mode 100644 index 000000000..09c5bfb27 --- /dev/null +++ b/legacy/mm-audio/aenc-evrc/qdsp6/src/omx_evrc_aenc.cpp @@ -0,0 +1,4518 @@ +/*-------------------------------------------------------------------------- +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 +#include +#include +#include "omx_evrc_aenc.h" +#include + +using namespace std; + +// 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() +{ + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + pthread_cond_wait(&cond, &m_event_lock); + } + 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 + . + +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 + . + +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. + +PARAMETERS + . + +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. + +PARAMETERS + . + +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. + +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 + . + +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 . + +PARAMETERS + . + +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 + . + +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/legacy/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c b/legacy/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c new file mode 100644 index 000000000..e01759e84 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif + + +#include + +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/legacy/mm-audio/aenc-qcelp13/Android.mk b/legacy/mm-audio/aenc-qcelp13/Android.mk new file mode 100644 index 000000000..bc4def507 --- /dev/null +++ b/legacy/mm-audio/aenc-qcelp13/Android.mk @@ -0,0 +1,16 @@ +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 + +endif diff --git a/legacy/mm-audio/aenc-qcelp13/Makefile b/legacy/mm-audio/aenc-qcelp13/Makefile new file mode 100644 index 000000000..83d822bb7 --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-qcelp13/qdsp6/Android.mk b/legacy/mm-audio/aenc-qcelp13/qdsp6/Android.mk new file mode 100644 index 000000000..5aaa3bf7d --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-qcelp13/qdsp6/Makefile b/legacy/mm-audio/aenc-qcelp13/qdsp6/Makefile new file mode 100644 index 000000000..b14655bda --- /dev/null +++ b/legacy/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/legacy/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h b/legacy/mm-audio/aenc-qcelp13/qdsp6/inc/Map.h new file mode 100644 index 000000000..aac96fd12 --- /dev/null +++ b/legacy/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 +using namespace std; + +template +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 *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 +T2 Map::find(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data2; + } + tmp = tmp->next; + } + return 0; +} + +template +T Map::find_ele(T d1) +{ + tmp = head; + while(tmp) + { + if(tmp->data == d1) + { + return tmp->data; + } + tmp = tmp->next; + } + return 0; +} + +template +T2 Map::begin() +{ + tmp = head; + if(tmp) + { + return (tmp->data2); + } + return 0; +} + +template +void Map::show() +{ + tmp = head; + while(tmp) + { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + +template +int Map::size() +{ + int count =0; + tmp = head; + while(tmp) + { + tmp = tmp->next; + count++; + } + return count; +} + +template +void Map::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 +bool Map::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 +bool Map::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 +bool Map::isempty() +{ + if(!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/legacy/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h b/legacy/mm-audio/aenc-qcelp13/qdsp6/inc/aenc_svr.h new file mode 100644 index 000000000..940d863ae --- /dev/null +++ b/legacy/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 +#include +#include + +#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/legacy/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h b/legacy/mm-audio/aenc-qcelp13/qdsp6/inc/omx_qcelp13_aenc.h new file mode 100644 index 000000000..c54780998 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#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 +#include +#include +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 + input_buffer_map; + + typedef Map + 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/legacy/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c b/legacy/mm-audio/aenc-qcelp13/qdsp6/src/aenc_svr.c new file mode 100644 index 000000000..b39f62522 --- /dev/null +++ b/legacy/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 +#include +#include + +#include +#include + +#include + +/** + @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/legacy/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp b/legacy/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp new file mode 100644 index 000000000..a93f14fef --- /dev/null +++ b/legacy/mm-audio/aenc-qcelp13/qdsp6/src/omx_qcelp13_aenc.cpp @@ -0,0 +1,4519 @@ +/*-------------------------------------------------------------------------- +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 +#include +#include +#include "omx_qcelp13_aenc.h" +#include + +using namespace std; + +// 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() +{ + pthread_mutex_lock(&m_event_lock); + while (0 == m_is_event_done) + { + pthread_cond_wait(&cond, &m_event_lock); + } + 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 + . + +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 + . + +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. + +PARAMETERS + . + +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. + +PARAMETERS + . + +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. + +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 + . + +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 . + +PARAMETERS + . + +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 + . + +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/legacy/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c b/legacy/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c new file mode 100644 index 000000000..5c59349c8 --- /dev/null +++ b/legacy/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "pthread.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QOMX_AudioExtensions.h" +#include "QOMX_AudioIndexExtensions.h" +#ifdef AUDIOV2 +#include "control.h" +#endif + + +#include + +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/legacy/mm-audio/autogen.sh b/legacy/mm-audio/autogen.sh new file mode 100644 index 000000000..de72aa199 --- /dev/null +++ b/legacy/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/legacy/mm-audio/configure.ac b/legacy/mm-audio/configure.ac new file mode 100644 index 000000000..b75d2ed8e --- /dev/null +++ b/legacy/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/voice_processing/Android.mk b/voice_processing/Android.mk deleted file mode 100644 index b64c0e301..000000000 --- a/voice_processing/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# audio preprocessing wrapper -include $(CLEAR_VARS) - -LOCAL_MODULE:= libqcomvoiceprocessing -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx - -LOCAL_SRC_FILES:= \ - voice_processing.c - -LOCAL_C_INCLUDES += \ - $(call include-path-for, audio-effects) - -LOCAL_SHARED_LIBRARIES := \ - libcutils - -LOCAL_SHARED_LIBRARIES += libdl - -LOCAL_CFLAGS += -fvisibility=hidden - -include $(BUILD_SHARED_LIBRARY) diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c deleted file mode 100644 index f4120909e..000000000 --- a/voice_processing/voice_processing.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * 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_processing" -/*#define LOG_NDEBUG 0*/ -#include -#include -#include -#include -#include -#include - - -//------------------------------------------------------------------------------ -// local definitions -//------------------------------------------------------------------------------ - -// types of pre processing modules -enum effect_id -{ - AEC_ID, // Acoustic Echo Canceler - NS_ID, // Noise Suppressor -//ENABLE_AGC AGC_ID, // Automatic Gain Control - NUM_ID -}; - -// Session state -enum session_state { - SESSION_STATE_INIT, // initialized - SESSION_STATE_CONFIG // configuration received -}; - -// Effect/Preprocessor state -enum effect_state { - EFFECT_STATE_INIT, // initialized - EFFECT_STATE_CREATED, // webRTC engine created - EFFECT_STATE_CONFIG, // configuration received/disabled - EFFECT_STATE_ACTIVE // active/enabled -}; - -// Effect context -struct effect_s { - const struct effect_interface_s *itfe; - uint32_t id; // type of pre processor (enum effect_id) - uint32_t state; // current state (enum effect_state) - struct session_s *session; // session the effect is on -}; - -// Session context -struct session_s { - struct listnode node; - effect_config_t config; - struct effect_s effects[NUM_ID]; // effects in this session - uint32_t state; // current state (enum session_state) - int id; // audio session ID - int io; // handle of input stream this session is on - uint32_t created_msk; // bit field containing IDs of crested pre processors - uint32_t enabled_msk; // bit field containing IDs of enabled pre processors - uint32_t processed_msk; // bit field containing IDs of pre processors already -}; - - -//------------------------------------------------------------------------------ -// Effect descriptors -//------------------------------------------------------------------------------ - -// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html -// as the pre processing effects are not defined by OpenSL ES - -// Acoustic Echo Cancellation -static const effect_descriptor_t aec_descriptor = { - { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type - { 0x0f8d0d2a, 0x59e5, 0x45fe, 0xb6e4, { 0x24, 0x8c, 0x8a, 0x79, 0x91, 0x09 } }, // uuid - EFFECT_CONTROL_API_VERSION, - (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), - 0, - 0, - "Acoustic Echo Canceler", - "Qualcomm Fluence" -}; - -// Noise suppression -static const effect_descriptor_t ns_descriptor = { - { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type - { 0x1d97bb0b, 0x9e2f, 0x4403, 0x9ae3, { 0x58, 0xc2, 0x55, 0x43, 0x06, 0xf8 } }, // uuid - EFFECT_CONTROL_API_VERSION, - (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), - 0, - 0, - "Noise Suppression", - "Qualcomm Fluence" -}; - -//ENABLE_AGC -// Automatic Gain Control -//static const effect_descriptor_t agc_descriptor = { -// { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type -// { 0x0dd49521, 0x8c59, 0x40b1, 0xb403, { 0xe0, 0x8d, 0x5f, 0x01, 0x87, 0x5e } }, // uuid -// EFFECT_CONTROL_API_VERSION, -// (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), -// 0, -// 0, -// "Automatic Gain Control", -// "Qualcomm Fluence" -//}; - -static const effect_descriptor_t *descriptors[NUM_ID] = { - &aec_descriptor, - &ns_descriptor, -//ENABLE_AGC &agc_descriptor, -}; - - -static int init_status = 1; -struct listnode session_list; -static const struct effect_interface_s effect_interface; -static const effect_uuid_t * uuid_to_id_table[NUM_ID]; - -//------------------------------------------------------------------------------ -// Helper functions -//------------------------------------------------------------------------------ - -static const effect_uuid_t * id_to_uuid(int id) -{ - if (id >= NUM_ID) - return EFFECT_UUID_NULL; - - return uuid_to_id_table[id]; -} - -static uint32_t uuid_to_id(const effect_uuid_t * uuid) -{ - size_t i; - for (i = 0; i < NUM_ID; i++) - if (memcmp(uuid, uuid_to_id_table[i], sizeof(*uuid)) == 0) - break; - - return i; -} - -//------------------------------------------------------------------------------ -// Effect functions -//------------------------------------------------------------------------------ - -static void session_set_fx_enabled(struct session_s *session, uint32_t id, bool enabled); - -#define BAD_STATE_ABORT(from, to) \ - LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to); - -static int effect_set_state(struct effect_s *effect, uint32_t state) -{ - int status = 0; - ALOGV("effect_set_state() id %d, new %d old %d", effect->id, state, effect->state); - switch(state) { - case EFFECT_STATE_INIT: - switch(effect->state) { - case EFFECT_STATE_ACTIVE: - session_set_fx_enabled(effect->session, effect->id, false); - case EFFECT_STATE_CONFIG: - case EFFECT_STATE_CREATED: - case EFFECT_STATE_INIT: - break; - default: - BAD_STATE_ABORT(effect->state, state); - } - break; - case EFFECT_STATE_CREATED: - switch(effect->state) { - case EFFECT_STATE_INIT: - break; - case EFFECT_STATE_CREATED: - case EFFECT_STATE_ACTIVE: - case EFFECT_STATE_CONFIG: - ALOGE("effect_set_state() invalid transition"); - status = -ENOSYS; - break; - default: - BAD_STATE_ABORT(effect->state, state); - } - break; - case EFFECT_STATE_CONFIG: - switch(effect->state) { - case EFFECT_STATE_INIT: - ALOGE("effect_set_state() invalid transition"); - status = -ENOSYS; - break; - case EFFECT_STATE_ACTIVE: - session_set_fx_enabled(effect->session, effect->id, false); - break; - case EFFECT_STATE_CREATED: - case EFFECT_STATE_CONFIG: - break; - default: - BAD_STATE_ABORT(effect->state, state); - } - break; - case EFFECT_STATE_ACTIVE: - switch(effect->state) { - case EFFECT_STATE_INIT: - case EFFECT_STATE_CREATED: - ALOGE("effect_set_state() invalid transition"); - status = -ENOSYS; - break; - case EFFECT_STATE_ACTIVE: - // enabling an already enabled effect is just ignored - break; - case EFFECT_STATE_CONFIG: - session_set_fx_enabled(effect->session, effect->id, true); - break; - default: - BAD_STATE_ABORT(effect->state, state); - } - break; - default: - BAD_STATE_ABORT(effect->state, state); - } - - if (status == 0) - effect->state = state; - - return status; -} - -static int effect_init(struct effect_s *effect, uint32_t id) -{ - effect->itfe = &effect_interface; - effect->id = id; - effect->state = EFFECT_STATE_INIT; - return 0; -} - -static int effect_create(struct effect_s *effect, - struct session_s *session, - effect_handle_t *interface) -{ - effect->session = session; - *interface = (effect_handle_t)&effect->itfe; - return effect_set_state(effect, EFFECT_STATE_CREATED); -} - -static int effect_release(struct effect_s *effect) -{ - return effect_set_state(effect, EFFECT_STATE_INIT); -} - - -//------------------------------------------------------------------------------ -// Session functions -//------------------------------------------------------------------------------ - -static int session_init(struct session_s *session) -{ - size_t i; - int status = 0; - - session->state = SESSION_STATE_INIT; - session->id = 0; - session->io = 0; - session->created_msk = 0; - for (i = 0; i < NUM_ID && status == 0; i++) - status = effect_init(&session->effects[i], i); - - return status; -} - - -static int session_create_effect(struct session_s *session, - int32_t id, - effect_handle_t *interface) -{ - int status = -ENOMEM; - - ALOGV("session_create_effect() %s, created_msk %08x", - id == AEC_ID ? "AEC" : id == NS_ID ? "NS" : "?", session->created_msk); - - if (session->created_msk == 0) { - session->config.inputCfg.samplingRate = 16000; - session->config.inputCfg.channels = AUDIO_CHANNEL_IN_MONO; - session->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; - session->config.outputCfg.samplingRate = 16000; - session->config.outputCfg.channels = AUDIO_CHANNEL_IN_MONO; - session->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; - session->enabled_msk = 0; - session->processed_msk = 0; - } - status = effect_create(&session->effects[id], session, interface); - if (status < 0) - goto error; - - ALOGV("session_create_effect() OK"); - session->created_msk |= (1<id); - - session->created_msk &= ~(1<id); - if (session->created_msk == 0) - { - ALOGV("session_release_effect() last effect: removing session"); - list_remove(&session->node); - free(session); - } - - return 0; -} - - -static int session_set_config(struct session_s *session, effect_config_t *config) -{ - int status; - - if (config->inputCfg.samplingRate != config->outputCfg.samplingRate || - config->inputCfg.format != config->outputCfg.format || - config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) - return -EINVAL; - - ALOGV("session_set_config() sampling rate %d channels %08x", - config->inputCfg.samplingRate, config->inputCfg.channels); - - // if at least one process is enabled, do not accept configuration changes - if (session->enabled_msk) { - if (session->config.inputCfg.samplingRate != config->inputCfg.samplingRate || - session->config.inputCfg.channels != config->inputCfg.channels || - session->config.outputCfg.channels != config->outputCfg.channels) - return -ENOSYS; - else - return 0; - } - - memcpy(&session->config, config, sizeof(effect_config_t)); - - session->state = SESSION_STATE_CONFIG; - return 0; -} - -static void session_get_config(struct session_s *session, effect_config_t *config) -{ - memcpy(config, &session->config, sizeof(effect_config_t)); - - config->inputCfg.mask = config->outputCfg.mask = - (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT); -} - - -static void session_set_fx_enabled(struct session_s *session, uint32_t id, bool enabled) -{ - if (enabled) { - if(session->enabled_msk == 0) { - /* do first enable here */ - } - session->enabled_msk |= (1 << id); - } else { - session->enabled_msk &= ~(1 << id); - if(session->enabled_msk == 0) { - /* do last enable here */ - } - } - ALOGV("session_set_fx_enabled() id %d, enabled %d enabled_msk %08x", - id, enabled, session->enabled_msk); - session->processed_msk = 0; -} - -//------------------------------------------------------------------------------ -// Global functions -//------------------------------------------------------------------------------ - -static struct session_s *get_session(int32_t id, int32_t sessionId, int32_t ioId) -{ - size_t i; - int free = -1; - struct listnode *node; - struct session_s *session; - - list_for_each(node, &session_list) { - session = node_to_item(node, struct session_s, node); - if (session->io == ioId) { - if (session->created_msk & (1 << id)) { - ALOGV("get_session() effect %d already created", id); - return NULL; - } - ALOGV("get_session() found session %p", session); - return session; - } - } - - session = (struct session_s *)calloc(1, sizeof(struct session_s)); - session_init(session); - session->id = sessionId; - session->io = ioId; - list_add_tail(&session_list, &session->node); - - ALOGV("get_session() created session %p", session); - - return session; -} - -static int init() { - size_t i; - int status = 0; - - if (init_status <= 0) - return init_status; - - uuid_to_id_table[AEC_ID] = FX_IID_AEC; - uuid_to_id_table[NS_ID] = FX_IID_NS; - - list_init(&session_list); - - init_status = 0; - return init_status; -} - -static const effect_descriptor_t *get_descriptor(const effect_uuid_t *uuid) -{ - size_t i; - for (i = 0; i < NUM_ID; i++) - if (memcmp(&descriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) - return descriptors[i]; - - return NULL; -} - - -//------------------------------------------------------------------------------ -// Effect Control Interface Implementation -//------------------------------------------------------------------------------ - -static int fx_process(effect_handle_t self, - audio_buffer_t *inBuffer, - audio_buffer_t *outBuffer) -{ - struct effect_s *effect = (struct effect_s *)self; - struct session_s *session; - - if (effect == NULL) { - ALOGV("fx_process() ERROR effect == NULL"); - return -EINVAL; - } - - if (inBuffer == NULL || inBuffer->raw == NULL || - outBuffer == NULL || outBuffer->raw == NULL) { - ALOGW("fx_process() ERROR bad pointer"); - return -EINVAL; - } - - session = (struct session_s *)effect->session; - - session->processed_msk |= (1<id); - - if ((session->processed_msk & session->enabled_msk) == session->enabled_msk) { - effect->session->processed_msk = 0; - return 0; - } else - return -ENODATA; -} - -static int fx_command(effect_handle_t self, - uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *replySize, - void *pReplyData) -{ - struct effect_s *effect = (struct effect_s *)self; - - if (effect == NULL) - return -EINVAL; - - //ALOGV("fx_command: command %d cmdSize %d",cmdCode, cmdSize); - - switch (cmdCode) { - case EFFECT_CMD_INIT: - if (pReplyData == NULL || *replySize != sizeof(int)) - return -EINVAL; - - *(int *)pReplyData = 0; - break; - - case EFFECT_CMD_SET_CONFIG: { - if (pCmdData == NULL|| - cmdSize != sizeof(effect_config_t)|| - pReplyData == NULL|| - *replySize != sizeof(int)) { - ALOGV("fx_command() EFFECT_CMD_SET_CONFIG invalid args"); - return -EINVAL; - } - *(int *)pReplyData = session_set_config(effect->session, (effect_config_t *)pCmdData); - if (*(int *)pReplyData != 0) - break; - - if (effect->state != EFFECT_STATE_ACTIVE) - *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_CONFIG); - - } break; - - case EFFECT_CMD_GET_CONFIG: - if (pReplyData == NULL || - *replySize != sizeof(effect_config_t)) { - ALOGV("fx_command() EFFECT_CMD_GET_CONFIG invalid args"); - return -EINVAL; - } - - session_get_config(effect->session, (effect_config_t *)pReplyData); - break; - - case EFFECT_CMD_RESET: - break; - - case EFFECT_CMD_GET_PARAM: { - if (pCmdData == NULL || - cmdSize < (int)sizeof(effect_param_t) || - pReplyData == NULL || - *replySize < (int)sizeof(effect_param_t)) { - ALOGV("fx_command() EFFECT_CMD_GET_PARAM invalid args"); - return -EINVAL; - } - effect_param_t *p = (effect_param_t *)pCmdData; - - memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize); - p = (effect_param_t *)pReplyData; - p->status = -ENOSYS; - - } break; - - case EFFECT_CMD_SET_PARAM: { - if (pCmdData == NULL|| - cmdSize < (int)sizeof(effect_param_t) || - pReplyData == NULL || - *replySize != sizeof(int32_t)) { - ALOGV("fx_command() EFFECT_CMD_SET_PARAM invalid args"); - return -EINVAL; - } - effect_param_t *p = (effect_param_t *) pCmdData; - - if (p->psize != sizeof(int32_t)) { - ALOGV("fx_command() EFFECT_CMD_SET_PARAM invalid param format"); - return -EINVAL; - } - *(int *)pReplyData = -ENOSYS; - } break; - - case EFFECT_CMD_ENABLE: - if (pReplyData == NULL || *replySize != sizeof(int)) { - ALOGV("fx_command() EFFECT_CMD_ENABLE invalid args"); - return -EINVAL; - } - *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_ACTIVE); - break; - - case EFFECT_CMD_DISABLE: - if (pReplyData == NULL || *replySize != sizeof(int)) { - ALOGV("fx_command() EFFECT_CMD_DISABLE invalid args"); - return -EINVAL; - } - *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_CONFIG); - break; - - case EFFECT_CMD_SET_DEVICE: - case EFFECT_CMD_SET_INPUT_DEVICE: - case EFFECT_CMD_SET_VOLUME: - case EFFECT_CMD_SET_AUDIO_MODE: - if (pCmdData == NULL || - cmdSize != sizeof(uint32_t)) { - ALOGV("fx_command() %s invalid args", - cmdCode == EFFECT_CMD_SET_DEVICE ? "EFFECT_CMD_SET_DEVICE" : - cmdCode == EFFECT_CMD_SET_INPUT_DEVICE ? "EFFECT_CMD_SET_INPUT_DEVICE" : - cmdCode == EFFECT_CMD_SET_VOLUME ? "EFFECT_CMD_SET_VOLUME" : - cmdCode == EFFECT_CMD_SET_AUDIO_MODE ? "EFFECT_CMD_SET_AUDIO_MODE" : - ""); - return -EINVAL; - } - ALOGV("fx_command() %s value %08x", - cmdCode == EFFECT_CMD_SET_DEVICE ? "EFFECT_CMD_SET_DEVICE" : - cmdCode == EFFECT_CMD_SET_INPUT_DEVICE ? "EFFECT_CMD_SET_INPUT_DEVICE" : - cmdCode == EFFECT_CMD_SET_VOLUME ? "EFFECT_CMD_SET_VOLUME" : - cmdCode == EFFECT_CMD_SET_AUDIO_MODE ? "EFFECT_CMD_SET_AUDIO_MODE": - "", - *(int *)pCmdData); - break; - - default: - return -EINVAL; - } - return 0; -} - - -static int fx_get_descriptor(effect_handle_t self, - effect_descriptor_t *pDescriptor) -{ - struct effect_s *effect = (struct effect_s *)self; - - if (effect == NULL || pDescriptor == NULL) - return -EINVAL; - - *pDescriptor = *descriptors[effect->id]; - - return 0; -} - - -// effect_handle_t interface implementation for effect -static const struct effect_interface_s effect_interface = { - fx_process, - fx_command, - fx_get_descriptor, - NULL -}; - -//------------------------------------------------------------------------------ -// Effect Library Interface Implementation -//------------------------------------------------------------------------------ - -static int lib_create(const effect_uuid_t *uuid, - int32_t sessionId, - int32_t ioId, - effect_handle_t *pInterface) -{ - ALOGV("lib_create: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId); - - int status; - const effect_descriptor_t *desc; - struct session_s *session; - uint32_t id; - - if (init() != 0) - return init_status; - - desc = get_descriptor(uuid); - - if (desc == NULL) { - ALOGW("lib_create: fx not found uuid: %08x", uuid->timeLow); - return -EINVAL; - } - id = uuid_to_id(&desc->type); - - session = get_session(id, sessionId, ioId); - - if (session == NULL) { - ALOGW("lib_create: no more session available"); - return -EINVAL; - } - - status = session_create_effect(session, id, pInterface); - - if (status < 0 && session->created_msk == 0) { - list_remove(&session->node); - free(session); - } - return status; -} - -static int lib_release(effect_handle_t interface) -{ - struct listnode *node; - struct session_s *session; - - ALOGV("lib_release %p", interface); - if (init() != 0) - return init_status; - - struct effect_s *fx = (struct effect_s *)interface; - - list_for_each(node, &session_list) { - session = node_to_item(node, struct session_s, node); - if (session == fx->session) { - session_release_effect(fx->session, fx); - return 0; - } - } - - return -EINVAL; -} - -static int lib_get_descriptor(const effect_uuid_t *uuid, - effect_descriptor_t *pDescriptor) -{ - const effect_descriptor_t *desc; - - if (pDescriptor == NULL || uuid == NULL) - return -EINVAL; - - desc = get_descriptor(uuid); - if (desc == NULL) { - ALOGV("lib_get_descriptor() not found"); - return -EINVAL; - } - - ALOGV("lib_get_descriptor() got fx %s", desc->name); - - *pDescriptor = *desc; - return 0; -} - -// This is the only symbol that needs to be exported -__attribute__ ((visibility ("default"))) -audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { - tag : AUDIO_EFFECT_LIBRARY_TAG, - version : EFFECT_LIBRARY_API_VERSION, - name : "MSM8960 Audio Preprocessing Library", - implementor : "The Android Open Source Project", - create_effect : lib_create, - release_effect : lib_release, - get_descriptor : lib_get_descriptor -}; -- GitLab