fixup! Reset dump values when pause function is called 88/309088/4 accepted/tizen_unified accepted/tizen_unified_x tizen accepted/tizen/unified/20240409.135556 accepted/tizen/unified/20240409.155901 accepted/tizen/unified/x/20240411.011827
authorSeungbae Shin <seungbae.shin@samsung.com>
Thu, 4 Apr 2024 12:05:00 +0000 (21:05 +0900)
committerSeungbae Shin <seungbae.shin@samsung.com>
Fri, 5 Apr 2024 07:20:57 +0000 (16:20 +0900)
refactor code to handle internal cork scenario due to empty-pop-timeout

Change-Id: Ief7fad657bc78a34f4835ace504ffd6d1fa9ee8c

include/CAudioIO.h
include/CAudioIODef.h
include/CAudioOutput.h
include/CPulseAudioClient.h
include/IPulseStreamListener.h
packaging/capi-media-audio-io.spec
src/cpp/CAudioIO.cpp
src/cpp/CAudioOutput.cpp
src/cpp/CPulseAudioClient.cpp

index 4cb769e..36eabfc 100644 (file)
@@ -71,6 +71,7 @@ namespace tizen_media_audio {
         virtual void onStream(CPulseAudioClient* pClient, size_t length);
         virtual void onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy);
         virtual void onStateChanged(CAudioInfo::EAudioIOState state);
+        virtual void onCorked(CPulseAudioClient* pClient, bool corked);
 
         /* Methods */
         virtual void initialize();
index 1fffbb7..b431bdf 100644 (file)
@@ -20,7 +20,7 @@
 
 #ifdef __cplusplus
 
-
+#include <atomic>
 #include <stdio.h>
 #include <dlog.h>
 
index da44f63..8b9b0bc 100644 (file)
@@ -37,6 +37,7 @@ namespace tizen_media_audio {
 
         /* Overridden Handler */
         void onStream(CPulseAudioClient* pClient, size_t length) override;
+        void onCorked(CPulseAudioClient* pClient, bool corked) override;
 
         /* Implemented Methods */
         void initialize() override;
@@ -67,8 +68,8 @@ namespace tizen_media_audio {
         bool __mIsUsedSyncWrite {};
         bool __mIsInit {};
 
-        uint64_t __mTotalWrittenCount {};
-        uint64_t __mTotalWrittenBytes {};
+        std::atomic<uint64_t> __mTotalWrittenCount {};
+        std::atomic<uint64_t> __mTotalWrittenBytes {};
     };
 
 
index 631362a..7e1ce1e 100644 (file)
@@ -102,6 +102,8 @@ namespace tizen_media_audio {
         /* Private Method */
         void resetStreamCallbacks();
         void resetInternalObjects();
+        bool streamCork(bool cork, pa_stream_success_cb_t cb, void* user_data);
+        void notifyCorkStatus();
 
         /* Private Callback Method */
         static void __contextStateChangeCb(pa_context* c, void* user_data);
@@ -112,8 +114,10 @@ namespace tizen_media_audio {
         static void __streamStartedCb(pa_stream* s, void* user_data);
         static void __streamUnderflowCb(pa_stream* s, void* user_data);
         static void __streamOverflowCb(pa_stream* s, void* user_data);
-        static void __streamEventCb(pa_stream* s, const char *name, pa_proplist *pl, void *user_data);
+        static void __streamEventCb(pa_stream* s, const char* name, pa_proplist* pl, void* user_data);
         static void __successStreamCb(pa_stream* s, int success, void* user_data);
+        static void __successCorkCb(pa_stream* s, int success, void* user_data);
+        static void __successCorkCbSignal(pa_stream* s, int success, void* user_data);
         static void __successDrainCb(pa_stream* s, int success, void* user_data);
         static void __successDrainCbInThread(pa_stream* s, int success, void* user_data);
         static void __successVolumeCb(pa_context* c, int success, void* user_data);
index 76b4288..90521c7 100644 (file)
@@ -37,6 +37,7 @@ namespace tizen_media_audio {
         virtual void onStateChanged(CAudioInfo::EAudioIOState state) = 0;
         virtual void onStateChanged(CAudioInfo::EAudioIOState state, bool policy) = 0;
         virtual void setState(CAudioInfo::EAudioIOState state) = 0;
+        virtual void onCorked(CPulseAudioClient* pClient, bool corked) = 0;
     };
 
 
index 8c46590..80df104 100644 (file)
@@ -1,6 +1,6 @@
 Name:           capi-media-audio-io
 Summary:        An Audio Input & Audio Output library in Tizen Native API
-Version:        0.5.67
+Version:        0.5.68
 Release:        0
 Group:          Multimedia/API
 License:        Apache-2.0
index fac712a..04ceb05 100644 (file)
@@ -220,3 +220,10 @@ void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
             getAudioInfo().setEffectMethodWithReference(method_reference, device_id);
     }
 }
+
+void CAudioIO::onCorked(CPulseAudioClient* pClient, bool corked) {
+    assert(__mIsInit);
+    assert(pClient);
+
+    AUDIO_IO_LOGD("pClient(%p), corked(%d)", pClient, corked);
+}
index d50762a..7a5c3ad 100644 (file)
@@ -218,9 +218,6 @@ void CAudioOutput::pause() {
     CAudioIO::pause();
     CAudioIO::setState(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
 
-    __mTotalWrittenCount = 0;
-    __mTotalWrittenBytes = 0;
-
     locker.unlock();
 
     CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
@@ -388,7 +385,8 @@ size_t CAudioOutput::write(const void* buffer, size_t length) {
 
 void CAudioOutput::__dumpStat() noexcept {
     AUDIO_IO_LOGD("pClient[%p] : total written %5" PRIu64 " times, %10" PRIu64 " bytes, %7zu ms",
-                  mpPulseAudioClient, __mTotalWrittenCount, __mTotalWrittenBytes, mAudioInfo.bytesToMs(__mTotalWrittenBytes));
+                  mpPulseAudioClient, __mTotalWrittenCount.load(), __mTotalWrittenBytes.load(),
+                  mAudioInfo.bytesToMs(__mTotalWrittenBytes.load()));
 }
 
 void CAudioOutput::__dumpStat(size_t length) noexcept {
@@ -403,3 +401,19 @@ void CAudioOutput::__dumpStat(size_t length) noexcept {
         writtenBytes = 0;
     }
 }
+
+void CAudioOutput::onCorked(CPulseAudioClient* pClient, bool corked) {
+    assert(pClient);
+
+    AUDIO_IO_LOGD("pClient:[%p], corked:[%d]", pClient, corked);
+
+    if (!corked)
+        return;
+
+    __dumpStat();
+
+    AUDIO_IO_LOGW("Now reset previous written count/bytes due to corked!");
+
+    __mTotalWrittenCount = 0;
+    __mTotalWrittenBytes = 0;
+}
\ No newline at end of file
index d143d94..e18c69e 100644 (file)
@@ -281,17 +281,50 @@ void CPulseAudioClient::__streamEventCb(pa_stream* s, const char* name, pa_propl
 
     AUDIO_IO_LOGW("pClient[%p] pa_stream[%p] : name[%s], proplist[%p]", pClient, s, name, pl);
 
-    if (strcmp(name, PA_STREAM_EVENT_POP_TIMEOUT) == 0) {
-        pa_operation* o = pa_stream_cork(pClient->__mpStream, 1, NULL, NULL);
-        if (!o) {
-            AUDIO_IO_LOGE("pa_stream[%p] : cork failed", pClient->__mpStream);
-            return;
-        }
-        pa_operation_unref(o);
-    }
+    if (strcmp(name, PA_STREAM_EVENT_POP_TIMEOUT) != 0)
+        return;
+
+    if (!pClient->streamCork(true, __successCorkCb, pClient))
+        AUDIO_IO_LOGE("pa_stream[%p] : cork failed", pClient->__mpStream);
 }
 //LCOV_EXCL_STOP
 
+void CPulseAudioClient::notifyCorkStatus() {
+    assert(__mpListener);
+    assert(__mpStream);
+
+    __mpListener->onCorked(this, static_cast<bool>(pa_stream_is_corked(__mpStream)));
+}
+
+void CPulseAudioClient::__successCorkCb(pa_stream* s, int success, void* user_data) {
+    assert(s);
+    assert(user_data);
+
+    auto pClient = static_cast<CPulseAudioClient*>(user_data);
+
+    AUDIO_IO_LOGD("pClient[%p] pa_stream[%p] success[%d] user_data[%p]", pClient, s, success, user_data);
+
+    if (success)
+        pClient->notifyCorkStatus();
+}
+
+void CPulseAudioClient::__successCorkCbSignal(pa_stream* s, int success, void* user_data) {
+    assert(s);
+    assert(user_data);
+
+    auto pClient = static_cast<CPulseAudioClient*>(user_data);
+
+    AUDIO_IO_LOGD("pClient[%p] pa_stream[%p] success[%d] user_data[%p]", pClient, s, success, user_data);
+
+    if (success)
+        pClient->notifyCorkStatus();
+
+    pClient->__mIsOperationSuccess = static_cast<bool>(success);
+
+    /* FIXME : verify following action without any waiting */
+    pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
+}
+
 void CPulseAudioClient::__successStreamCb(pa_stream* s, int success, void* user_data) {
     assert(s);
     assert(user_data);
@@ -747,11 +780,8 @@ int CPulseAudioClient::write(const void* data, size_t length) {
         CPulseThreadLocker locker{__mpMainloop};
         if (pa_stream_is_corked(__mpStream)) {
             AUDIO_IO_LOGW("pa_stream[%p] is corked...do uncork here first!!!!", __mpStream);
-            pa_operation* o = pa_stream_cork(__mpStream, 0, NULL, NULL);
-            if (!o)
+            if (!streamCork(false, __successCorkCb, this))
                 AUDIO_IO_LOGE("pa_stream[%p] : uncork failed", __mpStream);
-            else
-                pa_operation_unref(o);
         }
 
         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
@@ -759,11 +789,9 @@ int CPulseAudioClient::write(const void* data, size_t length) {
 // LCOV_EXCL_START
         if (pa_stream_is_corked(__mpStream)) {
             AUDIO_IO_LOGW("pa_stream[%p] is corked...do uncork here first!!!!", __mpStream);
-            pa_operation* o = pa_stream_cork(__mpStream, 0, NULL, NULL);
-            if (!o)
+
+            if (!streamCork(false, __successCorkCb, this))
                 AUDIO_IO_LOGE("pa_stream[%p] : uncork failed", __mpStream);
-            else
-                pa_operation_unref(o);
         }
 
         if (__mIsFirstStream) {
@@ -788,6 +816,15 @@ int CPulseAudioClient::write(const void* data, size_t length) {
     return ret;
 }
 
+bool CPulseAudioClient::streamCork(bool cork, pa_stream_success_cb_t cb, void* user_data) {
+    pa_operation* o = pa_stream_cork(__mpStream, static_cast<int>(cork), cb, user_data);
+    if (!o)
+        return false;
+    pa_operation_unref(o);
+
+    return true;
+}
+
 void CPulseAudioClient::cork(bool cork) {
     AUDIO_IO_LOGD("cork[%d]", cork);
 
@@ -806,13 +843,15 @@ void CPulseAudioClient::cork(bool cork) {
     CPulseThreadLocker locker{__mpMainloop};
 
     /* FIXME: wait for completion like drain? */
-    pa_operation* o = pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this);
-    if (!o) {
+    if (!streamCork(cork, __successCorkCbSignal, this)) {
         AUDIO_IO_LOGE("pa_stream[%p] : cork[%d] failed", __mpStream, cork);
         return;
     }
-    pa_operation_unref(o);
-    AUDIO_IO_LOGD("cork[%d] done", cork);
+
+    AUDIO_IO_LOGD("cork[%d] requested, is-stream-started[%d]", cork, __mIsStarted);
+
+    /* FIXME: need to consider manual pa_stream_trigger() when uncorking but stream is not started yet,
+              because even uncorked here, it is still prebuf state so, empty-pop will not be checked in this situation */
 }
 
 bool CPulseAudioClient::isCorked() {