author | Jing Wei <jing.wei@amlogic.com> | 2015-07-23 06:08:19 (GMT) |
---|---|---|
committer | Jing Wei <jing.wei@amlogic.com> | 2015-07-23 07:16:48 (GMT) |
commit | 327eadef2b307230360aec3f53d2a6cc5764c69a (patch) | |
tree | fbcee9c3c13424c70c0d12e48a0a0d3aa94cdece | |
parent | e891f0fb2527a54865cb3e7fd4425fd71d981c90 (diff) | |
download | audio-327eadef2b307230360aec3f53d2a6cc5764c69a.zip audio-327eadef2b307230360aec3f53d2a6cc5764c69a.tar.gz audio-327eadef2b307230360aec3f53d2a6cc5764c69a.tar.bz2 |
PD #109887: g9tv:merge tv audio
Change-Id: I6dc565fc88bccfc42038032054423464c893948f
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | libTVaudio/Android.mk | 32 | ||||
-rw-r--r-- | libTVaudio/audio/Android.mk | 30 | ||||
-rw-r--r-- | libTVaudio/audio/DDP_media_source.cpp | 754 | ||||
-rw-r--r-- | libTVaudio/audio/DDP_media_source.h | 143 | ||||
-rw-r--r-- | libTVaudio/audio/amaudio_main.cpp | 74 | ||||
-rw-r--r-- | libTVaudio/audio/aml_audio.c | 1864 | ||||
-rw-r--r-- | libTVaudio/audio/aml_audio.h | 73 | ||||
-rw-r--r-- | libTVaudio/audio/android_out.cpp | 160 | ||||
-rw-r--r-- | libTVaudio/audio/android_out.h | 15 | ||||
-rw-r--r-- | libTVaudio/audio/audio_amaudio.cpp | 209 | ||||
-rw-r--r-- | libTVaudio/audio/audio_effect_control.c | 423 | ||||
-rw-r--r-- | libTVaudio/audio/audio_effect_control.h | 48 | ||||
-rw-r--r-- | libTVaudio/audio/audio_usb_check.cpp | 29 | ||||
-rw-r--r-- | libTVaudio/audio/audio_usb_check.h | 18 | ||||
-rw-r--r-- | libTVaudio/audio_amaudio.h | 38 |
16 files changed, 3911 insertions, 0 deletions
@@ -120,3 +120,4 @@ include $(BUILD_SHARED_LIBRARY) endif # USE_CUSTOM_AUDIO_POLICY endif # BOARD_ALSA_AUDIO +include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file diff --git a/libTVaudio/Android.mk b/libTVaudio/Android.mk new file mode 100644 index 0000000..91ef7dc --- a/dev/null +++ b/libTVaudio/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libTVaudio + +LOCAL_SHARED_LIBRARIES := libcutils libutils libtinyalsa libdl \ + libmedia libbinder libusbhost libstagefright + +LOCAL_C_INCLUDES := \ + external/tinyalsa/include \ + frameworks/av/include/media/stagefright \ + frameworks/av/include/media \ + frameworks/native/include/media/openmax \ + $(LOCAL_PATH)/ \ + $(LOCAL_PATH)/audio \ + +LOCAL_SRC_FILES := \ + audio/aml_audio.c \ + audio/audio_effect_control.c \ + audio/android_out.cpp \ + audio/audio_amaudio.cpp \ + audio/audio_usb_check.cpp \ + audio/amaudio_main.cpp \ + audio/DDP_media_source.cpp \ + +LOCAL_CFLAGS := -DANDROID_PLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) + +LOCAL_MODULE_TAGS := optional +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) diff --git a/libTVaudio/audio/Android.mk b/libTVaudio/audio/Android.mk new file mode 100644 index 0000000..eeb030f --- a/dev/null +++ b/libTVaudio/audio/Android.mk @@ -0,0 +1,30 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := aml_audio_test + +LOCAL_SHARED_LIBRARIES := libcutils libutils libtinyalsa libdl \ + libmedia libbinder libusbhost libstagefright + +LOCAL_C_INCLUDES := \ + external/tinyalsa/include \ + frameworks/av/include/media/stagefright \ + frameworks/native/include/media/openmax \ + $(LOCAL_PATH)/ \ + +LOCAL_SRC_FILES := \ + aml_audio.c \ + audio_effect_control.c \ + android_out.cpp \ + audio_amaudio.cpp \ + audio_usb_check.cpp \ + amaudio_main.cpp \ + DDP_media_source.cpp \ + +LOCAL_CFLAGS := -DANDROID_PLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) + +LOCAL_MODULE_TAGS := optional +LOCAL_PRELINK_MODULE := false + +include $(BUILD_EXECUTABLE) diff --git a/libTVaudio/audio/DDP_media_source.cpp b/libTVaudio/audio/DDP_media_source.cpp new file mode 100644 index 0000000..14eb6bf --- a/dev/null +++ b/libTVaudio/audio/DDP_media_source.cpp @@ -0,0 +1,754 @@ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <android/log.h> +#include <cutils/properties.h> +#include <pthread.h> + +#include "DDP_media_source.h" +#include "aml_audio.h" + +extern struct circle_buffer android_out_buffer; +extern struct circle_buffer DDP_out_buffer; + +namespace android { + +#define LOG_TAG "DDP_Media_Source" + +static DDPerr ddbs_init(DDPshort * buf, DDPshort bitptr,DDP_BSTRM *p_bstrm) +{ + p_bstrm->buf = buf; + p_bstrm->bitptr = bitptr; + p_bstrm->data = *buf; + return 0; +} +static DDPerr ddbs_unprj(DDP_BSTRM *p_bstrm,DDPshort *p_data, DDPshort numbits) +{ + DDPushort data; + *p_data = (DDPshort)((p_bstrm->data << p_bstrm->bitptr) & msktab[numbits]); + p_bstrm->bitptr += numbits; + if (p_bstrm->bitptr >= BITSPERWRD) + { + p_bstrm->buf++; + p_bstrm->data = *p_bstrm->buf; + p_bstrm->bitptr -= BITSPERWRD; + data = (DDPushort)p_bstrm->data; + *p_data |= ((data >> (numbits - p_bstrm->bitptr)) & msktab[numbits]); + } + *p_data = (DDPshort)((DDPushort)(*p_data) >> (BITSPERWRD - numbits)); + return 0; +} + + +static int Get_DD_Parameters(void *buf, int *sample_rate, int *frame_size,int *ChNum) +{ + int numch=0; + DDP_BSTRM bstrm={0}; + DDP_BSTRM *p_bstrm=&bstrm; + short tmp=0,acmod,lfeon,fscod,frmsizecod; + ddbs_init((short*)buf,0,p_bstrm); + + ddbs_unprj(p_bstrm, &tmp, 16); + if (tmp!= SYNCWRD) + { + ALOGI("Invalid synchronization word"); + return 0; + } + ddbs_unprj(p_bstrm, &tmp, 16); + ddbs_unprj(p_bstrm, &fscod, 2); + if (fscod == MAXFSCOD) + { + ALOGI("Invalid sampling rate code"); + return 0; + } + + if (fscod == 0) *sample_rate = 48000; + else if (fscod == 1) *sample_rate = 44100; + else if (fscod == 2) *sample_rate = 32000; + + ddbs_unprj(p_bstrm, &frmsizecod, 6); + if (frmsizecod >= MAXDDDATARATE) + { + ALOGI("Invalid frame size code"); + return 0; + } + + *frame_size=2*frmsizetab[fscod][frmsizecod]; + + ddbs_unprj(p_bstrm, &tmp, 5); + if (!ISDD(tmp)) + { + ALOGI("Unsupported bitstream id"); + return 0; + } + + ddbs_unprj(p_bstrm, &tmp, 3); + ddbs_unprj(p_bstrm, &acmod, 3); + + if ((acmod!= MODE10) && (acmod& 0x1)) + { + ddbs_unprj(p_bstrm, &tmp, 2); + } + if (acmod& 0x4) + { + ddbs_unprj(p_bstrm, &tmp, 2); + } + + if (acmod == MODE20) + { + ddbs_unprj(p_bstrm,&tmp, 2); + } + ddbs_unprj(p_bstrm, &lfeon, 1); + + + numch = chanary[acmod]; + if (0) + { + if (numch >= 3) + numch = 8; + else + numch = 2; + }else{ + numch = 2; + } + *ChNum=numch; + //ALOGI("DEBUG:numch=%d sample_rate=%d %p [%s %d]",ChNum,sample_rate,this,__FUNCTION__,__LINE__); + return numch; +} + +static int Get_DDP_Parameters(void *buf, int *sample_rate, int *frame_size,int *ChNum) +{ + int numch = 0; + DDP_BSTRM bstrm={0}; + DDP_BSTRM *p_bstrm=&bstrm; + short tmp=0,acmod,lfeon,strmtyp; + ddbs_init((short*)buf,0,p_bstrm); + ddbs_unprj(p_bstrm, &tmp, 16); + if (tmp!= SYNCWRD) { + ALOGI("Invalid synchronization word"); + return -1; + } + + ddbs_unprj(p_bstrm, &strmtyp, 2); + ddbs_unprj(p_bstrm, &tmp, 3); + ddbs_unprj(p_bstrm, &tmp, 11); + + *frame_size = 2 * (tmp + 1); + if (strmtyp != 0 && strmtyp != 2) { + return -1; + } + ddbs_unprj(p_bstrm, &tmp, 2); + + if (tmp == 0x3) { + ALOGI("Half sample rate unsupported"); + return -1; + } else { + if (tmp == 0) + *sample_rate = 48000; + else if (tmp == 1) + *sample_rate = 44100; + else if (tmp == 2) + *sample_rate = 32000; + + ddbs_unprj(p_bstrm, &tmp, 2); + } + ddbs_unprj(p_bstrm, &acmod, 3); + ddbs_unprj(p_bstrm, &lfeon, 1); + numch = chanary[acmod]; + numch = 2; + *ChNum = numch; + //ALOGI("DEBUG[%s %d]:numch=%d,sr=%d,frs=%d",__FUNCTION__,__LINE__,*ChNum,*sample_rate,*frame_size); + return 0; + +} + +static DDPerr ddbs_skip(DDP_BSTRM *p_bstrm, DDPshort numbits) +{ + p_bstrm->bitptr += numbits; + while (p_bstrm->bitptr >= BITSPERWRD) + { + p_bstrm->buf++; + p_bstrm->data = *p_bstrm->buf; + p_bstrm->bitptr -= BITSPERWRD; + } + + return 0; +} + +static DDPerr ddbs_getbsid(DDP_BSTRM *p_inbstrm, DDPshort *p_bsid) +{ + DDP_BSTRM bstrm; + + ddbs_init(p_inbstrm->buf, p_inbstrm->bitptr, &bstrm); + ddbs_skip(&bstrm, BS_BITOFFSET); + ddbs_unprj(&bstrm, p_bsid, 5); + if (!ISDDP(*p_bsid) && !ISDD(*p_bsid)) + { + ALOGI("Unsupported bitstream id"); + } + + return 0; +} + +static int Get_Parameters(void *buf, int *sample_rate, int *frame_size,int *ChNum) + { + DDP_BSTRM bstrm={0}; + DDP_BSTRM *p_bstrm=&bstrm; + DDPshort bsid; + int chnum = 0; + uint8_t ptr8[PTR_HEAD_SIZE]; + + memcpy(ptr8, buf, PTR_HEAD_SIZE); + + //ALOGI("LZG->ptr_head:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n", + // ptr8[0],ptr8[1],ptr8[2], ptr8[3],ptr8[4],ptr8[5] ); + if ((ptr8[0] == 0x0b) && (ptr8[1] == 0x77)) { + int i; + uint8_t tmp; + for (i = 0; i < PTR_HEAD_SIZE; i += 2) { + tmp = ptr8[i]; + ptr8[i] = ptr8[i + 1]; + ptr8[i + 1] = tmp; + } + } + + ddbs_init((short*)ptr8,0,p_bstrm); + int ret = ddbs_getbsid(p_bstrm, &bsid); + if (ret < 0) { + return -1; + } + + if (ISDDP(bsid)) { + Get_DDP_Parameters(ptr8, sample_rate, frame_size, ChNum); + }else if (ISDD(bsid)){ + Get_DD_Parameters(ptr8, sample_rate, frame_size, ChNum); + } + + return 0; +} + +//----------------------------DDP Media Source---------------------------------------------- + +static pthread_mutex_t decode_dev_op_mutex = PTHREAD_MUTEX_INITIALIZER; +static int decode_ThreadExitFlag = 0; //0:exit from thread; 1:thread looping +static int decode_ThreadStopFlag = 1; //0:start; 1: stop +static pthread_t decode_ThreadID = 0; + +DDP_Media_Source::DDP_Media_Source(void) { + ALOGI("[%s: %d]\n", __FUNCTION__, __LINE__); + mStarted = false; + mMeta = new MetaData; + mGroup = NULL; + mSample_rate = 0; + mChNum = 0; + mFrame_size = 0; + mStop_ReadBuf_Flag = 0; //0:start 1:stop +} + +DDP_Media_Source::~DDP_Media_Source() { +} + +int DDP_Media_Source::GetSampleRate() { + ALOGI("[DDP_Media_Source::%s: %d]\n", __FUNCTION__, __LINE__); + return mSample_rate; +} +int DDP_Media_Source::GetChNum() { + ALOGI("[DDP_Media_Source::%s: %d]\n", __FUNCTION__, __LINE__); + return mChNum; +} + +int DDP_Media_Source::Get_Stop_ReadBuf_Flag() { + return mStop_ReadBuf_Flag; +} + +int DDP_Media_Source::Set_Stop_ReadBuf_Flag(int Stop) { + //ALOGI("[DDP_Media_Source::%s: %d]\n",__FUNCTION__,__LINE__); + mStop_ReadBuf_Flag = Stop; + return 0; +} + +sp<MetaData> DDP_Media_Source::getFormat() { + ALOGI("[DDP_Media_Source::%s: %d]\n", __FUNCTION__, __LINE__); + return mMeta; +} + +status_t DDP_Media_Source::start(MetaData *params) { + ALOGI("[DDP_Media_Source::%s: %d]\n", __FUNCTION__, __LINE__); + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(4096)); + mStarted = true; + return OK; +} + +status_t DDP_Media_Source::stop() { + ALOGI("[DDP_Media_Source::%s: %d]\n", __FUNCTION__, __LINE__); + delete mGroup; + mGroup = NULL; + mStarted = false; + return OK; +} + +int DDP_Media_Source::MediaSourceRead_buffer(unsigned char *buffer, int size) { + int readcnt = -1; + int sleep_time = 0; + if ((mStop_ReadBuf_Flag == 1) || (decode_ThreadStopFlag == 1)) { + ALOGI("[DDP_Media_Source::%s] ddp mediasource stop!\n ", __FUNCTION__); + return -1; + } + while ((readcnt < size) && (mStop_ReadBuf_Flag == 0) + && (decode_ThreadStopFlag == 0)) { + readcnt = buffer_read(&android_out_buffer, (char*) buffer, size); + if (readcnt < 0) { + sleep_time++; + usleep(1000); //1ms + } + if (sleep_time > 2000) { //wait for max 1s to get audio data + ALOGE("[%s] time out to read audio buffer data! wait for 2s\n ", + __FUNCTION__); + return -1; + } + } + return readcnt; +} + +status_t DDP_Media_Source::read(MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + unsigned char ptr_head[PTR_HEAD_SIZE] = { 0 }; + int readedbytes; + int SyncFlag = 0; + + resync: mFrame_size = 0; + SyncFlag = 0; + + if ((mStop_ReadBuf_Flag == 1) || (decode_ThreadStopFlag == 1)) { + ALOGI("Stop Flag is set, stop read_buf [%s %d]", __FUNCTION__, + __LINE__); + return ERROR_END_OF_STREAM; + } + + if (MediaSourceRead_buffer(&ptr_head[0], 6) < 6) { + readedbytes = 6; + ALOGI("WARNING:read %d bytes failed [%s %d]!\n", readedbytes, + __FUNCTION__, __LINE__); + return ERROR_END_OF_STREAM; + } + + if ((mStop_ReadBuf_Flag == 1) || (decode_ThreadStopFlag == 1)) { + ALOGI("Stop Flag is set, stop read_buf [%s %d]", __FUNCTION__, + __LINE__); + return ERROR_END_OF_STREAM; + } + + while (!SyncFlag) { + int i; + for (i = 0; i <= 4; i++) { + if ((ptr_head[i] == 0x0b && ptr_head[i + 1] == 0x77) + || (ptr_head[i] == 0x77 && ptr_head[i + 1] == 0x0b)) { + memcpy(&ptr_head[0], &ptr_head[i], 6 - i); + if (MediaSourceRead_buffer(&ptr_head[6 - i], i) < i) { + readedbytes = i; + ALOGI("WARNING: read %d bytes failed [%s %d]!\n", + readedbytes, __FUNCTION__, __LINE__); + return ERROR_END_OF_STREAM; + } + + if ((mStop_ReadBuf_Flag == 1) || (decode_ThreadStopFlag == 1)) { + ALOGI("Stop Flag is set, stop read_buf [%s %d]", + __FUNCTION__, __LINE__); + return ERROR_END_OF_STREAM; + } + SyncFlag = 1; + break; + } + } + + if (SyncFlag == 0) { + ptr_head[0] = ptr_head[5]; + if (MediaSourceRead_buffer(&ptr_head[1], 5) < 5) { + readedbytes = 5; + ALOGI("WARNING: fpread_buffer read %d bytes failed [%s %d]!\n", + readedbytes, __FUNCTION__, __LINE__); + return ERROR_END_OF_STREAM; + } + + if ((mStop_ReadBuf_Flag == 1) || (decode_ThreadStopFlag == 1)) { + ALOGI("Stop Flag is set, stop read_buf [%s %d]", __FUNCTION__, + __LINE__); + return ERROR_END_OF_STREAM; + } + } + } + if (MediaSourceRead_buffer(&ptr_head[6], PTR_HEAD_SIZE - 6) + < (PTR_HEAD_SIZE - 6)) { + readedbytes = PTR_HEAD_SIZE - 6; + ALOGI("WARNING: fpread_buffer read %d bytes failed [%s %d]!\n", + readedbytes, __FUNCTION__, __LINE__); + return ERROR_END_OF_STREAM; + } + + Get_Parameters(ptr_head, &mSample_rate, &mFrame_size, &mChNum); + if ((mFrame_size == 0) || (mFrame_size < PTR_HEAD_SIZE) || (mChNum == 0) + || (mSample_rate == 0)) { + goto resync; + } + + MediaBuffer *buffer; + status_t err = mGroup->acquire_buffer(&buffer); + if (err != OK) { + return err; + } + memcpy((unsigned char*) (buffer->data()), ptr_head, PTR_HEAD_SIZE); + if (MediaSourceRead_buffer( + (unsigned char*) (buffer->data()) + PTR_HEAD_SIZE, + mFrame_size - PTR_HEAD_SIZE) != (mFrame_size - PTR_HEAD_SIZE)) { + ALOGI("[%s %d]stream read failed:bytes_req/%d\n", __FUNCTION__, + __LINE__, (mFrame_size - PTR_HEAD_SIZE)); + buffer->release(); + buffer = NULL; + return ERROR_END_OF_STREAM; + } + + buffer->set_range(0, mFrame_size); + buffer->meta_data()->setInt64(kKeyTime, 0); + buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); + + *out = buffer; + return OK; +} + +//-------------------------------OMX codec------------------------------------------------ + +const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3"; +Aml_OMX_Codec::Aml_OMX_Codec(void) { + ALOGI("[Aml_OMX_Codec::%s: %d]\n", __FUNCTION__, __LINE__); + m_codec = NULL; + status_t m_OMXClientConnectStatus = m_OMXClient.connect(); + lock_init(); + locked(); + buf_decode_offset = 0; + buf_decode_offset_pre = 0; + + if (m_OMXClientConnectStatus != OK) { + ALOGE("Err:omx client connect error\n"); + } else { + const char *mine_type = NULL; + mine_type = MEDIA_MIMETYPE_AUDIO_AC3; + m_OMXMediaSource = new DDP_Media_Source(); + sp < MetaData > metadata = m_OMXMediaSource->getFormat(); + metadata->setCString(kKeyMIMEType, mine_type); + m_codec = OMXCodec::Create(m_OMXClient.interface(), metadata, false, // createEncoder + m_OMXMediaSource, 0, 0); + + if (m_codec != NULL) { + ALOGI("OMXCodec::Create success %s %d \n", __FUNCTION__, __LINE__); + } else { + ALOGE("Err: OMXCodec::Create failed %s %d \n", __FUNCTION__, + __LINE__); + } + } + unlocked(); +} + +Aml_OMX_Codec::~Aml_OMX_Codec() { +} + +status_t Aml_OMX_Codec::read(unsigned char *buf, unsigned *size, int *exit) { + MediaBuffer *srcBuffer; + status_t status; + + m_OMXMediaSource->Set_Stop_ReadBuf_Flag(*exit); + + if (*exit) { + ALOGI("NOTE:exit flag enabled! [%s %d] \n", __FUNCTION__, __LINE__); + *size = 0; + return OK; + } + + status = m_codec->read(&srcBuffer, NULL); + + if (srcBuffer == NULL) { + *size = 0; + return OK; + } + + *size = srcBuffer->range_length(); + + if (status == OK && (*size != 0)) { + memcpy((unsigned char *) buf, + (unsigned char *) srcBuffer->data() + srcBuffer->range_offset(), + *size); + srcBuffer->set_range(srcBuffer->range_offset() + (*size), + srcBuffer->range_length() - (*size)); + srcBuffer->meta_data()->findInt64(kKeyTime, &buf_decode_offset); + } + + if (srcBuffer->range_length() == 0) { + srcBuffer->release(); + srcBuffer = NULL; + } + + return OK; +} + +status_t Aml_OMX_Codec::start() { + ALOGI("[Aml_OMX_Codec::%s %d] enter!\n", __FUNCTION__, __LINE__); + status_t status = m_codec->start(); + if (status != OK) { + ALOGE("Err:OMX client can't start OMX decoder! status=%d (0x%08x)\n", + (int) status, (int) status); + m_codec.clear(); + } + return status; +} + +void Aml_OMX_Codec::stop() { + ALOGI("[Aml_OMX_Codec::%s %d] enter!\n", __FUNCTION__, __LINE__); + if (m_codec != NULL) { + if (m_OMXMediaSource->Get_Stop_ReadBuf_Flag()) + m_OMXMediaSource->Set_Stop_ReadBuf_Flag(1); + m_codec->pause(); + m_codec->stop(); + wp < MediaSource > tmp = m_codec; + m_codec.clear(); + while (tmp.promote() != NULL) { + ALOGI("[Aml_OMX_Codec::%s %d]wait m_codec free OK!\n", __FUNCTION__, + __LINE__); + usleep(1000); + } + m_OMXClient.disconnect(); + m_OMXMediaSource.clear(); + } else + ALOGE("m_codec==NULL, m_codec->stop() failed! [%s %d] \n", __FUNCTION__, + __LINE__); +} + +void Aml_OMX_Codec::pause() { + ALOGI("[Aml_OMX_Codec::%s %d] \n", __FUNCTION__, __LINE__); + if (m_codec != NULL) + m_codec->pause(); + else + ALOGE("m_codec==NULL, m_codec->pause() failed! [%s %d] \n", + __FUNCTION__, __LINE__); +} + +int Aml_OMX_Codec::GetDecBytes() { + int used_len = 0; + used_len = buf_decode_offset - buf_decode_offset_pre; + buf_decode_offset_pre = buf_decode_offset; + return used_len; +} + +void Aml_OMX_Codec::lock_init() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(&lock, &attr); + pthread_mutexattr_destroy(&attr); +} +void Aml_OMX_Codec::locked() { + pthread_mutex_lock (&lock); +} +void Aml_OMX_Codec::unlocked() { + pthread_mutex_unlock (&lock); +} + +//--------------------------------OMX_Codec_local API------------------------------------------------- + +Aml_OMX_Codec *arm_omx_codec = NULL; + +void omx_codec_pause() { + if (arm_omx_codec != NULL) { + arm_omx_codec->locked(); + arm_omx_codec->pause(); + arm_omx_codec->unlocked(); + } else + ALOGE("arm_omx_codec==NULL arm_omx_codec->pause failed! %s %d \n", + __FUNCTION__, __LINE__); +} + +void omx_codec_read(unsigned char *buf, unsigned *size, int *exit) { + if (arm_omx_codec != NULL) { + arm_omx_codec->locked(); + arm_omx_codec->read(buf, size, exit); + arm_omx_codec->unlocked(); + } else + ALOGE("arm_omx_codec==NULL arm_omx_codec->read failed! %s %d \n", + __FUNCTION__, __LINE__); +} + +int omx_codec_get_declen() { + int declen = 0; + if (arm_omx_codec != NULL) { + arm_omx_codec->locked(); + declen = arm_omx_codec->GetDecBytes(); + arm_omx_codec->unlocked(); + } else { + ALOGI( + "NOTE:arm_omx_codec==NULL arm_omx_codec_get_declen() return 0! %s %d \n", + __FUNCTION__, __LINE__); + } + return declen; +} + +int omx_codec_get_FS() { + if (arm_omx_codec != NULL) { + return arm_omx_codec->m_OMXMediaSource->GetSampleRate(); + + } else { + ALOGI( + "NOTE:arm_omx_codec==NULL arm_omx_codec_get_FS() return 0! %s %d \n", + __FUNCTION__, __LINE__); + return 0; + } +} + +int omx_codec_get_Nch() { + if (arm_omx_codec != NULL) { + return arm_omx_codec->m_OMXMediaSource->GetChNum(); + } else { + ALOGI( + "NOTE:arm_omx_codec==NULL arm_omx_codec_get_Nch() return 0! %s %d \n", + __FUNCTION__, __LINE__); + return 0; + } +} + +//--------------------------------------Decoder ThreadLoop-------------------------------------------- + +void *decode_threadloop(void *args) { + unsigned int outlen = 0; + int write_sucessed = 1; + int ret = 0; + unsigned char tmp[8192]; + + ALOGI("[%s %d] enter!\n", __FUNCTION__, __LINE__); + while (decode_ThreadStopFlag == 0) { + if (write_sucessed == 1) { + outlen = 0; + omx_codec_read(&tmp[0], &outlen, &(decode_ThreadStopFlag)); + } + if (decode_ThreadStopFlag == 1) { + ALOGD("%s, exit threadloop! \n", __FUNCTION__); + break; + } + if (outlen > 0) { + ret = buffer_write(&DDP_out_buffer, (char *) (&tmp[0]), outlen); + if (ret < 0) { + write_sucessed = 0; + usleep(10 * 1000); //10ms + } else { + write_sucessed = 1; + } + } + } + + decode_ThreadExitFlag = 0; + ALOGD("%s, exiting...\n", __FUNCTION__); + return NULL; +} + +static int start_decode_thread_omx(void) { + pthread_attr_t attr; + struct sched_param param; + int ret = 0; + + ALOGI("[%s %d] enter!\n", __FUNCTION__, __LINE__); + pthread_mutex_lock(&decode_dev_op_mutex); + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_RR); + param.sched_priority = sched_get_priority_max(SCHED_RR); + pthread_attr_setschedparam(&attr, ¶m); + decode_ThreadStopFlag = 0; + decode_ThreadExitFlag = 1; + ret = pthread_create(&decode_ThreadID, &attr, &decode_threadloop, NULL); + pthread_attr_destroy(&attr); + if (ret != 0) { + ALOGE("%s, Create thread fail!\n", __FUNCTION__); + pthread_mutex_unlock(&decode_dev_op_mutex); + return -1; + } + pthread_mutex_unlock(&decode_dev_op_mutex); + ALOGD("[%s] exiting...\n", __FUNCTION__); + return 0; +} + +static int stop_decode_thread_omx(void) { + int i = 0, tmp_timeout_count = 1000; + + ALOGI("[%s %d] enter!\n", __FUNCTION__, __LINE__); + pthread_mutex_lock(&decode_dev_op_mutex); + + decode_ThreadStopFlag = 1; + while (1) { + if (decode_ThreadExitFlag == 0) + break; + if (i >= tmp_timeout_count) + break; + i++; + usleep(1000); + } + if (i >= tmp_timeout_count) { + ALOGE( + "%s, Timeout: we have try %d ms, but the aml audio thread's exec flag is still(%d)!!!\n", + __FUNCTION__, tmp_timeout_count, decode_ThreadExitFlag); + } else { + ALOGD("%s, kill decode thread success after try %d ms.\n", __FUNCTION__, + i); + } + + pthread_join(decode_ThreadID, NULL); + decode_ThreadID = 0; + + ALOGD("%s, aml audio close success.\n", __FUNCTION__); + pthread_mutex_unlock(&decode_dev_op_mutex); + return 0; +} + +//-------------------------------------external OMX_codec_api----------------------------------------- +extern "C" { +int omx_codec_init(void) { + int ret = 0; + ALOGI("omx_codec_init!\n"); + arm_omx_codec = new android::Aml_OMX_Codec(); + if (arm_omx_codec == NULL) { + ALOGE("Err:arm_omx_codec_init failed!\n"); + return -1; + } + + arm_omx_codec->locked(); + ret = arm_omx_codec->start(); + arm_omx_codec->unlocked(); + if (ret < 0) { + goto Exit; + } + + ret = start_decode_thread_omx(); + if (ret == 0) + return 0; + Exit: arm_omx_codec->stop(); + delete arm_omx_codec; + arm_omx_codec = NULL; + return -1; +} + +void omx_codec_close(void) { + int ret = 0; + if (arm_omx_codec == NULL) { + ALOGI( + "NOTE:arm_omx_codec==NULL arm_omx_codec_close() do nothing! %s %d \n", + __FUNCTION__, __LINE__); + return; + } + ALOGI("omx_codec_close!\n"); + stop_decode_thread_omx(); + arm_omx_codec->locked(); + arm_omx_codec->stop(); + arm_omx_codec->unlocked(); + delete arm_omx_codec; + arm_omx_codec = NULL; + return; +} + +} +} + diff --git a/libTVaudio/audio/DDP_media_source.h b/libTVaudio/audio/DDP_media_source.h new file mode 100644 index 0000000..8df117d --- a/dev/null +++ b/libTVaudio/audio/DDP_media_source.h @@ -0,0 +1,143 @@ +#ifndef __DDP_MEDIA_SOURCE_H__ +#define __DDP_MEDIA_SOURCE_H__ + +#include "MediaSource.h" +#include "DataSource.h" +#include "MediaBufferGroup.h" +#include "MetaData.h" +#include "OMXCodec.h" +#include "OMX_Index.h" +#include "OMX_Core.h" +#include "OMXClient.h" + +namespace android { + +#define DDPshort short +#define DDPerr short +#define DDPushort unsigned short +#define BYTESPERWRD 2 +#define BITSPERWRD (BYTESPERWRD*8) +#define SYNCWRD ((DDPshort)0x0b77) +#define MAXFSCOD 3 +#define MAXDDDATARATE 38 +#define BS_STD 8 +#define ISDD(bsid) ((bsid) <= BS_STD) +#define MAXCHANCFGS 8 +#define BS_AXE 16 +#define ISDDP(bsid) ((bsid) <= BS_AXE && (bsid) > 10) +#define BS_BITOFFSET 40 +#define PTR_HEAD_SIZE 7//20 + + +typedef struct { + DDPshort *buf; + DDPshort bitptr; + DDPshort data; +} DDP_BSTRM; + +const DDPshort chanary[MAXCHANCFGS] = { 2, 1, 2, 3, 3, 4, 4, 5 }; +enum { + MODE11 = 0, + MODE_RSVD = 0, + MODE10, + MODE20, + MODE30, + MODE21, + MODE31, + MODE22, + MODE32 +}; +const DDPushort msktab[] = { 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, + 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, + 0xfffe, 0xffff }; +const DDPshort frmsizetab[MAXFSCOD][MAXDDDATARATE] = { + /* 48kHz */ + { + 64, 64, 80, 80, 96, 96, 112, 112, + 128, 128, 160, 160, 192, 192, 224, 224, + 256, 256, 320, 320, 384, 384, 448, 448, + 512, 512, 640, 640, 768, 768, 896, 896, + 1024, 1024, 1152, 1152, 1280, 1280 + }, + /* 44.1kHz */ + { + 69, 70, 87, 88, 104, 105, 121, 122, + 139, 140, 174, 175, 208, 209, 243, 244, + 278, 279, 348, 349, 417, 418, 487, 488, + 557, 558, 696, 697, 835, 836, 975, 976, + 1114, 1115, 1253, 1254, 1393, 1394 + }, + /* 32kHz */ + { + 96, 96, 120, 120, 144, 144, 168, 168, + 192, 192, 240, 240, 288, 288, 336, 336, + 384, 384, 480, 480, 576, 576, 672, 672, + 768, 768, 960, 960, 1152, 1152, 1344, 1344, + 1536, 1536, 1728, 1728, 1920, 1920 + } +}; + +//-------------------------------------------------------------------------------- +class DDP_Media_Source: public MediaSource { +public: + DDP_Media_Source(void); + + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + virtual sp<MetaData> getFormat(); + virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = + NULL); + + virtual int GetSampleRate(); + virtual int GetChNum(); + + virtual int Get_Stop_ReadBuf_Flag(); + virtual int Set_Stop_ReadBuf_Flag(int StopFlag); + virtual int MediaSourceRead_buffer(unsigned char *buffer, int size); + +protected: + virtual ~DDP_Media_Source(); + +private: + + bool mStarted; + sp<MetaData> mMeta; + MediaBufferGroup *mGroup; + int mSample_rate; + int mChNum; + int mFrame_size; + int mStop_ReadBuf_Flag; + + DDP_Media_Source(const DDP_Media_Source &); + DDP_Media_Source &operator=(const DDP_Media_Source &); +}; + +//---------------------------------------------------------------------------------- +class Aml_OMX_Codec { +public: + + Aml_OMX_Codec(void); + + OMXClient m_OMXClient; + sp<DDP_Media_Source> m_OMXMediaSource; + sp<MediaSource> m_codec; + + int read(unsigned char *buf, unsigned *size, int* exit); + status_t start(); + void pause(); + void stop(); + void lock_init(); + void locked(); + void unlocked(); + int GetDecBytes(); + + int64_t buf_decode_offset; + int64_t buf_decode_offset_pre; + pthread_mutex_t lock; + + ~Aml_OMX_Codec(); +}; + +} + +#endif diff --git a/libTVaudio/audio/amaudio_main.cpp b/libTVaudio/audio/amaudio_main.cpp new file mode 100644 index 0000000..f236820 --- a/dev/null +++ b/libTVaudio/audio/amaudio_main.cpp @@ -0,0 +1,74 @@ +/* + This file is used for testing audio fuction. + */ + +#include <unistd.h> + +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> + +#include "../audio_amaudio.h" +#include "audio_usb_check.h" + +using namespace android; + +int main(int argc, char** argv) { + sp < ProcessState > proc(ProcessState::self()); + sp < IServiceManager > sm = defaultServiceManager(); + + //test for audio volume control + amAudioSetAndroidVolumeEnable(1); + amAudioSetAndroidVolume(60, 60); + sleep(10); + + //test for S805 HDMI_IN BOX + amAudioOpen(48000, CC_IN_USE_SPDIF_DEVICE, CC_OUT_USE_AMAUDIO); + amAudioOpen(48000, CC_IN_USE_SPDIF_DEVICE, CC_OUT_USE_ANDROID); + sleep(100); + + //test for TV + amAudioOpen(48000, CC_IN_USE_I2S_DEVICE, CC_OUT_USE_AMAUDIO); + amAudioOpen(48000, CC_IN_USE_I2S_DEVICE, CC_OUT_USE_ANDROID); + sleep(100); + + //test for data mix mode and mix volume + sleep(10); + amAudioSetOutputMode(2); + amAudioSetMusicGain(60); + sleep(10); + amAudioSetMusicGain(256); + sleep(10); + amAudioSetAndroidVolumeEnable(0); + sleep(10); + amAudioSetOutputMode(0); + amAudioSetLeftGain(256); + amAudioSetRightGain(256); + + //test for audio effect + sleep(30); + //EQ parameters + int gain_val_buf[5] = { 3, 2, 0, 2, 3 }; + amAudioSetEQGain(gain_val_buf, sizeof(gain_val_buf)); + amAudioSetEQEnable(1); + sleep(30); + + //srs parameters + amAudioSetSRSTrubassSpeakerSize(4); + amAudioSetSRSTrubassGain(0.3); + amAudioSetSRSDialogClarityGain(0.2); + amAudioSetSRSDefinitionGain(0.5); + amAudioSetSRSSurroundGain(0.6); + amAudioSetSRSDialogClaritySwitch(1); + amAudioSetSRSSurroundSwitch(1); + amAudioSetSRSTrubassSwitch(1); + + sleep(500); + + amAudioClose(); + + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} diff --git a/libTVaudio/audio/aml_audio.c b/libTVaudio/audio/aml_audio.c new file mode 100644 index 0000000..4791eec --- a/dev/null +++ b/libTVaudio/audio/aml_audio.c @@ -0,0 +1,1864 @@ +/* + ** aml_audio.c + ** + ** This program is designed for TV application. + ** author: Wang Zhe + ** Email: Zhe.Wang@amlogic.com + ** + */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <signal.h> +#include <pthread.h> +#include <unistd.h> +#include <math.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <cutils/log.h> +#include <cutils/properties.h> +#include "tinyalsa/asoundlib.h" + +#include "android_out.h" +#include "aml_audio.h" + +#define LOG_TAG "aml_audio" + +#define ANDROID_OUT_BUFFER_SIZE (2048*8*2)//in byte +#define DDP_OUT_BUFFER_SIZE (2048*8*2)//in byte +#define DEFAULT_OUT_SAMPLE_RATE (48000) +#define DEFAULT_IN_SAMPLE_RATE (48000) +#define PLAYBACK_PERIOD_SIZE (512) +#define CAPTURE_PERIOD_SIZE (512) +#define PLAYBACK_PERIOD_COUNT (4) +#define CAPTURE_PERIOD_COUNT (4) +#define TEMP_BUFFER_SIZE (PLAYBACK_PERIOD_SIZE * 4 * 3) +//output device ID from audio.h +#define AUDIO_DEVICE_OUT_SPEAKER (0x2) +#define AUDIO_DEVICE_OUT_REMOTE_SUBMIX (0x8000) + +static struct pcm_config pcm_config_out = { + .channels = 2, + .rate = DEFAULT_OUT_SAMPLE_RATE, + .period_size = PLAYBACK_PERIOD_SIZE, + .period_count = PLAYBACK_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .stop_threshold = PLAYBACK_PERIOD_SIZE*PLAYBACK_PERIOD_COUNT, +}; + +static struct pcm_config pcm_config_in = { + .channels = 2, + .rate = DEFAULT_IN_SAMPLE_RATE, + .period_size = CAPTURE_PERIOD_SIZE, + .period_count = CAPTURE_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .stop_threshold = CAPTURE_PERIOD_SIZE*CAPTURE_PERIOD_COUNT*10, +}; + +struct buffer_status { + short *start_add; + int size; + int level; + unsigned int rd; + unsigned int wr; +}; + +struct resample_para { + unsigned int FractionStep; + unsigned int SampleFraction; + short lastsample_left; + short lastsample_right; +}; + +struct aml_stream_in { + pthread_mutex_t lock; + struct pcm_config config; + struct pcm *pcm; + int card; + int device; + int standby; + int resample_request; + void *resample_temp_buffer; + struct resample_para resample; + int max_bytes; + void *temp_buffer; + void *write_buffer; +}; + +struct aml_stream_out { + pthread_mutex_t lock; + struct pcm_config config; + struct pcm *pcm; + int card; + int device; + int standby; + int max_bytes; + void *temp_buffer; + void *read_buffer; + int output_device; + int amAudio_OutHandle; + struct buffer_status playback_buf; + struct buffer_status read_buf; + int amaudio_out_read_enable; + int user_set_device; +}; + +struct aml_dev { + struct aml_stream_in in; + struct aml_stream_out out; + pthread_t aml_Audio_ThreadID; + int aml_Audio_ThreadTurnOnFlag; + int aml_Audio_ThreadExecFlag; + int has_EQ_lib; + int has_SRS_lib; + int output_deviceID; +}; + +static void *start_temp_buffer = NULL; + +static struct aml_dev gmAmlDevice = { + .in = { + .lock = PTHREAD_MUTEX_INITIALIZER, + .config = { + .channels = 2, + .rate = DEFAULT_IN_SAMPLE_RATE, + .period_size = CAPTURE_PERIOD_SIZE, + .period_count = CAPTURE_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .stop_threshold = CAPTURE_PERIOD_SIZE*CAPTURE_PERIOD_COUNT*10, + }, + .pcm = NULL, + .card = 0, + .device = 0, + .standby = 0, + .resample_request = 0, + .resample_temp_buffer = NULL, + .resample = { + .FractionStep = 0, + .SampleFraction = 0, + .lastsample_left = 0, + .lastsample_right = 0, + }, + .max_bytes = 0, + .temp_buffer = NULL, + .write_buffer = NULL, + }, + + .out = { + .lock = PTHREAD_MUTEX_INITIALIZER, + .config = { + .channels = 2, + .rate = DEFAULT_OUT_SAMPLE_RATE, + .period_size = PLAYBACK_PERIOD_SIZE, + .period_count = PLAYBACK_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, + .stop_threshold = PLAYBACK_PERIOD_SIZE*PLAYBACK_PERIOD_COUNT, + }, + .pcm = NULL, + .card = 0, + .device = 0, + .standby = 0, + .max_bytes = 0, + .temp_buffer = NULL, + .read_buffer = NULL, + .output_device = 0, + .amAudio_OutHandle = 0, + .playback_buf = { + .start_add = NULL, + .size = 0, + .level = 0, + .rd = 0, + .wr = 0, + }, + .read_buf = { + .start_add = NULL, + .size = 0, + .level = 0, + .rd = 0, + .wr = 0, + }, + .amaudio_out_read_enable = 0, + .user_set_device = 0, + }, + + .aml_Audio_ThreadID = 0, + .aml_Audio_ThreadTurnOnFlag = 0, + .aml_Audio_ThreadExecFlag = 0, + .has_EQ_lib = 0, + .has_SRS_lib = 0, + .output_deviceID = 0, +}; + +struct circle_buffer android_out_buffer = { + .lock = PTHREAD_MUTEX_INITIALIZER, + .start_add = NULL, + .rd = NULL, + .wr = NULL, + .size = 0, +}; + +struct circle_buffer DDP_out_buffer = { + .lock = PTHREAD_MUTEX_INITIALIZER, + .start_add = NULL, + .rd = NULL, + .wr = NULL, + .size = 0, +}; + +static struct aml_dev *gpAmlDevice = NULL; +static pthread_mutex_t amaudio_dev_op_mutex = PTHREAD_MUTEX_INITIALIZER; + +extern int omx_codec_init(void); +extern void omx_codec_close(void); +extern int I2S_state; + +#define PCM_DATA 0 +#define RAW_DATA 1 +#define HDMI_IN_AUDIO_TYPE "HDMI Audio Type" +#define SPDIF_IN_AUDIO_TYPE "SPDIFIN Audio Type" +#define Audio_In_Source_TYPE "Audio In Source" +#define AMAUDIO_IN "/dev/amaudio2_in" +#define AMAUDIO_OUT "/dev/amaudio2_out" +#define AMAUDIO2_PREENABLE "/sys/class/amaudio2/aml_amaudio2_enable" + +#define AMAUDIO_IOC_MAGIC 'A' +#define AMAUDIO_IOC_GET_SIZE _IOW(AMAUDIO_IOC_MAGIC, 0x00, int) +#define AMAUDIO_IOC_GET_PTR _IOW(AMAUDIO_IOC_MAGIC, 0x01, int) +#define AMAUDIO_IOC_RESET _IOW(AMAUDIO_IOC_MAGIC, 0x02, int) +#define AMAUDIO_IOC_UPDATE_APP_PTR _IOW(AMAUDIO_IOC_MAGIC, 0x03, int) +#define AMAUDIO_IOC_AUDIO_OUT_MODE _IOW(AMAUDIO_IOC_MAGIC, 0x04, int) +#define AMAUDIO_IOC_MIC_LEFT_GAIN _IOW(AMAUDIO_IOC_MAGIC, 0x05, int) +#define AMAUDIO_IOC_MIC_RIGHT_GAIN _IOW(AMAUDIO_IOC_MAGIC, 0x06, int) +#define AMAUDIO_IOC_MUSIC_GAIN _IOW(AMAUDIO_IOC_MAGIC, 0x07, int) +#define AMAUDIO_IOC_GET_PTR_READ _IOW(AMAUDIO_IOC_MAGIC, 0x08, int) +#define AMAUDIO_IOC_UPDATE_APP_PTR_READ _IOW(AMAUDIO_IOC_MAGIC, 0x09, int) +#define AMAUDIO_IOC_OUT_READ_ENABLE _IOW(AMAUDIO_IOC_MAGIC, 0x0a, int) +#define AMAUDIO_IOC_SET_ANDROID_VOLUME_ENABLE _IOW(AMAUDIO_IOC_MAGIC, 0x0b, int) +#define AMAUDIO_IOC_SET_ANDROID_LEFT_VOLUME _IOW(AMAUDIO_IOC_MAGIC, 0x0c, int) +#define AMAUDIO_IOC_SET_ANDROID_RIGHT_VOLUME _IOW(AMAUDIO_IOC_MAGIC, 0x0d, int) + +#define CC_DUMP_SRC_TYPE_INPUT (0) +#define CC_DUMP_SRC_TYPE_OUTPUT (1) +#define CC_DUMP_SRC_TYPE_IN_OUT (2) +#define CC_DUMP_SRC_TYPE_OUT_IN (3) + +static int amaudio2_out_handle = -1; +static int gDumpDataFlag = 0; +static int gDumpDataFd1 = -1; +static int gDumpDataFd2 = -1; +static int audioin_type = 0; +static int omx_started = 0; +static int raw_data_counter = 0; +int output_record_enable = 0; +pthread_mutex_t device_change_lock = PTHREAD_MUTEX_INITIALIZER; + +static void DoDumpData(void *data_buf, int size, int aud_src_type); + +inline int GetWriteSpace(char *WritePoint, char *ReadPoint, int buffer_size) { + int bytes; + + if (WritePoint >= ReadPoint) { + bytes = buffer_size - (WritePoint - ReadPoint); + } else { + bytes = ReadPoint - WritePoint; + } + return bytes; +} + +inline int GetReadSpace(char *WritePoint, char *ReadPoint, int buffer_size) { + int bytes; + + if (WritePoint >= ReadPoint) { + bytes = WritePoint - ReadPoint; + } else { + bytes = buffer_size - (ReadPoint - WritePoint); + } + return bytes; +} + +inline int write_to_buffer(char *current_pointer, char *buffer, int bytes, + char *start_buffer, int buffer_size) { + int left_bytes = start_buffer + buffer_size - current_pointer; + + if (left_bytes >= bytes) { + memcpy(current_pointer, buffer, bytes); + } else { + memcpy(current_pointer, buffer, left_bytes); + memcpy(start_buffer, buffer + left_bytes, bytes - left_bytes); + } + return 0; +} + +inline int read_from_buffer(char *current_pointer, char *buffer, int bytes, + char *start_buffer, int buffer_size) { + int left_bytes = start_buffer + buffer_size - current_pointer; + + if (left_bytes >= bytes) { + memcpy(buffer, current_pointer, bytes); + } else { + memcpy(buffer, current_pointer, left_bytes); + memcpy(buffer + left_bytes, start_buffer, bytes - left_bytes); + } + return 0; +} + +inline void* update_pointer(char *current_pointer, int bytes, + char *start_buffer, int buffer_size) { + current_pointer += bytes; + if (current_pointer >= start_buffer + buffer_size) { + current_pointer -= buffer_size; + } + return current_pointer; +} + +//Clip from 16.16 fixed-point to 0.15 fixed-point. +inline static short clip(int x) { + if (x < -32768) { + return -32768; + } else if (x > 32767) { + return 32767; + } else { + return x; + } +} + +static int resampler_init(struct aml_stream_in *in) { + ALOGD("%s, Init Resampler!\n", __FUNCTION__); + + static const double kPhaseMultiplier = 1L << 28; + + in->resample.FractionStep = (unsigned int) (in->config.rate + * kPhaseMultiplier / pcm_config_in.rate); + in->resample.SampleFraction = 0; + + size_t buffer_size = in->config.period_size * 4; + in->resample_temp_buffer = malloc(buffer_size); + if (in->resample_temp_buffer == NULL) { + ALOGE("%s, Malloc resample buffer failed!\n", __FUNCTION__); + return -1; + } + in->max_bytes = (in->config.period_size * pcm_config_in.rate + / in->config.rate + 1) << 2; + return 0; +} + +static int resample_process(struct aml_stream_in *in, unsigned int in_frame, + short* input, short* output) { + unsigned int inputIndex = 0; + unsigned int outputIndex = 0; + unsigned int FractionStep = in->resample.FractionStep; + + static const uint32_t kPhaseMask = (1LU << 28) - 1; + unsigned int frac = in->resample.SampleFraction; + short lastsample_left = in->resample.lastsample_left; + short lastsample_right = in->resample.lastsample_right; + + while (inputIndex == 0) { + *output++ = clip( + (int) lastsample_left + + ((((int) input[0] - (int) lastsample_left) + * ((int) frac >> 13)) >> 15)); + *output++ = clip( + (int) lastsample_right + + ((((int) input[1] - (int) lastsample_right) + * ((int) frac >> 13)) >> 15)); + + frac += FractionStep; + inputIndex += (frac >> 28); + frac = (frac & kPhaseMask); + outputIndex++; + } + + while (inputIndex < in_frame) { + *output++ = clip( + (int) input[2 * inputIndex - 2] + + ((((int) input[2 * inputIndex] + - (int) input[2 * inputIndex - 2]) + * ((int) frac >> 13)) >> 15)); + *output++ = clip( + (int) input[2 * inputIndex - 1] + + ((((int) input[2 * inputIndex + 1] + - (int) input[2 * inputIndex - 1]) + * ((int) frac >> 13)) >> 15)); + + frac += FractionStep; + inputIndex += (frac >> 28); + frac = (frac & kPhaseMask); + outputIndex++; + } + + in->resample.lastsample_left = input[2 * in_frame - 2]; + in->resample.lastsample_right = input[2 * in_frame - 1]; + in->resample.SampleFraction = frac; + + return outputIndex; +} + +static int tmp_buffer_init(struct circle_buffer *tmp, int buffer_size) { + struct circle_buffer *buf = tmp; + pthread_mutex_lock(&buf->lock); + + buf->size = buffer_size; + buf->start_add = malloc(buffer_size * sizeof(char)); + if (buf->start_add == NULL) { + ALOGD("%s, Malloc android out buffer error!\n", __FUNCTION__); + pthread_mutex_unlock(&buf->lock); + return -1; + } + buf->rd = buf->start_add; + buf->wr = buf->start_add + buf->size / 2; + + pthread_mutex_unlock(&buf->lock); + return 0; +} + +static int tmp_buffer_release(struct circle_buffer *tmp) { + struct circle_buffer *buf = tmp; + pthread_mutex_lock(&buf->lock); + + if (buf->start_add != NULL) { + free(buf->start_add); + buf->start_add = NULL; + } + buf->rd = NULL; + buf->wr = NULL; + buf->size = 0; + + pthread_mutex_unlock(&buf->lock); + return 0; +} + +static int tmp_buffer_reset(struct circle_buffer *tmp) { + struct circle_buffer *buf = tmp; + buf->rd = buf->wr + buf->size / 2; + if (buf->rd >= (buf->start_add + buf->size)) + buf->rd -= buf->size; + return 0; +} + +int buffer_write(struct circle_buffer *tmp, char* buffer, size_t bytes) { + struct circle_buffer *buf = tmp; + pthread_mutex_lock(&buf->lock); + if (buf->start_add == NULL || buf->wr == NULL || buf->wr == NULL + || buf->size == 0) { + ALOGE("%s, Buffer malloc fail!\n", __FUNCTION__); + pthread_mutex_unlock(&buf->lock); + return -1; + } + size_t write_space = GetWriteSpace(buf->wr, buf->rd, buf->size); + if (write_space < bytes) { + //tmp_buffer_reset(buf); + //ALOGD("%s, no space to write %d bytes to buffer.\n", __FUNCTION__,bytes); + pthread_mutex_unlock(&buf->lock); + return -1; + } + write_to_buffer(buf->wr, buffer, bytes, buf->start_add, buf->size); + buf->wr = update_pointer(buf->wr, bytes, buf->start_add, buf->size); + pthread_mutex_unlock(&buf->lock); + return bytes; +} + +int buffer_read(struct circle_buffer *tmp, char* buffer, size_t bytes) { + struct circle_buffer *buf = tmp; + pthread_mutex_lock(&buf->lock); + if (buf->start_add == NULL || buf->wr == NULL || buf->wr == NULL + || buf->size == 0) { + ALOGE("%s, Buffer malloc fail!\n", __FUNCTION__); + pthread_mutex_unlock(&buf->lock); + return -1; + } + size_t read_space = GetReadSpace(buf->wr, buf->rd, buf->size); + if (read_space < bytes) { + //tmp_buffer_reset(buf); + //ALOGD("%s, no space to read %d bytes to buffer.\n", __FUNCTION__,bytes); + pthread_mutex_unlock(&buf->lock); + return -1; + } + read_from_buffer(buf->rd, buffer, bytes, buf->start_add, buf->size); + buf->rd = update_pointer(buf->rd, bytes, buf->start_add, buf->size); + pthread_mutex_unlock(&buf->lock); + return bytes; +} + +int GetOutputdevice(void) { + if (gpAmlDevice == NULL) + return -1; + return gpAmlDevice->output_deviceID; +} + +static int set_input_stream_sample_rate(unsigned int sr, + struct aml_stream_in *in) { + if (check_input_stream_sr(sr) == 0) { + in->config.rate = sr; + } else { + if (sr == 0) { + in->config.rate = pcm_config_in.rate; + } else { + ALOGE("%s, The sample rate (%u) is invalid!\n", __FUNCTION__, sr); + return -1; + } + } + return 0; +} + +static int get_aml_card(void) { + int card = -1, err = -1; + int fd = -1; + unsigned fileSize = 512; + char *read_buf = NULL, *pd = NULL; + static const char * const SOUND_CARDS_PATH = "/proc/asound/cards"; + fd = open(SOUND_CARDS_PATH, O_RDONLY); + if (fd < 0) { + ALOGE("ERROR: failed to open config file %s error: %d\n", + SOUND_CARDS_PATH, errno); + return -EINVAL; + } + + read_buf = (char *) malloc(fileSize); + if (!read_buf) { + ALOGE("Failed to malloc read_buf"); + close(fd); + return -ENOMEM; + } + memset(read_buf, 0x0, fileSize); + err = read(fd, read_buf, fileSize); + if (err < 0) { + ALOGE("ERROR: failed to read config file %s error: %d\n", + SOUND_CARDS_PATH, errno); + close(fd); + free(read_buf); + return -EINVAL; + } + pd = strstr(read_buf, "AML"); + card = *(pd - 3) - '0'; + + free(read_buf); + close(fd); + return card; +} + +static int alsa_in_open(struct aml_stream_in *in) { + in->config.channels = pcm_config_in.channels; + in->config.period_size = pcm_config_in.period_size; + in->config.period_count = pcm_config_in.period_count; + in->config.format = pcm_config_in.format; + in->config.stop_threshold = CAPTURE_PERIOD_SIZE * CAPTURE_PERIOD_COUNT * 4; + in->standby = 1; + in->resample_request = 0; + in->resample_temp_buffer = NULL; + in->max_bytes = in->config.period_size << 2; + + if (in->config.rate == 0) { + in->config.rate = pcm_config_in.rate; + } + + if (in->config.rate != pcm_config_in.rate) { + in->resample_request = 1; + int ret = resampler_init(in); + if (ret < 0) { + return -1; + } + } + + pthread_mutex_lock(&in->lock); + in->card = get_aml_card(); + ALOGE("pcm in card ID = %d \n", in->card); + in->pcm = pcm_open(in->card, in->device, PCM_IN, &pcm_config_in); + if (!pcm_is_ready(in->pcm)) { + ALOGE("%s, Unable to open PCM device in: %s\n", __FUNCTION__, + pcm_get_error(in->pcm)); + pcm_close(in->pcm); + pthread_mutex_unlock(&in->lock); + return -1; + } + + in->standby = 0; + ALOGD("%s, Input device is opened: card(%d), device(%d)\n", __FUNCTION__, + in->card, in->device); + pthread_mutex_unlock(&in->lock); + return 0; +} + +static int alsa_in_close(struct aml_stream_in *in) { + ALOGD("%s, Do input close!\n", __FUNCTION__); + + pthread_mutex_lock(&in->lock); + if (!in->standby) { + pcm_close(in->pcm); + in->pcm = NULL; + in->standby = 1; + } + if (in->resample_request && (in->resample_temp_buffer != NULL)) { + free(in->resample_temp_buffer); + in->resample_temp_buffer = NULL; + } + pthread_mutex_unlock(&in->lock); + return 0; +} + +static int get_in_framesize(struct aml_stream_in *in) { + int sample_format = 0; + if (in->config.format == PCM_FORMAT_S16_LE) { + sample_format = 2; + } + return sample_format * in->config.channels; +} + +static int alsa_in_read(struct aml_stream_in *in, void* buffer, size_t bytes) { + int ret; + + pthread_mutex_lock(&in->lock); + if (in->standby) { + pthread_mutex_unlock(&in->lock); + ALOGD("%s, Input device is closed!\n", __FUNCTION__); + return 0; + } + //if raw data in HDMI-in, no need to resample + if (GetOutputdevice() == 2) { + in->resample_request == 0; + } + + int output_size = 0; + if (in->resample_request == 1) { + ret = pcm_read(in->pcm, in->resample_temp_buffer, bytes); + if (ret < 0) { + //wait for next frame + usleep(bytes * 1000000 / get_in_framesize(in) / in->config.rate); + pthread_mutex_unlock(&in->lock); + return ret; + } + + DoDumpData(in->resample_temp_buffer, bytes, CC_DUMP_SRC_TYPE_INPUT); + + output_size = resample_process(in, bytes >> 2, + (short *) in->resample_temp_buffer, (short *) buffer) << 2; + } else { + ret = pcm_read(in->pcm, buffer, bytes); + if (ret < 0) { + //wait for next frame + usleep(bytes * 1000000 / get_in_framesize(in) / in->config.rate); + pthread_mutex_unlock(&in->lock); + return ret; + } + + DoDumpData(buffer, bytes, CC_DUMP_SRC_TYPE_INPUT); + + output_size = bytes; + } + pthread_mutex_unlock(&in->lock); + return output_size; +} + +static int alsa_out_open(struct aml_stream_out *out) { + out->config.channels = pcm_config_out.channels; + out->config.rate = pcm_config_out.rate; + out->config.period_size = pcm_config_out.period_size; + out->config.period_count = pcm_config_out.period_count; + out->config.format = pcm_config_out.format; + out->config.stop_threshold = PLAYBACK_PERIOD_SIZE * PLAYBACK_PERIOD_COUNT; + out->standby = 1; + out->max_bytes = out->config.period_size << 2; + out->amaudio_out_read_enable = 0; + + pthread_mutex_lock(&out->lock); + out->card = get_aml_card(); + out->pcm = pcm_open(out->card, out->device, PCM_OUT, &pcm_config_out); + if (!pcm_is_ready(out->pcm)) { + ALOGE("%s, Unable to open PCM device out: %s\n", __FUNCTION__, + pcm_get_error(out->pcm)); + pcm_close(out->pcm); + pthread_mutex_unlock(&out->lock); + return -1; + } + out->standby = 0; + ALOGD("%s, Output device is opened: card(%d), device(%d)\n", __FUNCTION__, + out->card, out->device); + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int alsa_out_close(struct aml_stream_out *out) { + ALOGD("%s, Do output close!\n", __FUNCTION__); + + pthread_mutex_lock(&out->lock); + if (!out->standby) { + pcm_close(out->pcm); + out->pcm = NULL; + out->standby = 1; + } + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int get_out_framesize(struct aml_stream_out *out) { + int sample_format = 0; + if (out->config.format == PCM_FORMAT_S16_LE) + sample_format = 2; + return sample_format * out->config.channels; +} + +static int alsa_out_write(struct aml_stream_out *out, void* buffer, + size_t bytes) { + int ret; + + pthread_mutex_lock(&out->lock); + if (out->standby) { + pthread_mutex_unlock(&out->lock); + ALOGD("%s, Output device is closed!\n", __FUNCTION__); + return 0; + } + + ret = pcm_write(out->pcm, buffer, bytes); + if (ret < 0) { + usleep(bytes * 1000000 / get_out_framesize(out) / out->config.rate); + pthread_mutex_unlock(&out->lock); + return ret; + } + + pthread_mutex_unlock(&out->lock); + return bytes; +} + +static int reset_amaudio(struct aml_stream_out *out, int delay_size) { + struct buffer_status *buf = &out->playback_buf; + buf->rd = 0; + buf->wr = 0; + buf->level = buf->size; + struct buffer_status *buf1 = &out->read_buf; + buf1->rd = 0; + buf1->wr = 0; + buf1->level = 0; + int ret = ioctl(out->amAudio_OutHandle, AMAUDIO_IOC_RESET, delay_size); + if (ret < 0) { + ALOGE("%s, amaudio reset delay_size error!\n", __FUNCTION__); + return -1; + } + return 0; +} + +static int set_amaudio2_enable(int flag) { + int fd = 0; + char string[16]; + fd = open(AMAUDIO2_PREENABLE, O_CREAT | O_RDWR, 0664); + if (fd < 0) { + ALOGE("unable to open file %s \n", AMAUDIO2_PREENABLE); + return -1; + } + sprintf(string, "%d", flag); + write(fd, string, strlen(string)); + close(fd); + return 0; +} +static int new_audiotrack(struct aml_stream_out *out) { + int i = 0, ret = 0; + int dly_tm = 20 * 1000, dly_cnt = 1000; //20s + + pthread_mutex_lock(&out->lock); + + ALOGD("%s, entering...\n", __FUNCTION__); + set_amaudio2_enable(1); + ret = new_android_audiotrack(); + if (ret < 0) { + ALOGE("%s, New an audio track is fail!\n", __FUNCTION__); + pthread_mutex_unlock(&out->lock); + return -1; + } + + while (I2S_state < 10) { + usleep(dly_tm); + + i++; + if (i >= dly_cnt) { + release_android_audiotrack(); + pthread_mutex_unlock(&out->lock); + ALOGE("%s, Time out error: wait %d ms for waiting I2S ready.\n", + __FUNCTION__, i * dly_tm / 1000); + return -1; + } + } + ALOGD("%s, sucess: wait %d ms for waiting I2S ready.\n", __FUNCTION__, + i * dly_tm / 1000); + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int new_audiotrack_nowait(struct aml_stream_out *out) { + int ret = 0; + pthread_mutex_lock(&out->lock); + ALOGD("%s, entering...\n", __FUNCTION__); + set_amaudio2_enable(1); + ret = new_android_audiotrack(); + if (ret < 0) { + ALOGE("%s, New an audio track is fail!\n", __FUNCTION__); + pthread_mutex_unlock(&out->lock); + return -1; + } + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int release_audiotrack(struct aml_stream_out *out) { + ALOGD("%s, Release audio track!\n", __FUNCTION__); + pthread_mutex_lock(&out->lock); + int ret = release_android_audiotrack(); + if (ret < 0) { + ALOGE("%s, Delete audio track is fail!\n", __FUNCTION__); + } + set_amaudio2_enable(0); + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int amaudio_out_open(struct aml_stream_out *out) { + + out->config.channels = pcm_config_out.channels; + out->config.rate = pcm_config_out.rate; + out->config.period_size = pcm_config_out.period_size; + out->config.period_count = pcm_config_out.period_count; + out->config.format = pcm_config_out.format; + + out->standby = 1; + out->max_bytes = out->config.period_size << 2; + out->amaudio_out_read_enable = 0; + + pthread_mutex_lock(&out->lock); + out->amAudio_OutHandle = -1; + out->amAudio_OutHandle = open(AMAUDIO_OUT, O_RDWR); + if (out->amAudio_OutHandle < 0) { + close(out->amAudio_OutHandle); + out->amAudio_OutHandle = -1; + release_android_audiotrack(); + pthread_mutex_unlock(&out->lock); + ALOGE("%s, The device amaudio_out cant't be opened!\n", __FUNCTION__); + return -1; + } + + struct buffer_status *buf = &out->playback_buf; + buf->size = ioctl(out->amAudio_OutHandle, AMAUDIO_IOC_GET_SIZE); + buf->start_add = (short*) mmap(NULL, buf->size, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, out->amAudio_OutHandle, 0); + if (buf->start_add == 0) { + close(out->amAudio_OutHandle); + out->amAudio_OutHandle = -1; + release_android_audiotrack(); + pthread_mutex_unlock(&out->lock); + ALOGE("%s, Error create mmap!\n", __FUNCTION__); + return -1; + } + + struct buffer_status *buf1 = &out->read_buf; + buf1->size = buf->size; + + out->standby = 0; + pthread_mutex_unlock(&out->lock); + ALOGD("%s, Amaudio device is opened!\n", __FUNCTION__); + return 0; +} + +static int amaudio_out_close(struct aml_stream_out *out) { + ALOGD("%s, Do amaudio device close!\n", __FUNCTION__); + pthread_mutex_lock(&out->lock); + if (out->amAudio_OutHandle > 0) { + close(out->amAudio_OutHandle); + out->amAudio_OutHandle = -1; + munmap(out->playback_buf.start_add, out->playback_buf.size); + } + pthread_mutex_unlock(&out->lock); + return 0; +} + +static int amaudio_out_write(struct aml_stream_out *out, void* buffer, + size_t bytes) { + int block = bytes >> 6 << 6; //align 2^6 + char *in_ptr = (char *) buffer; + char *out_ptr = NULL; + + int k = 0, i = 0; + struct buffer_status *buf = &out->playback_buf; + + pthread_mutex_lock(&out->lock); + + //get rd ptr, and calculate write space + buf->rd = ioctl(out->amAudio_OutHandle, AMAUDIO_IOC_GET_PTR); + buf->level = buf->size - ((buf->size + buf->wr - buf->rd) % buf->size); + + if (buf->level <= block) { + ALOGD("Reset amaudio: buf->level=%x,buf->rd = %x,buf->wr=%x\n", + buf->level, buf->rd, buf->wr); + pthread_mutex_unlock(&out->lock); + return -1; + } + + out_ptr = &(buf->start_add[buf->wr / 2]); + memcpy(out_ptr, in_ptr, block); + + // update the write pointer and write space + buf->wr = (buf->wr + block) % buf->size; + buf->level = buf->size - ((buf->size + buf->wr - buf->rd) % buf->size); + ioctl(out->amAudio_OutHandle, AMAUDIO_IOC_UPDATE_APP_PTR, buf->wr); + pthread_mutex_unlock(&out->lock); + + return block; +} + +int amaudio_out_read_enable(int enable) { + int ret; + + if (gpAmlDevice == NULL) { + ALOGE("%s, aml audio is not open, must open it first!\n", __FUNCTION__); + return -1; + } + + int OutHandle = gpAmlDevice->out.amAudio_OutHandle; + if (OutHandle < 0) { + ALOGE("%s, amaudio out handle error!\n", __FUNCTION__); + return -1; + } + + pthread_mutex_lock(&gpAmlDevice->out.lock); + gpAmlDevice->out.amaudio_out_read_enable = enable; + reset_amaudio(&gpAmlDevice->out, 64 * 32 * 2); + ioctl(OutHandle, AMAUDIO_IOC_OUT_READ_ENABLE, enable); + ALOGD("%s, out read enable :%d!\n", __FUNCTION__, enable); + pthread_mutex_unlock(&gpAmlDevice->out.lock); + return 0; +} + +static int amaudio_out_read(struct aml_stream_out *out, void* buffer, + size_t bytes) { + int block = bytes >> 6 << 6; //align 2^6 + char *in = (char *) buffer; + struct buffer_status *buf = &out->read_buf; + + pthread_mutex_lock(&out->lock); + + buf->wr = ioctl(out->amAudio_OutHandle, AMAUDIO_IOC_GET_PTR_READ); + buf->level = (buf->size + buf->wr - buf->rd) % buf->size; + + if (buf->level < block) { + usleep(5000); + pthread_mutex_unlock(&out->lock); + ALOGD("buf->level=%d,buf->rd = %d,buf->wr=%d\n", buf->level, buf->rd, + buf->wr); + return 0; + } + + int Ret = read(out->amAudio_OutHandle, (char *) buffer, block); + if (Ret != block) { + ALOGE("%s, amAudio2 read from hardware buffer failed!\n", __FUNCTION__); + pthread_mutex_unlock(&out->lock); + return -1; + } + + // update the read pointer + buf->rd += block; + buf->rd %= buf->size; + buf->level = (buf->size + buf->wr - buf->rd) % buf->size; + + ioctl(out->amAudio_OutHandle, AMAUDIO_IOC_UPDATE_APP_PTR_READ, buf->rd); + pthread_mutex_unlock(&out->lock); + return block; +} + +static int malloc_buffer(struct aml_dev *device) { + void *buffer = NULL; + struct aml_stream_in *in = &device->in; + struct aml_stream_out *out = &device->out; + + buffer = malloc(TEMP_BUFFER_SIZE); + if (buffer == NULL) { + ALOGD("%s, Malloc temp buffer failed!\n", __FUNCTION__); + return -1; + } + start_temp_buffer = buffer; + in->write_buffer = buffer; + out->read_buffer = buffer; + + in->temp_buffer = malloc(in->max_bytes); + if (in->temp_buffer == NULL) { + ALOGD("%s, Malloc input temp buffer failed!\n", __FUNCTION__); + return -1; + } + + out->temp_buffer = malloc(pcm_config_out.period_size << 2); + if (out->temp_buffer == NULL) { + ALOGD("%s, Malloc output temp buffer failed!\n", __FUNCTION__); + return -1; + } + + return 0; +} + +static int release_buffer(struct aml_dev *device) { + struct aml_stream_in *in = &device->in; + struct aml_stream_out *out = &device->out; + + if (start_temp_buffer != NULL) { + free(start_temp_buffer); + start_temp_buffer = NULL; + in->write_buffer = NULL; + out->read_buffer = NULL; + } + if (in->temp_buffer != NULL) { + free(in->temp_buffer); + in->temp_buffer = NULL; + } + if (out->temp_buffer != NULL) { + free(out->temp_buffer); + out->temp_buffer = NULL; + } + return 0; +} + +static int audio_effect_release() { + unload_EQ_lib(); + unload_SRS_lib(); + return 0; +} + +static int set_output_deviceID(int deviceID) { + int ret; + + if (gpAmlDevice == NULL) { + ALOGE("%s, aml audio is not open, must open it first!\n", __FUNCTION__); + return -1; + } + + gpAmlDevice->output_deviceID = deviceID; + ALOGE("%s, set output device ID: %d!\n", __FUNCTION__, deviceID); + return 0; +} + +static int aml_device_init(struct aml_dev *device) { + int ret; + + ALOGD("%s, start to open Devices!\n", __FUNCTION__); + + //Malloc temp buffer for audiotrak out + ret = tmp_buffer_init(&android_out_buffer, ANDROID_OUT_BUFFER_SIZE); + if (ret < 0) { + ALOGE("%s, malloc temp buffer error!\n", __FUNCTION__); + goto error1; + } + + ret = tmp_buffer_init(&DDP_out_buffer, DDP_OUT_BUFFER_SIZE); + if (ret < 0) { + ALOGE("%s, malloc ddp buffer failed!\n", __FUNCTION__); + goto error2; + } + + //open input device of tinyalsa + ret = alsa_in_open(&device->in); + if (ret < 0) { + ALOGE("%s, open alsa in device open error!\n", __FUNCTION__); + goto error3; + } + + //Malloc temp buffer for input and output + ret = malloc_buffer(device); + if (ret < 0) { + ALOGE("%s, malloc buffer error!\n", __FUNCTION__); + goto error4; + } + + if (device->out.user_set_device == CC_OUT_USE_ALSA) { + set_output_deviceID(0); + //open output device of tinyalsa + ret = alsa_out_open(&device->out); + if (ret < 0) { + ALOGE("%s, open alsa out device open error!\n", __FUNCTION__); + goto error5; + } + } else if (device->out.user_set_device == CC_OUT_USE_AMAUDIO) { + set_output_deviceID(0); + //open output device of amaudio + ret = new_audiotrack(&device->out); + if (ret < 0) { + ALOGE("%s, new audiotrack error!\n", __FUNCTION__); + goto error5; + } + ret = amaudio_out_open(&device->out); + if (ret < 0) { + release_audiotrack(&device->out); + ALOGE("%s, open amaudio out device error!\n", __FUNCTION__); + goto error5; + } + } else if (device->out.user_set_device == CC_OUT_USE_ANDROID) { + set_output_deviceID(1); + ret = new_audiotrack_nowait(&device->out); + if (ret < 0) { + ALOGE("%s, open android out device error!\n", __FUNCTION__); + goto error5; + } + } + + //EQ lib load and init EQ + ret = load_EQ_lib(); + if (ret < 0) { + ALOGE("%s, Load EQ lib fail!\n", __FUNCTION__); + device->has_EQ_lib = 0; + } else { + ret = HPEQ_init(); + if (ret < 0) { + device->has_EQ_lib = 0; + } else { + device->has_EQ_lib = 1; + } + HPEQ_enable(1); + } + + //load srs lib and init it. SRS is behand resampling, so sample rate is as default sr. + ret = load_SRS_lib(); + if (ret < 0) { + ALOGE("%s, Load EQ lib fail!\n", __FUNCTION__); + device->has_SRS_lib = 0; + } else { + ret = srs_init(device->out.config.rate); + if (ret < 0) { + device->has_SRS_lib = 0; + } else { + device->has_SRS_lib = 1; + } + } + + ALOGD("%s, exiting...\n", __FUNCTION__); + return 0; + + error5: release_buffer(device); + error4: alsa_in_close(&device->in); + error3: tmp_buffer_release (&DDP_out_buffer); + error2: tmp_buffer_release (&android_out_buffer); + error1: return ret; + +} + +static int aml_device_close(struct aml_dev *device) { + struct aml_stream_in *in = &device->in; + struct aml_stream_out *out = &device->out; + + alsa_in_close(in); + + if (out->output_device == CC_OUT_USE_ALSA) { + alsa_out_close(out); + } else if (out->output_device == CC_OUT_USE_AMAUDIO) { + amaudio_out_close(out); + release_audiotrack(out); + } else if (out->output_device == CC_OUT_USE_ANDROID) { + release_audiotrack(out); + } + omx_codec_close(); + omx_started = 0; + tmp_buffer_release (&DDP_out_buffer); + tmp_buffer_release (&android_out_buffer); + release_buffer(device); + audio_effect_release(); + return 0; +} + +static int gUSBCheckLastFlag = 0; +static int gUSBCheckFlag = 0; + +static void USB_check(struct aml_stream_out *out) { + + gUSBCheckFlag = GetUsbAudioCheckFlag(); + if (gUSBCheckLastFlag == gUSBCheckFlag) { + return; + } + + ALOGI("Audio Device is changed from %x to %x!\n", gUSBCheckLastFlag, gUSBCheckFlag); + + //if audio record from submix, don't change device + if ((gUSBCheckFlag & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) != 0) { + gUSBCheckLastFlag = gUSBCheckFlag; + set_output_record_enable(1); + return; + } else if((gUSBCheckLastFlag & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) != 0) { + gUSBCheckLastFlag = gUSBCheckFlag; + set_output_record_enable(0); + return; + } + + if ((gUSBCheckFlag & AUDIO_DEVICE_OUT_SPEAKER) == 0) { + if (out->output_device == CC_OUT_USE_AMAUDIO && omx_started == 0) { + amaudio_out_close(out); + set_output_deviceID(1); + out->output_device = CC_OUT_USE_ANDROID; + } else if (out->output_device == CC_OUT_USE_ALSA && omx_started == 0) { + alsa_out_close(out); + new_audiotrack_nowait(out); + set_output_deviceID(1); + out->output_device = CC_OUT_USE_ANDROID; + } + ALOGI("%s, USB audio playback device is in.\n", __FUNCTION__); + } else if ((gUSBCheckFlag & AUDIO_DEVICE_OUT_SPEAKER) != 0 && gUSBCheckLastFlag != 0) { + if (out->user_set_device == CC_OUT_USE_AMAUDIO && omx_started == 0) { + amaudio_out_open(out); + set_output_deviceID(0); + out->output_device = CC_OUT_USE_AMAUDIO; + } else if (out->user_set_device == CC_OUT_USE_ALSA + && omx_started == 0) { + release_audiotrack(out); + alsa_out_open(out); + set_output_deviceID(0); + out->output_device = CC_OUT_USE_ALSA; + } + ALOGI("%s, USB audio playback device is out.\n", __FUNCTION__); + } + gUSBCheckLastFlag = gUSBCheckFlag; + return; +} + +static int get_channel_status(void) { + struct mixer *pmixer; + struct mixer_ctl *pctl; + int card_id; + int type_HDMI = -1; + int type_SPDIF = -1; + int type_AUDIO_IN = -1; + + card_id = get_aml_card(); + pmixer = mixer_open(card_id); + if (NULL == pmixer) { + ALOGE("[%s:%d] Failed to open mixer\n", __FUNCTION__, __LINE__); + goto err_exit; + } + pctl = mixer_get_ctl_by_name(pmixer, Audio_In_Source_TYPE); + if (NULL != pctl) { + type_AUDIO_IN = mixer_ctl_get_value(pctl, 0); + if (type_AUDIO_IN != 2) { + mixer_close(pmixer); + return PCM_DATA; + } + } + + pctl = mixer_get_ctl_by_name(pmixer, SPDIF_IN_AUDIO_TYPE); + if (NULL != pctl) { + type_SPDIF = mixer_ctl_get_value(pctl, 0); + } + + pctl = mixer_get_ctl_by_name(pmixer, HDMI_IN_AUDIO_TYPE); + if (NULL != pctl) { + type_HDMI = mixer_ctl_get_value(pctl, 0); + } + + if (type_SPDIF == RAW_DATA || type_HDMI == RAW_DATA) { + mixer_close(pmixer); + return RAW_DATA; + } else { + mixer_close(pmixer); + return PCM_DATA; + } + err_exit: if (NULL != pmixer) { + mixer_close(pmixer); + } + return -1; +} + +static int set_rawdata_in_enable(struct aml_stream_out *out) { + if (out->output_device == CC_OUT_USE_AMAUDIO) { + amaudio_out_close(out); + } else if (out->output_device == CC_OUT_USE_ALSA) { + alsa_out_close(out); + new_audiotrack_nowait(out); + } + set_output_deviceID(2); + out->output_device = CC_OUT_USE_ANDROID; + omx_codec_init(); + return 0; +} + +static int set_rawdata_in_disable(struct aml_stream_out *out) { + omx_codec_close(); + if (gUSBCheckFlag == 0) { + if (out->user_set_device == CC_OUT_USE_AMAUDIO) { + set_output_deviceID(0); + amaudio_out_open(out); + out->output_device = CC_OUT_USE_AMAUDIO; + } else if (out->user_set_device == CC_OUT_USE_ANDROID) { + set_output_deviceID(1); + out->output_device = CC_OUT_USE_ANDROID; + } else if (out->user_set_device == CC_OUT_USE_ALSA) { + release_audiotrack(out); + alsa_out_open(out); + set_output_deviceID(0); + out->output_device = CC_OUT_USE_ALSA; + } + } else if (gUSBCheckFlag == 1) { + set_output_deviceID(1); + out->output_device = CC_OUT_USE_ANDROID; + } + return 0; +} + +int set_output_record_enable(int enable) { + pthread_mutex_lock(&device_change_lock); + if (enable == 0) { + output_record_enable = 0; + ALOGI("%s, set output record disable!\n", __FUNCTION__); + } else if (enable == 1) { + output_record_enable = 1; + ALOGI("%s, set output record enable\n", __FUNCTION__); + } else { + ALOGE("%s, invalid setting!\n", __FUNCTION__); + } + pthread_mutex_unlock(&device_change_lock); + return 0; +} + +static int check_audio_type(struct aml_stream_out *out) { + audioin_type = get_channel_status(); + + if (audioin_type == 1 && omx_started == 0) { + raw_data_counter++; + } + + if (raw_data_counter >= 3 && omx_started == 0) { + ALOGI("%s, audio type is changed to RAW data input!\n", __FUNCTION__); + set_rawdata_in_enable(out); + omx_started = 1; + raw_data_counter = 0; + } else if (audioin_type == 0 && omx_started == 1) { + ALOGI("%s, audio type is changed to PCM data input!\n", __FUNCTION__); + set_rawdata_in_disable(out); + omx_started = 0; + } + return 0; +} + +static void* aml_audio_threadloop(void *data) { + struct aml_stream_in *in = NULL; + struct aml_stream_out *out = NULL; + int output_size = 0; + + ALOGD("%s, entering...\n", __FUNCTION__); + + if (gpAmlDevice == NULL) { + ALOGE("%s, gpAmlDevice is NULL\n", __FUNCTION__); + return ((void *) 0); + } + + in = &gpAmlDevice->in; + out = &gpAmlDevice->out; + out->max_bytes = pcm_config_out.period_size << 2; + + gpAmlDevice->aml_Audio_ThreadExecFlag = 1; + ALOGD("%s, set aml_Audio_ThreadExecFlag as 1.\n", __FUNCTION__); + + if (gpAmlDevice->out.user_set_device == CC_OUT_USE_AMAUDIO) { + int delay_size = 64 * 32 * 2; //less than 10.67*2 ms delay + reset_amaudio(out, delay_size); + } + + gUSBCheckLastFlag = 0; + gUSBCheckFlag = 0; + + while (gpAmlDevice != NULL && gpAmlDevice->aml_Audio_ThreadTurnOnFlag) { + //exit threadloop + if (gpAmlDevice->aml_Audio_ThreadTurnOnFlag == 0) { + ALOGD("%s, aml_Audio_ThreadTurnOnFlag is 0 break now.\n", + __FUNCTION__); + break; + } + if (GetWriteSpace((char *) in->write_buffer, (char *) out->read_buffer, + TEMP_BUFFER_SIZE) > in->max_bytes) { + output_size = alsa_in_read(in, in->temp_buffer, + in->config.period_size * 4); + if (output_size < 0) { + //ALOGE("%s, alsa_in_read fail!\n", __FUNCTION__); + } else { + if (gpAmlDevice->has_EQ_lib && (GetOutputdevice() == 0)) { + HPEQ_process((short *) in->temp_buffer, + (short *) in->temp_buffer, output_size >> 2); + } + write_to_buffer((char *) in->write_buffer, + (char *) in->temp_buffer, output_size, + (char *) start_temp_buffer, TEMP_BUFFER_SIZE); + in->write_buffer = update_pointer((char *) in->write_buffer, + output_size, (char *) start_temp_buffer, + TEMP_BUFFER_SIZE); + check_audio_type(out); + } + + } + + USB_check(out); + + if (GetReadSpace((char *) in->write_buffer, (char *) out->read_buffer, + TEMP_BUFFER_SIZE) > out->max_bytes) { + read_from_buffer((char *) out->read_buffer, + (char *) out->temp_buffer, out->max_bytes, + (char *) start_temp_buffer, TEMP_BUFFER_SIZE); + + output_size = out->max_bytes; + if (gpAmlDevice->has_SRS_lib && (GetOutputdevice() == 0)) { + output_size = srs_process((short *) out->temp_buffer, + (short *) out->temp_buffer, out->max_bytes >> 2); + } + if (gpAmlDevice->out.output_device == CC_OUT_USE_ALSA) { + output_size = alsa_out_write(out, out->temp_buffer, + output_size); + } else if (gpAmlDevice->out.output_device == CC_OUT_USE_AMAUDIO) { + output_size = amaudio_out_write(out, out->temp_buffer, + output_size); + if (output_size < 0) { + amaudio_out_close(out); + set_output_deviceID(0); + amaudio_out_open(out); + reset_amaudio(out, 4096); + } + if (output_record_enable == 1) { + buffer_write(&android_out_buffer, out->temp_buffer, + output_size); + } + } else if (gpAmlDevice->out.output_device == CC_OUT_USE_ANDROID) { + output_size = buffer_write(&android_out_buffer, + out->temp_buffer, output_size); + } + + if (output_size < 0) { + //ALOGE("%s, out_write fail! bytes = %d \n", __FUNCTION__, output_size); + } else { + out->read_buffer = update_pointer((char *) out->read_buffer, + output_size, (char *) start_temp_buffer, + TEMP_BUFFER_SIZE); + DoDumpData(out->temp_buffer, output_size, + CC_DUMP_SRC_TYPE_OUTPUT); + memset(out->temp_buffer, 0, output_size); + } + } + } + + if (gpAmlDevice != NULL) { + gpAmlDevice->aml_Audio_ThreadTurnOnFlag = 0; + ALOGD("%s, set aml_Audio_ThreadTurnOnFlag as 0.\n", __FUNCTION__); + gpAmlDevice->aml_Audio_ThreadExecFlag = 0; + ALOGD("%s, set aml_Audio_ThreadExecFlag as 0.\n", __FUNCTION__); + } + + ALOGD("%s, exiting...\n", __FUNCTION__); + return ((void *) 0); +} + +static int clrDevice(struct aml_dev *device) { + memset((void *) device, 0, sizeof(struct aml_dev)); + + device->in.config.channels = 2; + device->in.config.rate = DEFAULT_IN_SAMPLE_RATE; + device->in.config.period_size = CAPTURE_PERIOD_SIZE; + device->in.config.period_count = CAPTURE_PERIOD_COUNT; + device->in.config.format = PCM_FORMAT_S16_LE; + + device->out.config.channels = 2; + device->out.config.rate = DEFAULT_OUT_SAMPLE_RATE; + device->out.config.period_size = PLAYBACK_PERIOD_SIZE; + device->out.config.period_count = PLAYBACK_PERIOD_COUNT; + device->out.config.format = PCM_FORMAT_S16_LE; + + return 0; +} + +int aml_audio_open(unsigned int sr, int input_device, int output_device) { + pthread_attr_t attr; + struct sched_param param; + int ret; + + ALOGD("%s, sr = %d, output_device = %d\n", __FUNCTION__, sr, output_device); + + aml_audio_close(); + + pthread_mutex_lock(&amaudio_dev_op_mutex); + + gpAmlDevice = &gmAmlDevice; + clrDevice(gpAmlDevice); + + ret = set_input_stream_sample_rate(sr, &gpAmlDevice->in); + if (ret < 0) { + ALOGE("%s, set_input_stream_sample_rate fail!\n", __FUNCTION__); + clrDevice(gpAmlDevice); + gpAmlDevice = NULL; + pthread_mutex_unlock(&amaudio_dev_op_mutex); + return -1; + } + + gpAmlDevice->out.output_device = output_device; + gpAmlDevice->out.user_set_device = output_device; + if (gpAmlDevice->out.user_set_device == CC_OUT_USE_ALSA) { + ALOGD("%s,Use tinyalsa as output device!\n", __FUNCTION__); + } else if (gpAmlDevice->out.user_set_device == CC_OUT_USE_AMAUDIO) { + ALOGD("%s, Use amlogic amaudio as output device!\n", __FUNCTION__); + } else if (gpAmlDevice->out.user_set_device == CC_OUT_USE_ANDROID) { + ALOGD("%s, Use amlogic android as output device!\n", __FUNCTION__); + } else { + ALOGE("%s, Unkown output device, use default amaudio\n", __FUNCTION__); + gpAmlDevice->out.user_set_device = CC_OUT_USE_AMAUDIO; + } + + gpAmlDevice->in.device = input_device; + + ret = aml_device_init(gpAmlDevice); + if (ret < 0) { + ALOGE("%s, Devices fail opened!\n", __FUNCTION__); + clrDevice(gpAmlDevice); + gpAmlDevice = NULL; + pthread_mutex_unlock(&amaudio_dev_op_mutex); + return -1; + } + + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_RR); + param.sched_priority = sched_get_priority_max(SCHED_RR); + pthread_attr_setschedparam(&attr, ¶m); + gpAmlDevice->aml_Audio_ThreadTurnOnFlag = 1; + ALOGD("%s, set aml_Audio_ThreadTurnOnFlag as 1.\n", __FUNCTION__); + gpAmlDevice->aml_Audio_ThreadExecFlag = 0; + ALOGD("%s, set aml_Audio_ThreadExecFlag as 0.\n", __FUNCTION__); + ret = pthread_create(&gpAmlDevice->aml_Audio_ThreadID, &attr, + &aml_audio_threadloop, NULL); + pthread_attr_destroy(&attr); + if (ret != 0) { + ALOGE("%s, Create thread fail!\n", __FUNCTION__); + aml_device_close(gpAmlDevice); + clrDevice(gpAmlDevice); + gpAmlDevice = NULL; + pthread_mutex_unlock(&amaudio_dev_op_mutex); + return -1; + } + + pthread_mutex_unlock(&amaudio_dev_op_mutex); + + ALOGD("%s, exiting...\n", __FUNCTION__); + return 0; +} + +int aml_audio_close(void) { + int i = 0, tmp_timeout_count = 1000; + + ALOGD("%s, gpAmlDevice = %p\n", __FUNCTION__, gpAmlDevice); + + pthread_mutex_lock(&amaudio_dev_op_mutex); + + if (gpAmlDevice != NULL) { + gpAmlDevice->aml_Audio_ThreadTurnOnFlag = 0; + ALOGD("%s, set aml_Audio_ThreadTurnOnFlag as 0.\n", __FUNCTION__); + while (1) { + if (gpAmlDevice->aml_Audio_ThreadExecFlag == 0) { + break; + } + + if (i >= tmp_timeout_count) { + break; + } + + i++; + + usleep(10 * 1000); + } + + if (i >= tmp_timeout_count) { + ALOGE( + "%s, we have try %d times, but the aml audio thread's exec flag is still(%d)!!!\n", + __FUNCTION__, tmp_timeout_count, + gpAmlDevice->aml_Audio_ThreadExecFlag); + } else { + ALOGD("%s, kill aml audio thread success after try %d times.\n", + __FUNCTION__, i); + } + + pthread_join(gpAmlDevice->aml_Audio_ThreadID, NULL); + gpAmlDevice->aml_Audio_ThreadID = 0; + + aml_device_close(gpAmlDevice); + clrDevice(gpAmlDevice); + gpAmlDevice = NULL; + + ALOGD("%s, aml audio close success.\n", __FUNCTION__); + } + + pthread_mutex_unlock(&amaudio_dev_op_mutex); + return 0; +} + +int check_input_stream_sr(unsigned int sr) { + if (sr >= 8000 && sr <= 48000) { + return 0; + } + return -1; +} + +int set_android_volume_enable(int enable) { + if (amaudio2_out_handle < 0) { + amaudio2_out_handle = open(AMAUDIO_OUT, O_RDWR); + if (amaudio2_out_handle < 0) { + ALOGE("%s, The device amaudio_out cant't be opened!\n", + __FUNCTION__); + return -1; + } + ALOGI("%s, get amaudio2 handle = %d!\n", __FUNCTION__, + amaudio2_out_handle); + } + + if (enable != 0 && enable != 1) { + ALOGE("invalid value: enable = %d. (warning: 0 or 1 is valid)\n", + enable); + return -1; + } + + ioctl(amaudio2_out_handle, AMAUDIO_IOC_SET_ANDROID_VOLUME_ENABLE, enable); + + return 0; +} + +int set_android_volume(int left, int right) { + if (amaudio2_out_handle < 0) { + amaudio2_out_handle = open(AMAUDIO_OUT, O_RDWR); + if (amaudio2_out_handle < 0) { + ALOGE("%s, The device amaudio_out cant't be opened!\n", + __FUNCTION__); + return -1; + } + ALOGI("%s, get amaudio2 handle = %d!\n", __FUNCTION__, + amaudio2_out_handle); + } + + if (left < 0 || left > 256 || right < 0 || right > 256) { + ALOGE( + "invalid value: left = %d, right = %d. (warning: 0-256 is valid)\n", + left, right); + return -1; + } + + ioctl(amaudio2_out_handle, AMAUDIO_IOC_SET_ANDROID_LEFT_VOLUME, left); + ioctl(amaudio2_out_handle, AMAUDIO_IOC_SET_ANDROID_RIGHT_VOLUME, right); + return 0; +} + +int set_output_mode(int mode) { + if (gpAmlDevice == NULL) { + ALOGE("%s, aml audio is not open, must open it first!\n", __FUNCTION__); + return -1; + } + + if (mode < CC_OUT_MODE_DIRECT || mode > CC_OUT_MODE_DIRECT_MIX) { + ALOGE("%s, mode error: mode = %d!\n", __FUNCTION__, mode); + return -1; + } + + int OutHandle = gpAmlDevice->out.amAudio_OutHandle; + if (OutHandle < 0) { + ALOGE("%s, amaudio out handle error!\n", __FUNCTION__); + return -1; + } + + pthread_mutex_lock(&gpAmlDevice->out.lock); + ioctl(OutHandle, AMAUDIO_IOC_AUDIO_OUT_MODE, mode); + pthread_mutex_unlock(&gpAmlDevice->out.lock); + return 0; +} + +int set_music_gain(int gain) { + if (gpAmlDevice == NULL) { + ALOGE("%s, aml audio is not open, must open it first!\n", __FUNCTION__); + return -1; + } + + int OutHandle = gpAmlDevice->out.amAudio_OutHandle; + if (OutHandle < 0) { + ALOGE("%s, amaudio out handle error!\n", __FUNCTION__); + return -1; + } + + pthread_mutex_lock(&gpAmlDevice->out.lock); + if (gain > 256) { + gain = 256; + } + if (gain < 0) { + gain = 0; + } + ioctl(OutHandle, AMAUDIO_IOC_MUSIC_GAIN, gain); + ALOGD("%s, music gain :%d!\n", __FUNCTION__, gain); + pthread_mutex_unlock(&gpAmlDevice->out.lock); + return 0; +} + +int set_left_gain(int left_gain) { + if (gpAmlDevice == NULL) { + ALOGE("%s, aml audio is not open, must open it first!\n", __FUNCTION__); + return -1; + } + + int OutHandle = gpAmlDevice->out.amAudio_OutHandle; + if (OutHandle < 0) { + ALOGE("%s, amaudio out handle error!\n", __FUNCTION__); + return -1; + } + pthread_mutex_lock(&gpAmlDevice->out.lock); + if (left_gain > 256) { + left_gain = 256; + } + if (left_gain < 0) { + left_gain = 0; + } + ioctl(OutHandle, AMAUDIO_IOC_MIC_LEFT_GAIN, left_gain); + ALOGD("%s, left mic gain :%d!\n", __FUNCTION__, left_gain); + pthread_mutex_unlock(&gpAmlDevice->out.lock); + return 0; +} + +int set_right_gain(int right_gain) { + if (gpAmlDevice == NULL) { + ALOGE("%s, aml audio is not open, must open it first!\n", __FUNCTION__); + return -1; + } + int OutHandle = gpAmlDevice->out.amAudio_OutHandle; + if (OutHandle < 0) { + ALOGE("%s, amaudio out handle error!\n", __FUNCTION__); + return -1; + } + pthread_mutex_lock(&gpAmlDevice->out.lock); + if (right_gain > 256) { + right_gain = 256; + } + if (right_gain < 0) { + right_gain = 0; + } + ioctl(OutHandle, AMAUDIO_IOC_MIC_RIGHT_GAIN, right_gain); + ALOGD("%s, right mic gain :%d!\n", __FUNCTION__, right_gain); + pthread_mutex_unlock(&gpAmlDevice->out.lock); + return 0; +} + +int SetDumpDataFlag(int tmp_flag) { + int tmp_val; + tmp_val = gDumpDataFlag; + gDumpDataFlag = tmp_flag; + return tmp_val; +} + +int GetDumpDataFlag(void) { + int tmp_val = 0; + tmp_val = gDumpDataFlag; + return tmp_val; +} + +static void DoDumpData(void *data_buf, int size, int aud_src_type) { + int tmp_type = 0; + char prop_value[PROPERTY_VALUE_MAX] = { 0 }; + char file_path_01[PROPERTY_VALUE_MAX] = { 0 }; + char file_path_02[PROPERTY_VALUE_MAX] = { 0 }; + + if (GetDumpDataFlag() == 0) { + return; + } + + memset(prop_value, '\0', PROPERTY_VALUE_MAX); + property_get("audio.dumpdata.en", prop_value, "null"); + if (strcasecmp(prop_value, "null") == 0 + || strcasecmp(prop_value, "0") == 0) { + if (gDumpDataFd1 >= 0) { + close(gDumpDataFd1); + gDumpDataFd1 = -1; + } + if (gDumpDataFd2 >= 0) { + close(gDumpDataFd2); + gDumpDataFd2 = -1; + } + + return; + } + + tmp_type = CC_DUMP_SRC_TYPE_INPUT; + property_get("audio.dumpdata.src", prop_value, "null"); + if (strcasecmp(prop_value, "null") == 0 + || strcasecmp(prop_value, "input") == 0) { + tmp_type = CC_DUMP_SRC_TYPE_INPUT; + } else if (strcasecmp(prop_value, "output") == 0) { + tmp_type = CC_DUMP_SRC_TYPE_OUTPUT; + } else if (strcasecmp(prop_value, "input,output") == 0) { + tmp_type = CC_DUMP_SRC_TYPE_IN_OUT; + } else if (strcasecmp(prop_value, "output,input") == 0) { + tmp_type = CC_DUMP_SRC_TYPE_OUT_IN; + } + + if (tmp_type == CC_DUMP_SRC_TYPE_INPUT + || tmp_type == CC_DUMP_SRC_TYPE_OUTPUT) { + if (tmp_type != aud_src_type) { + return; + } + } + + memset(file_path_01, '\0', PROPERTY_VALUE_MAX); + property_get("audio.dumpdata.path", file_path_01, "null"); + if (strcasecmp(file_path_01, "null") == 0) { + file_path_01[0] = '\0'; + } + + if (tmp_type == CC_DUMP_SRC_TYPE_IN_OUT + || tmp_type == CC_DUMP_SRC_TYPE_OUT_IN) { + memset(file_path_02, '\0', PROPERTY_VALUE_MAX); + property_get("audio.dumpdata.path2", file_path_02, "null"); + if (strcasecmp(file_path_02, "null") == 0) { + file_path_02[0] = '\0'; + } + } + + if (gDumpDataFd1 < 0 && file_path_01[0] != '\0') { + if (access(file_path_01, 0) == 0) { + gDumpDataFd1 = open(file_path_01, O_RDWR | O_SYNC); + if (gDumpDataFd1 < 0) { + ALOGE("%s, Open device file \"%s\" error: %s.\n", __FUNCTION__, + file_path_01, strerror(errno)); + } + } else { + gDumpDataFd1 = open(file_path_01, O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR); + if (gDumpDataFd1 < 0) { + ALOGE("%s, Create device file \"%s\" error: %s.\n", + __FUNCTION__, file_path_01, strerror(errno)); + } + } + } + + if (gDumpDataFd2 < 0 && file_path_02[0] != '\0' + && (tmp_type == CC_DUMP_SRC_TYPE_IN_OUT + || tmp_type == CC_DUMP_SRC_TYPE_OUT_IN)) { + if (access(file_path_02, 0) == 0) { + gDumpDataFd2 = open(file_path_02, O_RDWR | O_SYNC); + if (gDumpDataFd2 < 0) { + ALOGE("%s, Open device file \"%s\" error: %s.\n", __FUNCTION__, + file_path_02, strerror(errno)); + } + } else { + gDumpDataFd2 = open(file_path_02, O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR); + if (gDumpDataFd2 < 0) { + ALOGE("%s, Create device file \"%s\" error: %s.\n", + __FUNCTION__, file_path_02, strerror(errno)); + } + } + } + + if (tmp_type == CC_DUMP_SRC_TYPE_IN_OUT) { + if (aud_src_type == CC_DUMP_SRC_TYPE_INPUT && gDumpDataFd1 >= 0) { + write(gDumpDataFd1, data_buf, size); + } else if (aud_src_type == CC_DUMP_SRC_TYPE_OUTPUT + && gDumpDataFd2 >= 0) { + write(gDumpDataFd2, data_buf, size); + } + } else if (tmp_type == CC_DUMP_SRC_TYPE_OUT_IN) { + if (aud_src_type == CC_DUMP_SRC_TYPE_OUTPUT && gDumpDataFd1 >= 0) { + write(gDumpDataFd1, data_buf, size); + } else if (aud_src_type == CC_DUMP_SRC_TYPE_INPUT + && gDumpDataFd2 >= 0) { + write(gDumpDataFd2, data_buf, size); + } + } else { + if (gDumpDataFd1 >= 0) { + write(gDumpDataFd1, data_buf, size); + } + } +} diff --git a/libTVaudio/audio/aml_audio.h b/libTVaudio/audio/aml_audio.h new file mode 100644 index 0000000..1e37f07 --- a/dev/null +++ b/libTVaudio/audio/aml_audio.h @@ -0,0 +1,73 @@ +#ifndef __TV_AML_AUDIO_H__ +#define __TV_AML_AUDIO_H__ + +#include "audio_effect_control.h" +#include "audio_usb_check.h" + +/* + In this system, input device is always ALSA_in, but There are 3 devices outpurt. + For TV application, AMAUDIO OUT is suggested. This mode has low latency. + IF HMDI/SPDIF has raw data input, ANDROID OUT is suggested. + */ +#define CC_OUT_USE_AMAUDIO (0) +#define CC_OUT_USE_ALSA (1) +#define CC_OUT_USE_ANDROID (2) + +/* + mix mode: + DIRECT, input is direct to output, cover the local sound. + INTER_MIX, left and right input channels mix first as one channel, and then mix with local sound. + DIRECT_MIX,left input channel mix with local left channel, right input channel mix with local right channel + */ +#define CC_OUT_MODE_DIRECT (0) +#define CC_OUT_MODE_INTER_MIX (1) +#define CC_OUT_MODE_DIRECT_MIX (2) + +/* + There are two input device, spdif or i2s. + */ +#define CC_IN_USE_I2S_DEVICE (0) +#define CC_IN_USE_SPDIF_DEVICE (1) + +#define CC_SINGLE_OUTPUT (0) +#define CC_DOUBLE_OUTPUT (1) + +#ifdef __cplusplus +extern "C" { +#endif + +struct circle_buffer { + pthread_mutex_t lock; + char *start_add; + char *rd; + char *wr; + int size; +}; + +/* + In this system, input stream sample rate can be set from 8K-48K, and output sample rate is fixed 48K. + When input stream sample rate is different from output, inlined reample is in operation. If input stream sr is not set, + the input stream is default 48K. + */ +int GetOutputdevice(void); +int aml_audio_open(unsigned int sr, int input_device, int output_device); +int aml_audio_close(void); +int check_input_stream_sr(unsigned int sr); +int SetDumpDataFlag(int tmp_flag); +int GetDumpDataFlag(); +int set_output_mode(int mode); +int set_music_gain(int gain); +int set_left_gain(int left_gain); +int set_right_gain(int right_gain); +int buffer_read(struct circle_buffer *tmp, char* buffer, size_t bytes); +int buffer_write(struct circle_buffer *tmp, char* buffer, size_t bytes); +int getUSBCheckFlag(); +int set_android_volume_enable(int enable); +int set_android_volume(int left, int right); +int set_output_record_enable(int enable); + +#ifdef __cplusplus +} +#endif + +#endif //__TV_AML_AUDIO_H__ diff --git a/libTVaudio/audio/android_out.cpp b/libTVaudio/audio/android_out.cpp new file mode 100644 index 0000000..65922d9 --- a/dev/null +++ b/libTVaudio/audio/android_out.cpp @@ -0,0 +1,160 @@ +/* + android_out.cpp + New an audio track in android, but no data in this track. Only push FIFO pointer. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <pthread.h> +#include <cutils/log.h> + +#include <media/AudioTrack.h> + +#include "audio_usb_check.h" +#include "android_out.h" +#include "aml_audio.h" +#include "DDP_media_source.h" + +using namespace android; + +#define LOG_TAG "android_out" + +static AudioTrack *glpTracker = NULL; + +#if ANDROID_PLATFORM_SDK_VERSION >= 19 +static sp<AudioTrack> gmpAudioTracker; +#endif + +extern struct circle_buffer android_out_buffer; +extern struct circle_buffer DDP_out_buffer; +extern int output_record_enable; +extern pthread_mutex_t device_change_lock; + +int I2S_state = 0; + +static void AudioTrackCallback(int event, void* user, void *info) { + AudioTrack::Buffer *buffer = static_cast<AudioTrack::Buffer *>(info); + + if (event != AudioTrack::EVENT_MORE_DATA) { + ALOGD("%s, audio track envent = %d!\n", __FUNCTION__, event); + return; + } + if (buffer == NULL || buffer->size == 0) { + return; + } + + int bytes = 0; + + pthread_mutex_lock(&device_change_lock); + + if (GetOutputdevice() == 1) { + bytes = buffer_read(&android_out_buffer, (char *) buffer->raw, + buffer->size); + if (bytes < 0) + buffer->size = 0; + } else if (GetOutputdevice() == 2) { + bytes = buffer_read(&DDP_out_buffer, (char *) buffer->raw, + buffer->size); + if (bytes < 0) + buffer->size = 0; + } else { + if (output_record_enable == 1) { + bytes = buffer_read(&android_out_buffer, (char *) buffer->raw, + buffer->size); + if (bytes < 0) + buffer->size = 0; + } else { + memset(buffer->i16, 0, buffer->size); + } + } + + pthread_mutex_unlock(&device_change_lock); + I2S_state += 1; + return; +} + +static int AudioTrackRelease(void) { +#if ANDROID_PLATFORM_SDK_VERSION < 19 + if (glpTracker != NULL) { + glpTracker->stop(); + delete glpTracker; + glpTracker = NULL; + } +#else + if (glpTracker != NULL ) { + glpTracker->stop(); + glpTracker = NULL; + } + + if (gmpAudioTracker != NULL ) { + gmpAudioTracker.clear(); + } +#endif + return 0; +} + +static int AudioTrackInit(void) { + status_t Status; + + ALOGD("%s, entering...\n", __FUNCTION__); + + I2S_state = 0; + +#if ANDROID_PLATFORM_SDK_VERSION < 19 + glpTracker = new AudioTrack(); + if (glpTracker == NULL) { + ALOGE("%s, new AudioTrack failed.\n", __FUNCTION__); + return -1; + } +#else + gmpAudioTracker = new AudioTrack(); + if (gmpAudioTracker == NULL) { + ALOGE("%s, new AudioTrack failed.\n", __FUNCTION__); + return -1; + } + glpTracker = gmpAudioTracker.get(); +#endif + + Status = glpTracker->set(AUDIO_STREAM_MUSIC, 48000, AUDIO_FORMAT_PCM_16_BIT, + AUDIO_CHANNEL_OUT_STEREO, 0, AUDIO_OUTPUT_FLAG_NONE, + AudioTrackCallback, NULL, 0, 0, false, 0); + + if (Status != NO_ERROR) { + ALOGE("%s, AudioTrack set failed.\n", __FUNCTION__); + + AudioTrackRelease(); + return -1; + } + + Status = glpTracker->initCheck(); + if (Status != NO_ERROR) { + ALOGE("%s, AudioTrack initCheck failed.\n", __FUNCTION__); + + AudioTrackRelease(); + return -1; + } + + glpTracker->start(); + + Status = glpTracker->setVolume(1.0, 1.0); + if (Status != NO_ERROR) { + ALOGE("%s, AudioTrack setVolume failed.\n", __FUNCTION__); + + AudioTrackRelease(); + return -1; + } + + ALOGD("%s, exit...\n", __FUNCTION__); + + return 0; +} + +int new_android_audiotrack(void) { + return AudioTrackInit(); +} + +int release_android_audiotrack(void) { + return AudioTrackRelease(); +} + diff --git a/libTVaudio/audio/android_out.h b/libTVaudio/audio/android_out.h new file mode 100644 index 0000000..9deef75 --- a/dev/null +++ b/libTVaudio/audio/android_out.h @@ -0,0 +1,15 @@ +#ifndef __TV_ANDROID_OUT_H__ +#define __TV_ANDROID_OUT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int new_android_audiotrack(void); +int release_android_audiotrack(void); + +#ifdef __cplusplus +} +#endif + +#endif //__TV_ANDROID_OUT_H__ diff --git a/libTVaudio/audio/audio_amaudio.cpp b/libTVaudio/audio/audio_amaudio.cpp new file mode 100644 index 0000000..5ad5f51 --- a/dev/null +++ b/libTVaudio/audio/audio_amaudio.cpp @@ -0,0 +1,209 @@ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <signal.h> +#include <pthread.h> +#include <unistd.h> +#include <math.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <dlfcn.h> + +#include <cutils/log.h> +#include <cutils/properties.h> + +#include <tinyalsa/asoundlib.h> + +#include "audio_effect_control.h" +#include "../audio_amaudio.h" + +#define LOG_TAG "LibAudioCtl" + +int amAudioOpen(unsigned int sr, int input_device, int output_device) { + return aml_audio_open(sr, input_device, output_device); +} + +int amAudioClose(void) { + return aml_audio_close(); +} + +int amAudioSetInputSr(unsigned int sr, int input_device, int output_device) { + int tmpRet = 0; + + if (check_input_stream_sr(sr) < 0) { + ALOGE("%s, The sample rate (%u) is invalid!\n", __FUNCTION__, sr); + return -1; + } + + ALOGD("%s, sr = %d\n", __FUNCTION__, sr); + + tmpRet |= amAudioClose(); + tmpRet |= amAudioOpen(sr, input_device, output_device); + + return tmpRet; +} + +int amAudioSetOutputSr(unsigned int sr, int output_device) { + ALOGD("%s, sr = %d\n", __FUNCTION__, sr); + ALOGE("%s, amAudio not support set output sample rate\n", __FUNCTION__); + + return 0; +} + +int amAudioSetDumpDataFlag(int tmp_flag) { + return SetDumpDataFlag(tmp_flag); +} + +int amAudioGetDumpDataFlag() { + return GetDumpDataFlag(); +} + +int amAudioSetOutputMode(int mode) { + return set_output_mode(mode); +} + +int amAudioSetMusicGain(int gain) { + return set_music_gain(gain); +} + +int amAudioSetLeftGain(int gain) { + return set_left_gain(gain); +} + +int amAudioSetRightGain(int gain) { + return set_right_gain(gain); +} + +int amAudioSetAndroidVolumeEnable(int enable) { + return set_android_volume_enable(enable); +} + +int amAudioSetAndroidVolume(int left, int right) { + return set_android_volume(left, right); +} + +int amAudioSetEQGain(int gain_val_buf[], int buf_item_cnt) { + int i = 0; + int tmp_buf[6] = { 0, 0, 0, 0, 0, 0 }; + + if (buf_item_cnt > 5) { + buf_item_cnt = 5; + } + + for (i = 0; i < buf_item_cnt; i++) { + tmp_buf[i] = gain_val_buf[i]; + } + + HPEQ_setParameter(tmp_buf[0], tmp_buf[1], tmp_buf[2], tmp_buf[3], + tmp_buf[4]); + + return 0; +} + +int amAudioGetEQGain(int gain_val_buf[], int buf_item_cnt) { + int i = 0, tmp_cnt = 0; + int tmp_buf[6] = { 0, 0, 0, 0, 0, 0 }; + + HPEQ_getParameter(tmp_buf); + + tmp_cnt = buf_item_cnt; + + if (buf_item_cnt > 5) { + tmp_cnt = 5; + } + + for (i = 0; i < buf_item_cnt; i++) { + if (i < tmp_cnt) { + gain_val_buf[i] = tmp_buf[i]; + } else { + gain_val_buf[i] = 0; + } + } + + return 0; +} + +int amAudioSetEQEnable(int en_val) { + return HPEQ_enable(en_val); +} + +int amAudioGetEQEnable() { + return 0; +} + +int amAudioSetDoubleOutput(int en_val, unsigned int sr, int input_device, + int output_device) { + return amAudioSetInputSr(sr, input_device, output_device); +} + +int amAudioSetOutputRecordEnable(int enable) { + return 0; //set_output_record_enable(enable); +} + +#define CC_SET_TYPE_TRUBASS_SPEAKERSIZE (0) +#define CC_SET_TYPE_TRUBASS_GAIN (1) +#define CC_SET_TYPE_DIALOGCLARITY_GAIN (2) +#define CC_SET_TYPE_DEFINITION_GAIN (3) +#define CC_SET_TYPE_SURROUND_GAIN (4) +#define CC_SET_TYPE_MAX (CC_SET_TYPE_SURROUND_GAIN) + +static int amAudioSetSRSParameter(int set_type, int gain_val) { + int tmp_buf[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + if (srs_getParameter(tmp_buf) < 0) { + ALOGE("%s, srs_getParameter error.\n", __FUNCTION__); + return -1; + } + + if (set_type < 0 || set_type > CC_SET_TYPE_MAX) { + ALOGE("%s, not support param set type (%d).\n", __FUNCTION__, set_type); + return -1; + } + + tmp_buf[set_type] = gain_val; + + return srs_setParameter(tmp_buf); +} + +int amAudioSetSRSSurroundSwitch(int switch_val) { + return srs_surround_enable(switch_val); +} + +int amAudioSetSRSSurroundGain(int gain_val) { + return amAudioSetSRSParameter(CC_SET_TYPE_SURROUND_GAIN, gain_val); +} + +int amAudioSetSRSTrubassSwitch(int switch_val) { + return srs_truebass_enable(switch_val); +} + +int amAudioSetSRSTrubassGain(int gain_val) { + return amAudioSetSRSParameter(CC_SET_TYPE_TRUBASS_GAIN, gain_val); +} + +int amAudioSetSRSDialogClaritySwitch(int switch_val) { + return srs_dialogclarity_enable(switch_val); +} + +int amAudioSetSRSDialogClarityGain(int gain_val) { + return amAudioSetSRSParameter(CC_SET_TYPE_DIALOGCLARITY_GAIN, gain_val); +} + +int amAudioSetSRSDefinitionGain(int gain_val) { + return amAudioSetSRSParameter(CC_SET_TYPE_DEFINITION_GAIN, gain_val); +} + +int amAudioSetSRSTrubassSpeakerSize(int tmp_val) { + int tmp_buf[8] = { 40, 60, 100, 150, 200, 250, 300, 400 }; + int gain_val = 40; + + if (tmp_val >= 0 && tmp_val < (int) sizeof(tmp_buf)) { + gain_val = tmp_buf[tmp_val]; + } + + return amAudioSetSRSParameter(CC_SET_TYPE_TRUBASS_SPEAKERSIZE, gain_val); +} diff --git a/libTVaudio/audio/audio_effect_control.c b/libTVaudio/audio/audio_effect_control.c new file mode 100644 index 0000000..02247b1 --- a/dev/null +++ b/libTVaudio/audio/audio_effect_control.c @@ -0,0 +1,423 @@ +/* + audio_effect_control.c + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <dlfcn.h> + +#include <cutils/log.h> + +#include "aml_audio.h" +#include "audio_effect_control.h" + +#define LOG_TAG "audioeffect" + +//------------------------------------EQ control------------------------------------------------ +int (*EQ_process)(short *in, short *out, int framecount); +int (*EQ_init)(void); +int (*EQ_setParameter)(int band1, int band2, int band3, int band4, int band5); +int (*EQ_getParameter)(int *band1, int *band2, int *band3, int *band4, + int *band5); +int (*EQ_enable)(bool enable); +int (*EQ_release)(void); + +static void *gEQLibHandler = NULL; + +int unload_EQ_lib(void) { + ALOGD("%s, entering...\n", __FUNCTION__); + + HPEQ_release(); + + EQ_process = NULL; + EQ_init = NULL; + EQ_setParameter = NULL; + EQ_getParameter = NULL; + EQ_enable = NULL; + EQ_release = NULL; + + if (gEQLibHandler != NULL) { + dlclose(gEQLibHandler); + gEQLibHandler = NULL; + } + + return 0; +} + +int load_EQ_lib(void) { + char *error; + + unload_EQ_lib(); + + ALOGD("%s, entering...\n", __FUNCTION__); + + gEQLibHandler = dlopen("/system/lib/soundfx/libhpeq.so", RTLD_NOW); + if (!gEQLibHandler) { + ALOGE("%s, failed to load EQ lib (libhpeq.so)\n", __FUNCTION__); + goto Error; + } + + EQ_release = (int (*)(void))dlsym(gEQLibHandler, "HPEQ_release_api"); + if (EQ_release == NULL) { + ALOGE("%s, fail find fun HPEQ_release_api()\n", __FUNCTION__); + goto Error; + } + EQ_process = (int (*)(short*, short*, + int))dlsym(gEQLibHandler, "HPEQ_process_api"); + if (EQ_process == NULL) { + ALOGE("%s, fail find fun HPEQ_process_api()\n", __FUNCTION__); + goto Error; + } + EQ_init = (int (*)(void))dlsym(gEQLibHandler, "HPEQ_init_api"); + if (EQ_init == NULL) { + ALOGE("%s, fail find fun HPEQ_init_api()\n", __FUNCTION__); + goto Error; + } + EQ_setParameter = (int (*)(int, int, int, int, + int))dlsym(gEQLibHandler, "HPEQ_setParameter_api"); + if (EQ_setParameter == NULL) { + ALOGE("%s, fail find fun HPEQ_setParameter_api\n", __FUNCTION__); + goto Error; + } + EQ_getParameter = (int (*)(int*, int*, int*, int*, + int*))dlsym(gEQLibHandler, "HPEQ_getParameter_api"); + if (EQ_getParameter == NULL) { + ALOGE("%s, fail find fun HPEQ_getParameter_api()\n", __FUNCTION__); + goto Error; + } + EQ_enable = (int (*)(bool))dlsym(gEQLibHandler, "HPEQ_enable_api"); + if (EQ_enable == NULL) { + ALOGE("%s, fail find fun HPEQ_enable_api()\n", __FUNCTION__); + goto Error; + } + + return 0; + + Error: // + unload_EQ_lib(); + return -1; +} + +int HPEQ_process(short *in, short *out, int framecount) { + int ret = 0; + + if (EQ_process == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*EQ_process)(in, out, framecount); + + return ret; +} + +int HPEQ_init(void) { + int ret = 0; + + if (EQ_init == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*EQ_init)(); + + return ret; +} + +int HPEQ_setParameter(int band1, int band2, int band3, int band4, int band5) { + int ret = 0; + + if (EQ_setParameter == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*EQ_setParameter)(band1, band2, band3, band4, band5); + + return ret; +} +int HPEQ_getParameter(int EQ_user_config[]) { + int ret = 0; + + if (EQ_getParameter == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + (*EQ_getParameter)(&EQ_user_config[0], &EQ_user_config[1], + &EQ_user_config[2], &EQ_user_config[3], &EQ_user_config[4]); + + return 0; +} + +int HPEQ_enable(bool enable) { + int ret = 0; + + if (EQ_enable == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*EQ_enable)(enable); + + return ret; +} + +int HPEQ_release(void) { + int ret = 0; + + if (EQ_release == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*EQ_release)(); + + return ret; +} + +//-------------------------SRS control--------------------------------------------------------- +int (*SRS_init)(int sample_rate); +int (*SRS_release)(void); +int (*SRS_setParameter)(int truebass_spker_size, float truebass_gain, + float dialogclarity_gain, float definition_gain, float surround_gain); +int (*SRS_getParameter)(int *truebass_spker_size, float *truebass_gain, + float *dialogclarity_gain, float *definition_gain, + float *surround_gain); +int (*SRS_TRUEBASS_ENABLE)(int value); +int (*SRS_DIALOGCLARITY_ENABLE)(int value); +int (*SRS_SURROUND_ENABLE)(int value); +int (*SRS_process)(short *in, short *out, int framecount); + +static void *gSRSLibHandler = NULL; + +int unload_SRS_lib(void) { + ALOGD("%s, entering...\n", __FUNCTION__); + + srs_release(); + + SRS_release = NULL; + SRS_process = NULL; + SRS_init = NULL; + SRS_setParameter = NULL; + SRS_getParameter = NULL; + SRS_TRUEBASS_ENABLE = NULL; + SRS_DIALOGCLARITY_ENABLE = NULL; + SRS_SURROUND_ENABLE = NULL; + + if (gSRSLibHandler != NULL) { + dlclose(gSRSLibHandler); + gSRSLibHandler = NULL; + } + + return 0; +} + +int load_SRS_lib(void) { + char *error; + + unload_SRS_lib(); + + ALOGD("%s, entering...\n", __FUNCTION__); + + gSRSLibHandler = dlopen("/system/lib/soundfx/libsrs.so", RTLD_NOW); + if (!gSRSLibHandler) { + ALOGE("%s, failed to load SRS lib (libsrs.so)\n", __FUNCTION__); + goto Error; + } + + SRS_release = (int (*)(void))dlsym(gSRSLibHandler, "SRS_release_api"); + if (SRS_release == NULL) { + ALOGE("%s, fail find fun SRS_release_api()\n", __FUNCTION__); + goto Error; + } + SRS_process = (int (*)(short*, short*, + int))dlsym(gSRSLibHandler, "SRS_process_api"); + if (SRS_process == NULL) { + ALOGE("%s, fail find fun SRS_process_api()\n", __FUNCTION__); + goto Error; + } + SRS_init = (int (*)(int))dlsym(gSRSLibHandler, "SRS_init_api"); + if (SRS_init == NULL) { + ALOGE("%s, fail find fun SRS_init_api()\n", __FUNCTION__); + goto Error; + } + SRS_setParameter = (int (*)(int, float, float, float, + float))dlsym(gSRSLibHandler, "SRS_setParameter_api"); + if (SRS_setParameter == NULL) { + ALOGE("%s, fail find fun SRS_setParameter_api()\n", __FUNCTION__); + goto Error; + } + SRS_getParameter = (int (*)(int*, float*, float*, float*, + float*))dlsym(gSRSLibHandler, "SRS_getParameter_api"); + if (SRS_getParameter == NULL) { + ALOGE("%s, fail find fun SRS_getParameter_api()\n", __FUNCTION__); + goto Error; + } + SRS_TRUEBASS_ENABLE = (int (*)( + int))dlsym(gSRSLibHandler, "SRS_TRUEBASS_ENABLE_api"); + if (SRS_TRUEBASS_ENABLE == NULL) { + ALOGE("%s, fail find fun SRS_TRUEBASS_ENABLE_api()\n", __FUNCTION__); + goto Error; + } + SRS_DIALOGCLARITY_ENABLE = (int (*)( + int))dlsym(gSRSLibHandler, "SRS_DIALOGCLARITY_ENABLE_api"); + if (SRS_DIALOGCLARITY_ENABLE == NULL) { + ALOGE("%s, fail find fun SRS_DIALOGCLARITY_ENABLE_api\n", __FUNCTION__); + goto Error; + } + SRS_SURROUND_ENABLE = (int (*)( + int))dlsym(gSRSLibHandler, "SRS_SURROUND_ENABLE_api"); + if (SRS_SURROUND_ENABLE == NULL) { + ALOGE("%s, fail find fun SRS_SURROUND_ENABLE_api\n", __FUNCTION__); + goto Error; + } + + return 0; + + Error: // + unload_SRS_lib(); + return -1; +} + +int srs_init(int sample_rate) { + int ret = 0; + + if (SRS_init == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*SRS_init)(sample_rate); + + return ret; +} + +int srs_release(void) { + int ret = 0; + + if (SRS_release == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*SRS_release)(); + + return ret; +} + +int srs_setParameter(int SRS_user_config[]) { + int ret = 0; + int truebass_spker_size; + float truebass_gain; + float dialogclarity_gain; + float definition_gain; + float surround_gain; + + if (SRS_setParameter == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + if (SRS_user_config == NULL) { + ALOGE("%s, SRS_user_config buf pointer is NULL.\n", __FUNCTION__); + return -1; + } + + truebass_spker_size = SRS_user_config[0]; + truebass_gain = (float) SRS_user_config[1] / (float) 100; + dialogclarity_gain = (float) SRS_user_config[1] / (float) 100; + definition_gain = (float) SRS_user_config[1] / (float) 100; + surround_gain = (float) SRS_user_config[1] / (float) 100; + + ret = (*SRS_setParameter)(truebass_spker_size, truebass_gain, + dialogclarity_gain, definition_gain, surround_gain); + + return ret; +} + +int srs_getParameter(int SRS_user_config[]) { + int ret = 0; + int truebass_spker_size; + float truebass_gain; + float dialogclarity_gain; + float definition_gain; + float surround_gain; + + if (SRS_getParameter == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + if (SRS_user_config == NULL) { + ALOGE("%s, SRS_user_config buf pointer is NULL.\n", __FUNCTION__); + return -1; + } + + ret = (*SRS_getParameter)(&truebass_spker_size, &truebass_gain, + &dialogclarity_gain, &definition_gain, &surround_gain); + + SRS_user_config[0] = truebass_spker_size; + SRS_user_config[1] = (int) (truebass_gain * 100); + SRS_user_config[2] = (int) (dialogclarity_gain * 100); + SRS_user_config[3] = (int) (definition_gain * 100); + SRS_user_config[4] = (int) (surround_gain * 100); + + return 0; +} + +int srs_truebass_enable(int enable) { + int ret = 0; + + if (SRS_TRUEBASS_ENABLE == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*SRS_TRUEBASS_ENABLE)(enable); + + return ret; +} + +int srs_dialogclarity_enable(int enable) { + int ret = 0; + + if (SRS_DIALOGCLARITY_ENABLE == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*SRS_DIALOGCLARITY_ENABLE)(enable); + + return ret; +} + +int srs_surround_enable(int enable) { + int ret = 0; + + if (SRS_SURROUND_ENABLE == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + ret = (*SRS_SURROUND_ENABLE)(enable); + + return ret; +} + +int srs_process(short *in, short *out, int framecount) { + int output_framecount = 0; + + //In SRS prosess, framecount must be aligned by 64. + int input_framecount = framecount >> 6 << 6; + + if (SRS_process == NULL) { + ALOGE("%s, pls load lib first.\n", __FUNCTION__); + return -1; + } + + output_framecount = (*SRS_process)(in, out, input_framecount); + + return output_framecount << 2; +} diff --git a/libTVaudio/audio/audio_effect_control.h b/libTVaudio/audio/audio_effect_control.h new file mode 100644 index 0000000..4e2cc7c --- a/dev/null +++ b/libTVaudio/audio/audio_effect_control.h @@ -0,0 +1,48 @@ +#ifndef __TV_AUDIO_EFFECT_CONTROL_H__ +#define __TV_AUDIO_EFFECT_CONTROL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + When aml audio system is open, EQ is init, but not enable. Set EQ band value first, then enable it. + EQ has 5 bands, the gains are from -12dB to 12dB. When EQ is enabled, the main volume is 6 dB lowered. + */ + +int unload_EQ_lib(void); +int load_EQ_lib(void); +int HPEQ_process(short *in, short *out, int framecount); +int HPEQ_init(void); +int HPEQ_setParameter(int band1, int band2, int band3, int band4, int band5); +int HPEQ_getParameter(int EQ_user_config[]); +int HPEQ_enable(bool enable); +int HPEQ_release(void); + +/* + When aml audio system is open, SRS is init, but not enable. Set SRS parameters as default value. + truebass_spker_size = 2 (40, 60, 100, 150, 200, 250, 300, 400)Hz + truebass_gain = 0.3 (0.0~1.0) + dialogclarity_gain = 0.2 (0.0~1.0) + definition_gain = 0.3 (0.0~1.0) + surround_gain = 0.5 (0.0~1.0) + When set srs_truebass_enable(1), srs works in default value. You can set other values before enable. + SRS works only when framecount is aligned by 64, else it will make noise. + */ + +int unload_SRS_lib(void); +int load_SRS_lib(void); +int srs_init(int sample_rate); +int srs_release(void); +int srs_setParameter(int SRS_user_config[]); +int srs_getParameter(int SRS_user_config[]); +int srs_truebass_enable(int enable); +int srs_dialogclarity_enable(int enable); +int srs_surround_enable(int enable); +int srs_process(short *in, short *out, int framecount); + +#ifdef __cplusplus +} +#endif + +#endif //__TV_AUDIO_EFFECT_CONTROL_H__ diff --git a/libTVaudio/audio/audio_usb_check.cpp b/libTVaudio/audio/audio_usb_check.cpp new file mode 100644 index 0000000..2cbcc28 --- a/dev/null +++ b/libTVaudio/audio/audio_usb_check.cpp @@ -0,0 +1,29 @@ +/* + audio_usb_check.cpp + check usb audio device. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <cutils/log.h> +#include <media/AudioSystem.h> + +#include "audio_usb_check.h" + +#define LOG_TAG "audio_usb_check" + +namespace android { + +extern "C" int GetUsbAudioCheckFlag() { + int device = (int)AudioSystem::getDevicesForStream(AUDIO_STREAM_MUSIC); + return device; +} + +} + +int createMonitorUsbHostBusThread() { + return 0; +} + diff --git a/libTVaudio/audio/audio_usb_check.h b/libTVaudio/audio/audio_usb_check.h new file mode 100644 index 0000000..8116c13 --- a/dev/null +++ b/libTVaudio/audio/audio_usb_check.h @@ -0,0 +1,18 @@ +#ifndef __TV_USB_AUDIO_CHECK_H__ +#define __TV_USB_AUDIO_CHECK_H__ + +#define CC_USB_AUDIO_PLAYBACK_BIT_IND (0) +#define CC_USB_AUDIO_CAPTURE_BIT_IND (1) + +#ifdef __cplusplus +extern "C" { +#endif + +int createMonitorUsbHostBusThread(); +int GetUsbAudioCheckFlag(); + +#ifdef __cplusplus +} +#endif + +#endif //__TV_USB_AUDIO_CHECK_H__ diff --git a/libTVaudio/audio_amaudio.h b/libTVaudio/audio_amaudio.h new file mode 100644 index 0000000..eafaf88 --- a/dev/null +++ b/libTVaudio/audio_amaudio.h @@ -0,0 +1,38 @@ +#ifndef __TV_AUDIO_AMAUDIO_H__ +#define __TV_AUDIO_AMAUDIO_H__ + +#include "audio/aml_audio.h" +#include "audio/audio_usb_check.h" + +int amAudioOpen(unsigned int sr, int input_device, int output_device); +int amAudioClose(void); +int amAudioSetInputSr(unsigned int sr, int input_device, int output_device); +int amAudioSetOutputSr(unsigned int sr, int output_device); +int amAudioSetDumpDataFlag(int tmp_flag); +int amAudioGetDumpDataFlag(); + +int amAudioSetOutputMode(int mode); +int amAudioSetMusicGain(int gain); +int amAudioSetLeftGain(int gain); +int amAudioSetRightGain(int gain); +int amAudioSetAndroidVolumeEnable(int enable); +int amAudioSetAndroidVolume(int left, int right); +int amAudioSetOutputRecordEnable(int enable); +int amAudioSetDoubleOutput(int en_val, unsigned int sr, int input_device, + int output_device); + +int amAudioSetEQGain(int gain_val_buf[], int buf_item_cnt); +int amAudioGetEQGain(int gain_val_buf[], int buf_item_cnt); +int amAudioSetEQEnable(int en_val); +int amAudioGetEQEnable(); + +int amAudioSetSRSSurroundSwitch(int switch_val); +int amAudioSetSRSSurroundGain(int gain_val); +int amAudioSetSRSTrubassSwitch(int switch_val); +int amAudioSetSRSTrubassGain(int gain_val); +int amAudioSetSRSDialogClaritySwitch(int switch_val); +int amAudioSetSRSDialogClarityGain(int gain_val); +int amAudioSetSRSDefinitionGain(int gain_val); +int amAudioSetSRSTrubassSpeakerSize(int tmp_val); + +#endif //__TV_AUDIO_AMAUDIO_H__ |