audio-io fixed no callback issue at start 69/110969/11
authorKimJeongYeon <jeongyeon.kim@samsung.com>
Thu, 19 Jan 2017 05:02:11 +0000 (14:02 +0900)
committerKimJeongYeon <jeongyeon.kim@samsung.com>
Mon, 23 Jan 2017 06:30:03 +0000 (15:30 +0900)
Changes:
 * In case of asyncronous write, never callback will be invoked when
   application has wrote less than prebuf(-1) at first callback.
   To avoid deadlock between applicaiton and pulseaudio, audio-io
   ensure to write at least size of prebuf.
 * Need to move enabling __mIsInit flag to state changed callback.
   Because of some audio-io APIs rejected at first stream callback.
   (e.g audio_out_drain, audio_out_flush, ...)

[Version] 0.3.56
[Profile] Common
[Issue Type] Compatibility

Signed-off-by: KimJeongYeon <jeongyeon.kim@samsung.com>
Change-Id: I64e43913c6a22ab2003615b40b9e616c59423628

include/CPulseAudioClient.h
packaging/capi-media-audio-io.spec
src/cpp/CPulseAudioClient.cpp

index af3f0c5..b2778a3 100644 (file)
@@ -98,6 +98,7 @@ namespace tizen_media_audio {
         size_t                __mSyncReadIndex;
         size_t                __mSyncReadLength;
         bool                  __mIsUsedSyncRead;
+        bool                  __mIsFirstStream;
 
         /* Static Methods */
 
index 1e528e2..5ea5a53 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.55
+Version:        0.3.56
 Release:        0
 Group:          Multimedia/API
 License:        Apache-2.0
index fe28ea9..d0a0e0d 100644 (file)
@@ -46,7 +46,8 @@ CPulseAudioClient::CPulseAudioClient(
     __mpSyncReadDataPtr(NULL),
     __mSyncReadIndex(0),
     __mSyncReadLength(0),
-    __mIsUsedSyncRead(false) {
+    __mIsUsedSyncRead(false),
+    __mIsFirstStream(false) {
 }
 
 CPulseAudioClient::~CPulseAudioClient() {
@@ -118,6 +119,9 @@ void CPulseAudioClient::__streamStateChangeCb(pa_stream* s, void* user_data) {
     case PA_STREAM_READY:
         AUDIO_IO_LOGD("The stream is ready");
         pClient->__mpListener->onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
+        if (pClient->__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK)
+            pClient->__mIsFirstStream = true;
+        pClient->__mIsInit = true;
         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
         break;
 
@@ -346,7 +350,7 @@ void CPulseAudioClient::initialize() throw(CAudioError) {
         // End of synchronous
         pa_threaded_mainloop_unlock(__mpMainloop);
 
-        __mIsInit = true;
+        // __mIsInit = true;  // Moved to __streamStateChangeCb()
     } catch (CAudioError e) {
         finalize();
         throw e;
@@ -575,6 +579,20 @@ int CPulseAudioClient::write(const void* data, size_t length) throw(CAudioError)
         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
         pa_threaded_mainloop_unlock(__mpMainloop);
     } else {
+        if (__mIsFirstStream) {
+            const pa_buffer_attr* attr = pa_stream_get_buffer_attr(__mpStream);
+            uint32_t prebuf = attr->prebuf;
+            // Compensate amount of prebuf in first stream callback when audio-io use prebuf(-1)
+            // Because a stream will never start when an application wrote less than prebuf at first
+            if (length < prebuf) {
+                char* dummy = new char[prebuf - length];
+                memset(dummy, 0, prebuf - length);
+                pa_stream_write(__mpStream, dummy, prebuf - length, NULL, 0LL, PA_SEEK_RELATIVE);
+                delete [] dummy;
+            }
+            __mIsFirstStream = false;
+            AUDIO_IO_LOGD("FIRST STREAM CALLBACK : length[%d], prebuf[%d], dummy[%d]", length, prebuf, (length < prebuf) ? prebuf - length : 0);
+        }
         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
     }
 
@@ -598,6 +616,10 @@ void CPulseAudioClient::cork(bool cork) throw(CAudioError) {
 
     checkRunningState();
 
+    // Set __mIsFirstStream flag when uncork(resume) stream, because prebuf will be enable again
+    if (cork == false)
+        __mIsFirstStream = true;
+
     if (isInThread() == false) {
         pa_threaded_mainloop_lock(__mpMainloop);
         pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
@@ -701,7 +723,7 @@ void CPulseAudioClient::checkRunningState() throw(CAudioError) {
     if (__mpStream == NULL || PA_STREAM_IS_GOOD(pa_stream_get_state(__mpStream)) == 0) {
         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The stream[%p] is not created or not good state", __mpStream);
     }
-    if (pa_context_get_state(__mpContext) != PA_CONTEXT_READY || pa_stream_get_state(__mpStream)   != PA_STREAM_READY) {
+    if (pa_context_get_state(__mpContext) != PA_CONTEXT_READY || pa_stream_get_state(__mpStream) != PA_STREAM_READY) {
         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] or stream[%p] state is not ready", __mpContext, __mpStream);
     }