From 839418c0eb455971b9bb2ed07eb4aea5b9ecfbfd Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 3 Aug 2017 19:16:05 +0900 Subject: [PATCH] Merge from mobile product code for backward compatibility (common) - seperate cond wait mutex - reject read on interrupted situtation - no auto-resume by audio-io - async send interrupt completed event using g_idle_add() (except TV product) - seperate async playback latency managment - start stream as corked - dummy write on start [Version] 0.3.81 [Issue Type] Compatibility Change-Id: Ie55c7c723433db0c607e08319a09429d163c6b78 --- CMakeLists.txt | 4 ++ include/CAudioIO.h | 4 ++ include/CPulseStreamSpec.h | 1 + packaging/capi-media-audio-io.spec | 5 +- src/cpp/CAudioIO.cpp | 117 +++++++++++++++++++++++++------------ src/cpp/CAudioInput.cpp | 14 ++++- src/cpp/CAudioOutput.cpp | 37 ++++++++++-- src/cpp/CAudioSessionHandler.cpp | 2 + src/cpp/CPulseAudioClient.cpp | 39 ++++++++++++- src/cpp/CPulseStreamSpec.cpp | 10 ++++ 10 files changed, 185 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dcb532..b9999e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,10 @@ IF(TIZEN_FEATURE_DISABLE_SESSION_BACKWARD_COMP) ADD_DEFINITIONS("-DDISABLE_SESSION_BACK_COMP") ENDIF(TIZEN_FEATURE_DISABLE_SESSION_BACKWARD_COMP) +IF(TIZEN_FEATURE_PRODUCT_TV) + ADD_DEFINITIONS("-DDISABLE_MOBILE_BACK_COMP") +ENDIF(TIZEN_FEATURE_PRODUCT_TV) + SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") aux_source_directory(src/cpp CPPSOURCES) diff --git a/include/CAudioIO.h b/include/CAudioIO.h index abfa359..3d48f23 100644 --- a/include/CAudioIO.h +++ b/include/CAudioIO.h @@ -101,6 +101,7 @@ namespace tizen_media_audio { void setStreamInfo(sound_stream_info_h stream_info); void setInternalStreamInfo(); /* this is for session backward compatibility and will be removed later */ + static int sendInterrupt(void* user_data); CAudioInfo::EAudioIOState getState(); @@ -124,14 +125,17 @@ namespace tizen_media_audio { SStreamCallback mStreamCallback; SStateChangedCallback mStateChangedCallback; SInterruptCallback mInterruptCallback; + IAudioSessionEventListener::EInterruptCode mInterruptCode; CAudioInfo::EAudioDirection mDirection; CAudioInfo::EAudioIOState mState; CAudioInfo::EAudioIOState mStatePrev; bool mByPolicy; + bool mIsInterrupted; private: pthread_mutex_t __mMutex; + pthread_mutex_t __mCondMutex; pthread_cond_t __mCond; bool __mIsInit; bool __mForceIgnore; diff --git a/include/CPulseStreamSpec.h b/include/CPulseStreamSpec.h index 16a29f7..416884f 100644 --- a/include/CPulseStreamSpec.h +++ b/include/CPulseStreamSpec.h @@ -44,6 +44,7 @@ namespace tizen_media_audio { STREAM_LATENCY_OUTPUT_HIGH, STREAM_LATENCY_OUTPUT_VOIP, STREAM_LATENCY_OUTPUT_DEFAULT, + STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC, STREAM_LATENCY_MAX }; diff --git a/packaging/capi-media-audio-io.spec b/packaging/capi-media-audio-io.spec index ef8818c..6e20ddf 100644 --- a/packaging/capi-media-audio-io.spec +++ b/packaging/capi-media-audio-io.spec @@ -1,6 +1,6 @@ Name: capi-media-audio-io Summary: An Audio Input & Audio Output library in Tizen Native API -Version: 0.3.80 +Version: 0.3.81 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -36,7 +36,8 @@ cp %{SOURCE1001} . MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` %cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \ %if "%{TIZEN_PRODUCT_TV}" == "1" - -DTIZEN_FEATURE_DISABLE_SESSION_BACKWARD_COMP=On + -DTIZEN_FEATURE_DISABLE_SESSION_BACKWARD_COMP=On \ + -DTIZEN_FEATURE_PRODUCT_TV=On %endif make %{?jobs:-j%jobs} diff --git a/src/cpp/CAudioIO.cpp b/src/cpp/CAudioIO.cpp index d543219..b98c2f9 100644 --- a/src/cpp/CAudioIO.cpp +++ b/src/cpp/CAudioIO.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "CAudioIODef.h" using namespace std; @@ -31,27 +32,34 @@ CAudioIO::CAudioIO() : mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL), __mMutex(PTHREAD_MUTEX_INITIALIZER), + __mCondMutex(PTHREAD_MUTEX_INITIALIZER), __mCond(PTHREAD_COND_INITIALIZER), __mIsInit(false), __mForceIgnore(false) { + mInterruptCode = IAudioSessionEventListener::EInterruptCode::INTERRUPT_MAX; mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX; mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE; mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE; mByPolicy = false; + mIsInterrupted = false; + } CAudioIO::CAudioIO(CAudioInfo& audioInfo) : mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL), __mMutex(PTHREAD_MUTEX_INITIALIZER), + __mCondMutex(PTHREAD_MUTEX_INITIALIZER), __mCond(PTHREAD_COND_INITIALIZER), __mIsInit(false), __mForceIgnore(false) { mAudioInfo = audioInfo; + mInterruptCode = IAudioSessionEventListener::EInterruptCode::INTERRUPT_MAX; mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX; mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE; mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE; mByPolicy = false; + mIsInterrupted = false; } CAudioIO::~CAudioIO() { @@ -77,8 +85,9 @@ void CAudioIO::internalLock() { if (pthread_mutex_lock(&__mMutex) != 0) { THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); } + #ifdef _AUDIO_IO_DEBUG_TIMING_ - AUDIO_IO_LOGD(COLOR_RED "LOCK" COLOR_END); + AUDIO_IO_LOGD(COLOR_RED "%p LOCKED" COLOR_END, &__mMutex); #endif } @@ -91,7 +100,7 @@ void CAudioIO::internalUnlock() { THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); } #ifdef _AUDIO_IO_DEBUG_TIMING_ - AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK" COLOR_END); + AUDIO_IO_LOGD(COLOR_GREEN "%p UNLOCKED" COLOR_END, &__mMutex); #endif } @@ -104,7 +113,9 @@ void CAudioIO::internalWait() { AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END); #endif - pthread_cond_wait(&__mCond, &__mMutex); + pthread_mutex_lock(&__mCondMutex); + pthread_cond_wait(&__mCond, &__mCondMutex); + pthread_mutex_unlock(&__mCondMutex); } void CAudioIO::internalSignal() { @@ -116,7 +127,9 @@ void CAudioIO::internalSignal() { AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END); #endif + pthread_mutex_lock(&__mCondMutex); pthread_cond_signal(&__mCond); + pthread_mutex_unlock(&__mCondMutex); } bool CAudioIO::isForceIgnore() { @@ -150,16 +163,29 @@ void CAudioIO::finalize() { AUDIO_IO_LOGD("finalize"); + bool error_occured = false; int ret = pthread_mutex_destroy(&__mMutex); if (ret != 0) { - THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret); + AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mMutex, ret); + error_occured = true; + + } + ret = pthread_mutex_destroy(&__mCondMutex); + if (ret != 0) { + AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mCondMutex, ret); + error_occured = true; } + ret = pthread_cond_destroy(&__mCond); if (ret != 0) { - THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret); + AUDIO_IO_LOGE("Failed pthread_cond_destroy(%p) errno:%d", &__mCond, ret); + error_occured = true; } + if (error_occured) + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Finalize Failed"); + __mIsInit = false; } @@ -210,7 +236,23 @@ CAudioInfo::EAudioIOState CAudioIO::getState() { return mState; } -void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) { +int CAudioIO::sendInterrupt(void* user_data) { + CAudioIO *pCaudioIo = (CAudioIO *)user_data; + + if (pCaudioIo && pCaudioIo->mInterruptCallback.onInterrupt) { + AUDIO_IO_LOGD("sending interrupt [%d]", pCaudioIo->mInterruptCode); + pCaudioIo->mInterruptCallback.onInterrupt(pCaudioIo->mInterruptCode, pCaudioIo->mInterruptCallback.mUserData); + } + return 0; +} + +int caudio_gsource_callback(void *user_data) { + CAudioIO::sendInterrupt(user_data); + return 0; +} + +void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, + mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) { assert(pHandler); int session_option = pHandler->getOptions(); @@ -226,30 +268,16 @@ void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focu } if (state == FOCUS_IS_RELEASED) { - // Focus handle(id) of the other application was released, do resume if possible - internalLock(); - if (mpPulseAudioClient) { - mpPulseAudioClient->cork(false); - onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING); - } - internalUnlock(); - + // Focus handle(id) of the other application was released, notify resume // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience state = FOCUS_IS_ACQUIRED; } else if (state == FOCUS_IS_ACQUIRED) { // Focus handle(id) of the other application was acquired, do pause if possible internalLock(); if (mpPulseAudioClient) { - /* FIXME: Skip this codes due to the blocking of drain() function - if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) { - if (mpPulseAudioClient->drain() == false) { - AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()"); - } - } - */ mpPulseAudioClient->cork(true); - onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED); } + mIsInterrupted = true; internalUnlock(); // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience @@ -273,34 +301,28 @@ void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focu // Focus handle(id) was released, do pause here internalLock(); if (mpPulseAudioClient) { - /* FIXME: Skip this codes due to the blocking of drain() function - if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) { - if (mpPulseAudioClient->drain() == false) { - AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()"); - } - } - */ mpPulseAudioClient->cork(true); - onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED); } + + mIsInterrupted = true; internalUnlock(); } else if (state == FOCUS_IS_ACQUIRED) { // Focus handle(id) was acquired again, // check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...) // do resume here and call interrupt completed callback to application. - internalLock(); - if (mpPulseAudioClient) { - mpPulseAudioClient->cork(false); - onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING); - } - internalUnlock(); } } if (mInterruptCallback.onInterrupt != NULL) { IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::EInterruptCode::INTERRUPT_COMPLETED; e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change); - mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData); + + if (EInterruptCode::INTERRUPT_COMPLETED == e) { + mInterruptCode = e; + g_idle_add(caudio_gsource_callback, this); + } else { + mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData); + } } } @@ -322,8 +344,27 @@ void CAudioIO::prepare() { if (__mIsInit == false) { THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); } - + if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN) { + AUDIO_IO_LOGD("Prepare for Audio in"); + } else if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_OUT) { + AUDIO_IO_LOGD("Prepare for Audio Out"); + } try { + if (mIsInterrupted) { + AUDIO_IO_LOGE("This is preparing during interrupted!!!"); + bool isSkip = mpAudioSessionHandler->isSkipSession(); + if (__mForceIgnore == false && isSkip == false && mpAudioSessionHandler->getId() >= 0) { + AUDIO_IO_LOGE("Session updatePlaying!!!"); + mpAudioSessionHandler->updatePlaying(); + } + + if (mpPulseAudioClient && mpPulseAudioClient->isCorked()) { + AUDIO_IO_LOGE("Uncork!"); + mpPulseAudioClient->cork(false); + } + mIsInterrupted = false; + } + AUDIO_IO_LOGD("------> prepare done"); /* Do nothing */ } catch (CAudioError& e) { diff --git a/src/cpp/CAudioInput.cpp b/src/cpp/CAudioInput.cpp index 3aea844..93a58da 100644 --- a/src/cpp/CAudioInput.cpp +++ b/src/cpp/CAudioInput.cpp @@ -251,6 +251,7 @@ void CAudioInput::prepare() { if (__IsReady() == true) { AUDIO_IO_LOGD("Already prepared CAudioInput"); + CAudioIO::prepare(); return; } @@ -289,11 +290,18 @@ void CAudioInput::prepare() { if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) mpAudioSessionHandler->updatePlaying(); +#ifndef DISABLE_MOBILE_BACK_COMP + // Uncork stream which is created with CORKED flag */ + mpPulseAudioClient->cork(false); +#endif + internalUnlock(); // Do Prepare CAudioIO::prepare(); } catch (CAudioError& e) { + SAFE_FINALIZE(mpPulseAudioClient); + SAFE_DELETE(mpPulseAudioClient); internalUnlock(); throw; } catch (const std::bad_alloc&) { @@ -326,9 +334,6 @@ void CAudioInput::unprepare() { if (mpAudioSessionHandler->getId() >= 0) { if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) mpAudioSessionHandler->updateStop(); - - if (mpAudioSessionHandler->isSkipSession() == false) - mpAudioSessionHandler->unregisterSound(); } CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE); @@ -469,6 +474,9 @@ size_t CAudioInput::read(void* buffer, size_t length) { try { internalLock(); + if (mIsInterrupted) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_POLICY_BLOCKED, "audio-io is interrupted"); + } // If another thread did call unprepare, do not read if (mpPulseAudioClient == NULL) diff --git a/src/cpp/CAudioOutput.cpp b/src/cpp/CAudioOutput.cpp index b54c0db..6760f2e 100644 --- a/src/cpp/CAudioOutput.cpp +++ b/src/cpp/CAudioOutput.cpp @@ -143,6 +143,7 @@ void CAudioOutput::prepare() { if (__IsReady() == true) { AUDIO_IO_LOGD("Already prepared CAudioOutput"); + CAudioIO::prepare(); return; } @@ -167,8 +168,16 @@ void CAudioOutput::prepare() { CAudioIO::setInternalStreamInfo(); // Init StreamSpec - AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT"); CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT; +#ifndef DISABLE_MOBILE_BACK_COMP + if (!mStreamCallback.onStream) { + AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT"); + streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT; + } else { + AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC"); + streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC; + } +#endif CPulseStreamSpec spec(streamSpec, mAudioInfo); // Create PulseAudio Handler @@ -180,10 +189,16 @@ void CAudioOutput::prepare() { if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) mpAudioSessionHandler->updatePlaying(); +#ifndef DISABLE_MOBILE_BACK_COMP + // Uncork stream which is created with CORKED flag */ + mpPulseAudioClient->cork(false); +#endif internalUnlock(); CAudioIO::prepare(); } catch (CAudioError& e) { + SAFE_FINALIZE(mpPulseAudioClient); + SAFE_DELETE(mpPulseAudioClient); internalUnlock(); throw; } catch (const std::bad_alloc&) { @@ -204,6 +219,14 @@ void CAudioOutput::unprepare() { } try { + if (mpAudioSessionHandler->getId() >= 0 && !mIsInterrupted) { + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) { + CPulseStreamSpec::EStreamLatency streamSpec; + streamSpec = mpPulseAudioClient->getStreamSpec().getStreamLatency(); + if (CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC != streamSpec) + CAudioIO::drain(); + } + } CAudioIO::unprepare(); internalLock(); @@ -216,9 +239,6 @@ void CAudioOutput::unprepare() { if (mpAudioSessionHandler->getId() >= 0) { if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) mpAudioSessionHandler->updateStop(); - - if (mpAudioSessionHandler->isSkipSession() == false) - mpAudioSessionHandler->unregisterSound(); } CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE); @@ -294,11 +314,17 @@ void CAudioOutput::resume() { } void CAudioOutput::drain() { + CPulseStreamSpec::EStreamLatency streamSpec; + if (__IsInit() == false || __IsReady() == false) { THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); } + streamSpec = mpPulseAudioClient->getStreamSpec().getStreamLatency(); + if (CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC == streamSpec) + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "async type don't support drain"); + try { CAudioIO::drain(); } catch (CAudioError& e) { @@ -362,6 +388,9 @@ size_t CAudioOutput::write(const void* buffer, size_t length) { try { /* For synchronization */ internalLock(); + if (mIsInterrupted) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_POLICY_BLOCKED, "audio io is interrupted"); + } // If another thread did call unprepare, do not write if (mpPulseAudioClient == NULL) diff --git a/src/cpp/CAudioSessionHandler.cpp b/src/cpp/CAudioSessionHandler.cpp index 51f9a4b..f56d73e 100644 --- a/src/cpp/CAudioSessionHandler.cpp +++ b/src/cpp/CAudioSessionHandler.cpp @@ -303,6 +303,8 @@ void CAudioSessionHandler::finalize() { __pcmCaptureCountDec(); } + unregisterSound(); + if (__mSubscribeId > 0) { AUDIO_IO_LOGD("Unsubscribed mm_sound signal [id:%d]", __mSubscribeId); mm_sound_unsubscribe_signal(__mSubscribeId); diff --git a/src/cpp/CPulseAudioClient.cpp b/src/cpp/CPulseAudioClient.cpp index 1ac1c0d..50ce02e 100644 --- a/src/cpp/CPulseAudioClient.cpp +++ b/src/cpp/CPulseAudioClient.cpp @@ -164,6 +164,15 @@ void CPulseAudioClient::__streamCaptureCb(pa_stream* s, size_t length, void* use pClient->__mpListener->onStream(pClient, length); } +#ifndef DISABLE_MOBILE_BACK_COMP +static void __dummy_write(pa_stream* s, size_t length) { + char* dummy = new char[length]; + memset(dummy, 0, length); + pa_stream_write(s, dummy, length, NULL, 0LL, PA_SEEK_RELATIVE); + delete [] dummy; +} +#endif + void CPulseAudioClient::__streamPlaybackCb(pa_stream* s, size_t length, void* user_data) { assert(s); assert(user_data); @@ -171,6 +180,19 @@ void CPulseAudioClient::__streamPlaybackCb(pa_stream* s, size_t length, void* us CPulseAudioClient* pClient = static_cast(user_data); assert(pClient->__mpListener); +#ifndef DISABLE_MOBILE_BACK_COMP + if (pClient->__mIsInit == false) { + AUDIO_IO_LOGD("Occurred this listener when an out stream is on the way to create : Write dummy, length[%d]", length); + __dummy_write(s, length); + return; + } + if (pClient->isCorked()) { + AUDIO_IO_LOGD("Occurred this listener when an out stream is CORKED : Write dummy, length[%d]", length); + __dummy_write(s, length); + return; + } +#endif + pClient->__mpListener->onStream(pClient, length); /* If stream is not written in first callback during prepare, @@ -345,6 +367,9 @@ void CPulseAudioClient::initialize() { pa_stream_flags_t flags = static_cast( PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | +#ifndef DISABLE_MOBILE_BACK_COMP + PA_STREAM_START_CORKED | +#endif PA_STREAM_AUTO_TIMING_UPDATE); ret = pa_stream_connect_playback(__mpStream, NULL, NULL, flags, NULL, NULL); @@ -352,6 +377,9 @@ void CPulseAudioClient::initialize() { pa_stream_flags_t flags = static_cast( PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | +#ifndef DISABLE_MOBILE_BACK_COMP + PA_STREAM_START_CORKED | +#endif PA_STREAM_AUTO_TIMING_UPDATE); ret = pa_stream_connect_record(__mpStream, NULL, NULL, flags); @@ -712,7 +740,9 @@ bool CPulseAudioClient::isCorked() { isCork = pa_stream_is_corked(__mpStream); } +#ifdef _AUDIO_IO_DEBUG_TIMING_ AUDIO_IO_LOGD("isCork[%d]", isCork); +#endif return static_cast(isCork); } @@ -723,8 +753,15 @@ bool CPulseAudioClient::drain() { checkRunningState(); - if (__mIsDraining) + if (isCorked()) { + AUDIO_IO_LOGW("Corked..."); + return true; + } + + if (__mIsDraining) { AUDIO_IO_LOGW("already draining..."); + return true; + } if (isInThread() == false) { AUDIO_IO_LOGD("drain"); diff --git a/src/cpp/CPulseStreamSpec.cpp b/src/cpp/CPulseStreamSpec.cpp index 1ad6ee1..380935f 100644 --- a/src/cpp/CPulseStreamSpec.cpp +++ b/src/cpp/CPulseStreamSpec.cpp @@ -33,12 +33,14 @@ static const char* STREAM_NAME_OUTPUT_MID_LATENCY = "MID LATENCY PLAYBACK"; static const char* STREAM_NAME_OUTPUT_HIGH_LATENCY = "HIGH LATENCY PLAYBACK"; static const char* STREAM_NAME_OUTPUT_VOIP = "VOIP PLAYBACK"; static const char* STREAM_NAME_OUTPUT_DEFAULT = "DEFAULT PLAYBACK"; +static const char* STREAM_NAME_OUTPUT_DEFAULT_ASYNC = "DEFAULT PLAYBACK ASYNC"; static const char* STREAM_LATENCY_LOW = "low"; static const char* STREAM_LATENCY_MID = "mid"; static const char* STREAM_LATENCY_HIGH = "high"; static const char* STREAM_LATENCY_VOIP = "voip"; static const char* STREAM_LATENCY_DEFAULT = "default"; +static const char* STREAM_LATENCY_DEFAULT_ASYNC = "default-async"; CPulseStreamSpec::CPulseStreamSpec(): @@ -137,6 +139,10 @@ void CPulseStreamSpec::__adjustSpec() { __mStreamName = STREAM_NAME_OUTPUT_DEFAULT; break; + case EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC: + __mStreamName = STREAM_NAME_OUTPUT_DEFAULT_ASYNC; + break; + default: AUDIO_IO_LOGW("Invalid __mLatency[%d]", static_cast(__mLatency)); break; @@ -176,6 +182,10 @@ const char* CPulseStreamSpec::getStreamLatencyToString() { latency = STREAM_LATENCY_DEFAULT; break; + case EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC: + latency = STREAM_LATENCY_DEFAULT_ASYNC; + break; + default: AUDIO_IO_LOGW("Invalid __mLatency[%d]", static_cast(__mLatency)); latency = STREAM_LATENCY_DEFAULT; -- 2.7.4