Merge from mobile product code for backward compatibility 32/142432/9 accepted/tizen/unified/20170908.062032 submit/tizen/20170907.123315
authorSeungbae Shin <seungbae.shin@samsung.com>
Thu, 3 Aug 2017 10:16:05 +0000 (19:16 +0900)
committerSeungbae Shin <seungbae.shin@samsung.com>
Thu, 7 Sep 2017 11:38:54 +0000 (20:38 +0900)
(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
include/CAudioIO.h
include/CPulseStreamSpec.h
packaging/capi-media-audio-io.spec
src/cpp/CAudioIO.cpp
src/cpp/CAudioInput.cpp
src/cpp/CAudioOutput.cpp
src/cpp/CAudioSessionHandler.cpp
src/cpp/CPulseAudioClient.cpp
src/cpp/CPulseStreamSpec.cpp

index 1dcb532f26937e12eb53e64418797b99ce8ee44e..b9999e9000be1f51bf92fafaa0e85b954c4cab77 100644 (file)
@@ -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)
index abfa359779a755a05fc1cf804261a018a1cb488a..3d48f23fdf43e6ecee181c5e56abdd6e426b7830 100644 (file)
@@ -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;
index 16a29f7e8da6126f987f50fc95d8bafc6ecd0a5d..416884f57b42a5189bedcd742fde3f0d615464dd 100644 (file)
@@ -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
         };
 
index ef8818c8bc29472e488eff82aa885edac9680c15..6e20ddf64936d5f92cc4fe899352c9eb7fa326ad 100644 (file)
@@ -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}
index d5432192a048cc900138a71191c31e95c041c9ac..b98c2f934cb7759989cfc7b5ff9459c133935f78 100644 (file)
@@ -18,6 +18,7 @@
 #include <mm.h>
 #include <pthread.h>
 #include <assert.h>
+#include <glib.h>
 #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) {
index 3aea844774add48d451cbc30cc7c6087c436d3a1..93a58dad33ac285768dd1b18518259f941139cb7 100644 (file)
@@ -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)
index b54c0db56f3def75f575d0863edd265d356871b0..6760f2e358ac1a963a52a1c96252c4cbbb8ff335 100644 (file)
@@ -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)
index 51f9a4b8b3c059647f2b46678beb7e26b1517311..f56d73e6b9d6f8607d426087c8ecdc65f0a56eb9 100644 (file)
@@ -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);
index 1ac1c0d6c324725325dad64eab3aac629e832c97..50ce02ef0100577efdb7223c827a99f94c15ff48 100644 (file)
@@ -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<CPulseAudioClient*>(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_flags_t>(
                     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_flags_t>(
                     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<bool>(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");
index 1ad6ee1801a7277a09e64c88366886c0bb39ae75..380935fbb21e63baf21f665d2d2885001c75fbd1 100644 (file)
@@ -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<int>(__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<int>(__mLatency));
         latency = STREAM_LATENCY_DEFAULT;