a877c7288d07cda3f6af2a51ee626534d869c1a2
[platform/core/api/audio-io.git] / src / cpp / CPulseAudioClient.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <mm.h>
19 #include "CAudioIODef.h"
20 #include <unistd.h>
21 #include <inttypes.h>
22 #ifdef ENABLE_DPM
23 #include <dpm/restriction.h>
24 #endif
25
26 using namespace std;
27 using namespace tizen_media_audio;
28
29
30 /**
31  * class CPulseAudioClient
32  */
33 const char* CPulseAudioClient::CLIENT_NAME = "AUDIO_IO_PA_CLIENT";
34 static const unsigned int drain_wait_interval = 10000;
35 static const unsigned int drain_wait_max_count = 30;
36
37 CPulseAudioClient::CPulseAudioClient(
38         EStreamDirection      direction,
39         CPulseStreamSpec&     spec,
40         IPulseStreamListener* listener) :
41     __mDirection(direction),
42     __mSpec(spec),
43     __mpListener(listener),
44     __mpMainloop(NULL),
45     __mpContext(NULL),
46     __mpStream(NULL),
47     __mpPropList(NULL),
48     __mIsInit(false),
49     __mIsOperationSuccess(false),
50     __mpSyncReadDataPtr(NULL),
51     __mSyncReadIndex(0),
52     __mSyncReadLength(0),
53     __mIsUsedSyncRead(false),
54     __mIsFirstStream(false),
55     __mIsDraining(false),
56     __mIsStarted(false) {
57 }
58
59 CPulseAudioClient::~CPulseAudioClient() {
60     finalize();
61 }
62
63 void CPulseAudioClient::__contextStateChangeCb(pa_context* c, void* user_data) {
64     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
65     assert(pClient);
66     assert(c);
67
68     switch (pa_context_get_state(c)) {
69     case PA_CONTEXT_READY:
70         AUDIO_IO_LOGD("The context is ready");
71         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
72         break;
73
74     case PA_CONTEXT_FAILED:
75     case PA_CONTEXT_TERMINATED:
76         AUDIO_IO_LOGD("The context is lost");
77         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
78         break;
79
80     case PA_CONTEXT_UNCONNECTED:
81     case PA_CONTEXT_CONNECTING:
82     case PA_CONTEXT_AUTHORIZING:
83     case PA_CONTEXT_SETTING_NAME:
84         break;
85     }
86 }
87
88 void CPulseAudioClient::__successContextCb(pa_context* c, int success, void* user_data) {
89     AUDIO_IO_LOGD("pa_context[%p], success[%d], user_data[%p]", c, success, user_data);
90     assert(c);
91     assert(user_data);
92
93     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
94     pClient->__mIsOperationSuccess = static_cast<bool>(success);
95
96     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
97 }
98
99 static bool __is_microphone_restricted(void) {
100     int state = 1;
101 #ifdef ENABLE_DPM
102     device_policy_manager_h dpm_h = NULL;
103     int ret = 0;
104
105     if ((dpm_h = dpm_manager_create())) {
106         /* state: 0(disallowed), 1(allowed) */
107         if ((ret = dpm_restriction_get_microphone_state(dpm_h, &state)))
108             AUDIO_IO_LOGE("Failed to dpm_restriction_get_microphone_state(), ret(0x%x)", ret);
109         dpm_manager_destroy(dpm_h);
110         AUDIO_IO_LOGD("microphone restriction state: %d(1:allowed, 0:disallowed)", state);
111     } else {
112         AUDIO_IO_LOGE("Failed to dpm_manager_create()");
113     }
114 #endif
115     return (state ? false : true);
116 }
117
118 void CPulseAudioClient::__streamStateChangeCb(pa_stream* s, void* user_data) {
119     assert(s);
120     assert(user_data);
121
122     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
123
124     switch (pa_stream_get_state(s)) {
125     case PA_STREAM_READY:
126         AUDIO_IO_LOGD("The stream is ready");
127         pClient->__mpListener->onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
128         if (pClient->__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK)
129             pClient->__mIsFirstStream = true;
130         pClient->__mIsInit = true;
131         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
132         break;
133
134     case PA_STREAM_FAILED:
135         AUDIO_IO_LOGD("The stream is failed");
136         pClient->__mpListener->onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE,
137                                               __is_microphone_restricted());
138         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
139         break;
140
141     case PA_STREAM_TERMINATED:
142         AUDIO_IO_LOGD("The stream is terminated");
143         pClient->__mpListener->onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
144         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
145         break;
146
147     case PA_STREAM_UNCONNECTED:
148     case PA_STREAM_CREATING:
149         break;
150     }
151 }
152
153 void CPulseAudioClient::__streamCaptureCb(pa_stream* s, size_t length, void* user_data) {
154     assert(s);
155     assert(user_data);
156
157     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
158     assert(pClient->__mpListener);
159     assert(pClient->__mpMainloop);
160
161     if (pClient->__mIsUsedSyncRead == true) {
162         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
163     }
164
165     pClient->__mpListener->onStream(pClient, length);
166 }
167
168 #ifndef DISABLE_MOBILE_BACK_COMP
169 static void __dummy_write(pa_stream* s, size_t length) {
170     char* dummy = new char[length];
171     memset(dummy, 0, length);
172     pa_stream_write(s, dummy, length, NULL, 0LL, PA_SEEK_RELATIVE);
173     delete [] dummy;
174 }
175 #endif
176
177 void CPulseAudioClient::__streamPlaybackCb(pa_stream* s, size_t length, void* user_data) {
178     assert(s);
179     assert(user_data);
180
181     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
182     assert(pClient->__mpListener);
183
184 #ifndef DISABLE_MOBILE_BACK_COMP
185     if (pClient->__mIsInit == false) {
186         AUDIO_IO_LOGD("Occurred this listener when an out stream is on the way to create : Write dummy, length[%d]", length);
187         __dummy_write(s, length);
188         return;
189     }
190     if (pClient->isCorked()) {
191         AUDIO_IO_LOGD("Occurred this listener when an out stream is CORKED : Write dummy, length[%d]", length);
192         __dummy_write(s, length);
193         return;
194     }
195 #endif
196
197     pClient->__mpListener->onStream(pClient, length);
198
199 #ifndef DISABLE_MOBILE_BACK_COMP
200     /* If stream is not written in first callback during prepare,
201        then write dummy data to ensure the start */
202     if (pClient->__mSpec.getStreamLatency() == CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC &&
203         pClient->__mIsFirstStream) {
204         AUDIO_IO_LOGW("[async] Write dummy of length[%d] since not written in first callback during prepare", length);
205         __dummy_write(s, length);
206         pClient->__mIsFirstStream = false;
207     }
208 #endif
209 }
210
211 void CPulseAudioClient::__streamLatencyUpdateCb(pa_stream* s, void* user_data) {
212     assert(s);
213     assert(user_data);
214
215     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
216
217     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
218 }
219
220 void CPulseAudioClient::__streamStartedCb(pa_stream* s, void* user_data) {
221     assert(s);
222     assert(user_data);
223
224     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
225
226     AUDIO_IO_LOGD("stream %p started.", pClient);
227
228     pClient->__mIsStarted = true;
229 }
230
231 void CPulseAudioClient::__streamUnderflowCb(pa_stream* s, void* user_data) {
232     assert(s);
233     assert(user_data);
234
235     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
236
237     AUDIO_IO_LOGD("stream %p UnderFlow...", pClient);
238
239     pClient->__mIsStarted = false;
240 }
241
242 void CPulseAudioClient::__streamEventCb(pa_stream* s, const char *name, pa_proplist *pl, void *user_data) {
243     assert(s);
244     assert(user_data);
245
246     AUDIO_IO_LOGE("NAME : %s, Prop : %p", name, pl);
247
248     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
249     if (strcmp(name, PA_STREAM_EVENT_POP_TIMEOUT) == 0) {
250         pa_operation_unref(pa_stream_cork(pClient->__mpStream, 1, NULL, NULL));
251     }
252 }
253
254
255 void CPulseAudioClient::__successStreamCb(pa_stream* s, int success, void* user_data) {
256     AUDIO_IO_LOGD("pa_stream[%p], success[%d], user_data[%p]", s, success, user_data);
257     assert(s);
258     assert(user_data);
259
260     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
261     pClient->__mIsOperationSuccess = static_cast<bool>(success);
262
263     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
264 }
265
266 void CPulseAudioClient::__successDrainCbInThread(pa_stream* s, int success, void* user_data) {
267     AUDIO_IO_LOGD("pa_stream[%p], success[%d], user_data[%p]", s, success, user_data);
268     assert(s);
269     assert(user_data);
270
271     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
272     pClient->__mIsOperationSuccess = static_cast<bool>(success);
273     pClient->__mIsDraining = false;
274 }
275
276 void CPulseAudioClient::__successDrainCb(pa_stream* s, int success, void* user_data) {
277     AUDIO_IO_LOGD("pa_stream[%p], success[%d], user_data[%p]", s, success, user_data);
278     assert(s);
279     assert(user_data);
280
281     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
282     pClient->__mIsOperationSuccess = static_cast<bool>(success);
283     pClient->__mIsDraining = false;
284
285     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
286 }
287
288 void CPulseAudioClient::initialize() {
289     if (__mIsInit == true) {
290         return;
291     }
292
293     int ret = 0;
294     int err = 0;
295
296     try {
297         // Allocates PA proplist
298         __mpPropList = pa_proplist_new();
299         if (__mpPropList == NULL) {
300             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_proplist_new()");
301         }
302
303         // Adds values on proplist for delivery to PULSEAUDIO
304         char *streamType = NULL;
305         CAudioInfo::EAudioType audioType = __mSpec.getAudioInfo().getAudioType();
306         __mSpec.getAudioInfo().convertAudioType2StreamType(audioType, &streamType);
307         pa_proplist_sets(__mpPropList, PA_PROP_MEDIA_ROLE, streamType);
308
309         int index = __mSpec.getAudioInfo().getAudioIndex();
310         if (index >= 0) {
311             pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_PARENT_ID, "%u", (unsigned int) index);
312         }
313
314         // Adds latency on proplist for delivery to PULSEAUDIO
315         AUDIO_IO_LOGD("LATENCY : %s[%d]", __mSpec.getStreamLatencyToString(), static_cast<int>(__mSpec.getStreamLatency()));
316         pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, "%s", __mSpec.getStreamLatencyToString());
317
318         // Allocates PA mainloop
319         __mpMainloop = pa_threaded_mainloop_new();
320         if (__mpMainloop == NULL) {
321             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_threaded_mainloop_new()");
322         }
323
324         // Allocates PA context
325         __mpContext = pa_context_new(pa_threaded_mainloop_get_api(__mpMainloop), CLIENT_NAME);
326         if (__mpContext == NULL) {
327             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_new()");
328         }
329
330         // Sets context state changed callback
331         pa_context_set_state_callback(__mpContext, __contextStateChangeCb, this);
332
333         // Connects this client with PA server
334         if (pa_context_connect(__mpContext, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) {
335             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_connect()");
336         }
337
338         // LOCK for synchronous connection
339         pa_threaded_mainloop_lock(__mpMainloop);
340
341         // Start mainloop
342         if (pa_threaded_mainloop_start(__mpMainloop) < 0) {
343             pa_threaded_mainloop_unlock(__mpMainloop);
344             THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_threaded_mainloop_start()");
345         }
346
347         // Connection process is asynchronously
348         // So, this function will be waited when occurred context state change event
349         // If I got a signal, do next processing
350         while (true) {
351             pa_context_state_t state;
352             state = pa_context_get_state(__mpContext);
353
354             if (state == PA_CONTEXT_READY) {
355                 break;
356             }
357
358             if (!PA_CONTEXT_IS_GOOD(state)) {
359                 err = pa_context_errno(__mpContext);
360                 pa_threaded_mainloop_unlock(__mpMainloop);
361                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_context's state is not good : err[%d]", err);
362             }
363
364             /* Wait until the context is ready */
365             pa_threaded_mainloop_wait(__mpMainloop);
366         }
367
368         // Allocates PA stream
369         pa_sample_spec ss   = __mSpec.getSampleSpec();
370         pa_channel_map map  = __mSpec.getChannelMap();
371
372         __mpStream = pa_stream_new_with_proplist(__mpContext, __mSpec.getStreamName(), &ss, &map, __mpPropList);
373         if (__mpStream == NULL) {
374             pa_threaded_mainloop_unlock(__mpMainloop);
375             THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_new_with_proplist()");
376         }
377
378         // Sets stream callbacks
379         pa_stream_set_state_callback(__mpStream, __streamStateChangeCb, this);
380         pa_stream_set_read_callback(__mpStream, __streamCaptureCb, this);
381         pa_stream_set_write_callback(__mpStream, __streamPlaybackCb, this);
382         pa_stream_set_latency_update_callback(__mpStream, __streamLatencyUpdateCb, this);
383         pa_stream_set_event_callback(__mpStream, __streamEventCb, this);
384         if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
385             pa_stream_set_started_callback(__mpStream, __streamStartedCb, this);
386             pa_stream_set_underflow_callback(__mpStream, __streamUnderflowCb, this);
387         }
388
389         // Connect stream with PA Server
390
391         if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
392             pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(
393                     PA_STREAM_INTERPOLATE_TIMING |
394                     PA_STREAM_ADJUST_LATENCY     |
395 #ifndef DISABLE_MOBILE_BACK_COMP
396                     PA_STREAM_START_CORKED       |
397 #endif
398                     PA_STREAM_AUTO_TIMING_UPDATE);
399
400             ret = pa_stream_connect_playback(__mpStream, NULL, NULL, flags, NULL, NULL);
401         } else {
402             pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(
403                     PA_STREAM_INTERPOLATE_TIMING |
404                     PA_STREAM_ADJUST_LATENCY     |
405 #ifndef DISABLE_MOBILE_BACK_COMP
406                     PA_STREAM_START_CORKED       |
407 #endif
408                     PA_STREAM_AUTO_TIMING_UPDATE);
409
410             ret = pa_stream_connect_record(__mpStream, NULL, NULL, flags);
411         }
412
413         if (ret != 0) {
414             err = pa_context_errno(__mpContext);
415             pa_threaded_mainloop_unlock(__mpMainloop);
416             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_connect() : err[%d]", err);
417         }
418
419         while (true) {
420             pa_stream_state_t state;
421             state = pa_stream_get_state(__mpStream);
422
423             if (state == PA_STREAM_READY) {
424                 AUDIO_IO_LOGD("STREAM READY");
425                 break;
426             }
427
428             if (!PA_STREAM_IS_GOOD(state)) {
429                 err = pa_context_errno(__mpContext);
430                 pa_threaded_mainloop_unlock(__mpMainloop);
431                 if (err == PA_ERR_ACCESS) {
432                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_DEVICE_POLICY_RESTRICTION, "pa_stream's state is not good : err[%d]", err);
433                 } else {
434                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_stream's state is not good : err[%d]", err);
435                 }
436             }
437
438             /* Wait until the stream is ready */
439             pa_threaded_mainloop_wait(__mpMainloop);
440         }
441
442         // End of synchronous
443         pa_threaded_mainloop_unlock(__mpMainloop);
444
445         // __mIsInit = true;  // Moved to __streamStateChangeCb()
446     } catch (CAudioError& e) {
447         finalize();
448         throw;
449     }
450 }
451
452 void CPulseAudioClient::finalize() {
453     AUDIO_IO_LOGD("");
454
455     if (__mpMainloop && isInThread() == false)
456         pa_threaded_mainloop_lock(__mpMainloop);
457
458     /* clear callbacks */
459     if (__mpStream) {
460         if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK)
461             pa_stream_set_write_callback(__mpStream, NULL, NULL);
462         else
463             pa_stream_set_read_callback(__mpStream, NULL, NULL);
464         pa_stream_set_latency_update_callback(__mpStream, NULL, NULL);
465         pa_stream_set_event_callback(__mpStream, NULL, NULL);
466     }
467
468     if (__mpMainloop && isInThread() == false)
469         pa_threaded_mainloop_unlock(__mpMainloop);
470
471     /* Wait for drain complete if draining before finalize */
472     if (__mIsDraining) {
473         unsigned int drain_wait_count = 0;
474         while (__mIsDraining && drain_wait_count++ < drain_wait_max_count) {
475             usleep(drain_wait_interval);
476         }
477         AUDIO_IO_LOGD("wait for drain complete!!!! [%d * %d usec]",
478                       drain_wait_count, drain_wait_interval);
479     }
480
481     if (__mpMainloop != NULL) {
482         pa_threaded_mainloop_stop(__mpMainloop);
483     }
484
485     if (__mpStream != NULL) {
486         pa_stream_disconnect(__mpStream);
487         pa_stream_unref(__mpStream);
488         __mpStream = NULL;
489     }
490
491     if (__mpContext != NULL) {
492         pa_context_disconnect(__mpContext);
493         pa_context_unref(__mpContext);
494         __mpContext = NULL;
495     }
496
497     if (__mpMainloop != NULL) {
498         pa_threaded_mainloop_free(__mpMainloop);
499         __mpMainloop = NULL;
500     }
501
502     if (__mpPropList != NULL) {
503         pa_proplist_free(__mpPropList);
504         __mpPropList = NULL;
505     }
506
507     __mIsInit = false;
508 }
509
510 int CPulseAudioClient::read(void* buffer, size_t length) {
511     if (__mIsInit == false) {
512         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
513     }
514
515     checkRunningState();
516
517     if (buffer == NULL) {
518         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid : buffer[%p]", buffer);
519     }
520
521     if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
522         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
523     }
524
525     size_t lengthIter = length;
526     int ret = 0;
527
528     __mIsUsedSyncRead = true;
529
530     try {
531         pa_threaded_mainloop_lock(__mpMainloop);
532
533         while (lengthIter > 0) {
534             size_t l;
535
536             while (__mpSyncReadDataPtr == NULL) {
537                 ret = pa_stream_peek(__mpStream, &__mpSyncReadDataPtr, &__mSyncReadLength);
538                 if (ret != 0) {
539                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_peek() : ret[%d]", ret);
540                 }
541
542                 if (__mSyncReadLength <= 0) {
543 #ifdef _AUDIO_IO_DEBUG_TIMING_
544                     AUDIO_IO_LOGD("readLength(%d byte) is not valid. wait...", __mSyncReadLength);
545 #endif
546                     pa_threaded_mainloop_wait(__mpMainloop);
547                 } else if (__mpSyncReadDataPtr == NULL) {
548                     // Data peeked, but it doesn't have any data
549                     ret = pa_stream_drop(__mpStream);
550                     if (ret != 0) {
551                         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_drop() : ret[%d]", ret);
552                     }
553                 } else {
554                     __mSyncReadIndex = 0;
555                 }
556             }
557
558             if (__mSyncReadLength < lengthIter) {
559                 l = __mSyncReadLength;
560             } else {
561                 l = lengthIter;
562             }
563
564             // Copy partial pcm data on out parameter
565 #ifdef _AUDIO_IO_DEBUG_TIMING_
566             AUDIO_IO_LOGD("memcpy() that a peeked buffer[0x%x], index[%d], length[%d] on out buffer", (const uint8_t*)(__mpSyncReadDataPtr) + __mSyncReadIndex, __mSyncReadIndex, l);
567 #endif
568             memcpy(buffer, (const uint8_t*)__mpSyncReadDataPtr + __mSyncReadIndex, l);
569
570             // Move next position
571             buffer = (uint8_t*)buffer + l;
572             lengthIter -= l;
573
574             // Adjusts the rest length
575             __mSyncReadIndex  += l;
576             __mSyncReadLength -= l;
577
578             if (__mSyncReadLength == 0) {
579 #ifdef _AUDIO_IO_DEBUG_TIMING_
580                 AUDIO_IO_LOGD("__mSyncReadLength is zero, do drop()");
581 #endif
582                 ret = pa_stream_drop(__mpStream);
583                 if (ret != 0) {
584                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_drop() : ret[%d]", ret);
585                 }
586
587                 // Reset the internal pointer
588                 __mpSyncReadDataPtr = NULL;
589                 __mSyncReadLength   = 0;
590                 __mSyncReadIndex    = 0;
591             }
592         }  // End of while (lengthIter > 0)
593
594         pa_threaded_mainloop_unlock(__mpMainloop);
595         __mIsUsedSyncRead = false;
596     } catch (CAudioError& e) {
597         pa_threaded_mainloop_unlock(__mpMainloop);
598         __mIsUsedSyncRead = false;
599         throw;
600     }
601
602     return length;
603 }
604
605 int CPulseAudioClient::peek(const void** buffer, size_t* length) {
606     if (__mIsInit == false) {
607         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
608     }
609
610     checkRunningState();
611
612     if (buffer == NULL || length == NULL) {
613         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid : buffer[%p], length[%p]", buffer, length);
614     }
615
616     if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
617         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
618     }
619
620     int ret = 0;
621
622     if (isInThread() == false) {
623         pa_threaded_mainloop_lock(__mpMainloop);
624         ret = pa_stream_peek(__mpStream, buffer, length);
625         pa_threaded_mainloop_unlock(__mpMainloop);
626     } else {
627         ret = pa_stream_peek(__mpStream, buffer, length);
628     }
629
630 #ifdef _AUDIO_IO_DEBUG_TIMING_
631     AUDIO_IO_LOGD("buffer[%p], length[%d]", *buffer, *length);
632 #endif
633
634     if (ret < 0) {
635         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_peek() : err[%d]", ret);
636     }
637
638     return ret;
639 }
640
641 int CPulseAudioClient::drop() {
642     if (__mIsInit == false) {
643         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
644     }
645
646 #ifdef _AUDIO_IO_DEBUG_TIMING_
647     AUDIO_IO_LOGD("");
648 #endif
649
650     checkRunningState();
651
652     if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
653         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
654     }
655
656     int ret = 0;
657
658     if (isInThread() == false) {
659         pa_threaded_mainloop_lock(__mpMainloop);
660         ret = pa_stream_drop(__mpStream);
661         pa_threaded_mainloop_unlock(__mpMainloop);
662     } else {
663         ret = pa_stream_drop(__mpStream);
664     }
665
666     if (ret < 0) {
667         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_drop() : err[%d]", ret);
668     }
669
670     return ret;
671 }
672
673 int CPulseAudioClient::write(const void* data, size_t length) {
674     if (data == NULL) {
675         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid");
676     }
677
678     if (__mDirection == EStreamDirection::STREAM_DIRECTION_RECORD) {
679         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
680     }
681
682     int ret = 0;
683
684 #ifdef _AUDIO_IO_DEBUG_TIMING_
685     AUDIO_IO_LOGD("data[%p], length[%d], First[%d]", data, length, __mIsFirstStream);
686 #endif
687     if (pa_stream_is_corked(__mpStream)) {
688         AUDIO_IO_LOGW("stream is corked...do uncork here first!!!!");
689         pa_operation_unref(pa_stream_cork(__mpStream, 0, NULL, this));
690     }
691
692     if (isInThread() == false) {
693         pa_threaded_mainloop_lock(__mpMainloop);
694         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
695         pa_threaded_mainloop_unlock(__mpMainloop);
696     } else {
697         if (__mIsFirstStream) {
698             const pa_buffer_attr* attr = pa_stream_get_buffer_attr(__mpStream);
699             uint32_t prebuf = attr->prebuf;
700             // Compensate amount of prebuf in first stream callback when audio-io use prebuf(-1)
701             // Because a stream will never start when an application wrote less than prebuf at first
702             if (length < prebuf) {
703                 char* dummy = new char[prebuf - length];
704                 memset(dummy, 0, prebuf - length);
705                 pa_stream_write(__mpStream, dummy, prebuf - length, NULL, 0LL, PA_SEEK_RELATIVE);
706                 delete [] dummy;
707             }
708             __mIsFirstStream = false;
709             AUDIO_IO_LOGW("FIRST STREAM CALLBACK : length[%d], prebuf[%d], dummy[%d]",
710                           length, prebuf, (length < prebuf) ? prebuf - length : 0);
711         }
712         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
713     }
714
715     if (ret < 0) {
716         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_write() : err[%d]", ret);
717     }
718
719     return ret;
720 }
721
722 void CPulseAudioClient::cork(bool cork) {
723     AUDIO_IO_LOGD("cork[%d]", cork);
724
725     if (__mIsInit == false) {
726         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
727     }
728
729     if (isInThread() == true) {
730         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This operation is not supported in callback");
731     }
732
733     checkRunningState();
734
735     // Set __mIsFirstStream flag when uncork(resume) stream, because prebuf will be enable again
736     if (cork == false)
737         __mIsFirstStream = true;
738
739     if (isInThread() == false) {
740         pa_threaded_mainloop_lock(__mpMainloop);
741         pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
742         pa_threaded_mainloop_unlock(__mpMainloop);
743     } else {
744         pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
745     }
746
747     return;
748 }
749
750 bool CPulseAudioClient::isCorked() {
751     if (__mIsInit == false) {
752         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
753     }
754
755     checkRunningState();
756
757     int isCork = 0;
758
759     if (isInThread() == false) {
760         pa_threaded_mainloop_lock(__mpMainloop);
761         isCork = pa_stream_is_corked(__mpStream);
762         pa_threaded_mainloop_unlock(__mpMainloop);
763     } else {
764         isCork = pa_stream_is_corked(__mpStream);
765     }
766
767 #ifdef _AUDIO_IO_DEBUG_TIMING_
768     AUDIO_IO_LOGD("isCork[%d]", isCork);
769 #endif
770     return static_cast<bool>(isCork);
771 }
772
773 bool CPulseAudioClient::drain() {
774     if (__mIsInit == false) {
775         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
776     }
777
778     checkRunningState();
779
780     if (isCorked()) {
781         AUDIO_IO_LOGW("Corked...");
782         return true;
783     }
784
785     if (__mIsDraining) {
786         AUDIO_IO_LOGW("already draining...");
787         return true;
788     }
789
790     if (!__mIsStarted) {
791         AUDIO_IO_LOGW("stream not started yet...skip drain");
792         return true;
793     }
794
795     if (isInThread() == false) {
796         AUDIO_IO_LOGD("drain");
797         pa_threaded_mainloop_lock(__mpMainloop);
798         pa_operation* o = pa_stream_drain(__mpStream, __successDrainCb, this);
799         __mIsDraining = true;
800         while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
801             pa_threaded_mainloop_wait(__mpMainloop);
802         }
803         pa_operation_unref(o);
804         pa_threaded_mainloop_unlock(__mpMainloop);
805         AUDIO_IO_LOGD("drain done");
806     } else {
807         AUDIO_IO_LOGD("drain in thread");
808         pa_operation_unref(pa_stream_drain(__mpStream, __successDrainCbInThread, this));
809         __mIsDraining = true;
810     }
811
812     return true;
813 }
814
815 bool CPulseAudioClient::flush() {
816     if (__mIsInit == false) {
817         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
818     }
819
820     checkRunningState();
821
822     if (isInThread() == false) {
823         AUDIO_IO_LOGD("flush");
824         pa_threaded_mainloop_lock(__mpMainloop);
825         pa_operation_unref(pa_stream_flush(__mpStream, __successStreamCb, this));
826         pa_threaded_mainloop_unlock(__mpMainloop);
827     } else {
828         AUDIO_IO_LOGD("flush in thread");
829         pa_operation_unref(pa_stream_flush(__mpStream, __successStreamCb, this));
830     }
831
832     return true;
833 }
834
835 size_t CPulseAudioClient::getWritableSize() {
836     if (__mIsInit == false) {
837         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
838     }
839
840     checkRunningState();
841
842     if (__mDirection != EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
843         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This client is used for Playback");
844     }
845
846     size_t ret = 0;
847
848     if (isInThread() == false) {
849         pa_threaded_mainloop_lock(__mpMainloop);
850         ret = pa_stream_writable_size(__mpStream);
851         pa_threaded_mainloop_unlock(__mpMainloop);
852     } else {
853         ret = pa_stream_writable_size(__mpStream);
854     }
855
856     return ret;
857 }
858
859 void CPulseAudioClient::checkRunningState() {
860     if (__mpContext == NULL || PA_CONTEXT_IS_GOOD(pa_context_get_state(__mpContext)) == 0) {
861         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] is not created or not good state", __mpContext);
862     }
863     if (__mpStream == NULL || PA_STREAM_IS_GOOD(pa_stream_get_state(__mpStream)) == 0) {
864         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The stream[%p] is not created or not good state", __mpStream);
865     }
866     if (pa_context_get_state(__mpContext) != PA_CONTEXT_READY || pa_stream_get_state(__mpStream) != PA_STREAM_READY) {
867         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] or stream[%p] state is not ready", __mpContext, __mpStream);
868     }
869
870 #ifdef _AUDIO_IO_DEBUG_TIMING_
871     AUDIO_IO_LOGD("This client is running");
872 #endif
873 }
874
875 bool CPulseAudioClient::isInThread() {
876     int ret = pa_threaded_mainloop_in_thread(__mpMainloop);
877
878 #ifdef _AUDIO_IO_DEBUG_TIMING_
879     AUDIO_IO_LOGD("isInThread[%d]", ret);
880 #endif
881     return static_cast<bool>(ret);
882 }
883
884 size_t CPulseAudioClient::getReadableSize() {
885     if (__mIsInit == false) {
886         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
887     }
888
889     checkRunningState();
890
891     if (__mDirection != EStreamDirection::STREAM_DIRECTION_RECORD) {
892         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This client is used for Capture");
893     }
894
895     size_t ret = 0;
896
897     if (isInThread() == false) {
898         pa_threaded_mainloop_lock(__mpMainloop);
899         ret = pa_stream_writable_size(__mpStream);
900         pa_threaded_mainloop_unlock(__mpMainloop);
901     } else {
902         ret = pa_stream_writable_size(__mpStream);
903     }
904
905     return ret;
906 }
907
908 size_t CPulseAudioClient::getBufferSize() {
909     if (__mIsInit == false) {
910         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
911     }
912
913     checkRunningState();
914
915     size_t ret = 0;
916
917     try {
918         if (isInThread() == false) {
919             pa_threaded_mainloop_lock(__mpMainloop);
920         }
921
922         const pa_buffer_attr* attr = pa_stream_get_buffer_attr(__mpStream);
923         if (attr == NULL) {
924             int _err = pa_context_errno(__mpContext);
925             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_buffer_attr() : err[%d]", _err);
926         }
927
928         if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
929             ret = attr->tlength;
930             AUDIO_IO_LOGD("PLAYBACK buffer size[%d]", ret);
931         } else {
932             ret = attr->fragsize;
933             AUDIO_IO_LOGD("RECORD buffer size[%d]", ret);
934         }
935     } catch (CAudioError& e) {
936         if (isInThread() == false) {
937             pa_threaded_mainloop_unlock(__mpMainloop);
938         }
939         throw;
940     }
941
942     if (isInThread() == false) {
943         pa_threaded_mainloop_unlock(__mpMainloop);
944     }
945
946     return ret;
947 }
948
949 pa_usec_t CPulseAudioClient::getLatency() {
950     if (__mIsInit == false) {
951         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
952     }
953
954     checkRunningState();
955
956     pa_usec_t ret = 0;
957     int negative  = 0;
958
959     if (isInThread() == false) {
960         if (pa_stream_get_latency(__mpStream, &ret, &negative) < 0) {
961             int _err = pa_context_errno(__mpContext);
962             if (_err != PA_ERR_NODATA) {
963                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() : err[%d]", _err);
964             }
965         }
966         return negative ? 0 : ret;
967     }
968
969     pa_threaded_mainloop_lock(__mpMainloop);
970
971     try {
972         while (true) {
973             if (pa_stream_get_latency(__mpStream, &ret, &negative) >= 0) {
974                 break;
975             }
976
977             int _err = pa_context_errno(__mpContext);
978             if (_err != PA_ERR_NODATA) {
979                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() : err[%d]", _err);
980             }
981
982             /* Wait until latency data is available again */
983             pa_threaded_mainloop_wait(__mpMainloop);
984         }
985     } catch (CAudioError& e) {
986         pa_threaded_mainloop_unlock(__mpMainloop);
987         throw;
988     }
989
990     pa_threaded_mainloop_unlock(__mpMainloop);
991
992     return negative ? 0 : ret;
993 }
994
995 pa_usec_t CPulseAudioClient::getFinalLatency() {
996     if (__mIsInit == false) {
997         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
998     }
999
1000     checkRunningState();
1001
1002     pa_usec_t ret = 0;
1003     uint32_t  ver = 0;
1004
1005     try {
1006         if (isInThread() == false) {
1007             pa_threaded_mainloop_lock(__mpMainloop);
1008         }
1009
1010         ver = pa_context_get_server_protocol_version(__mpContext);
1011         if (ver >= 13) {
1012             const pa_buffer_attr* buffer_attr = pa_stream_get_buffer_attr(__mpStream);
1013             const pa_sample_spec* sample_spec = pa_stream_get_sample_spec(__mpStream);
1014             const pa_timing_info* timing_info = pa_stream_get_timing_info(__mpStream);
1015
1016             if (buffer_attr == NULL || sample_spec == NULL || timing_info == NULL) {
1017                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to get buffer_attr[%p] or sample_spec[%p] or timing_info[%p] from a pa_stream",
1018                         buffer_attr, sample_spec, timing_info);
1019             }
1020
1021             if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
1022                 ret = (pa_bytes_to_usec(buffer_attr->tlength, sample_spec) + timing_info->configured_sink_usec);
1023                 AUDIO_IO_LOGD("FINAL PLAYBACK LATENCY[%" PRIu64 "]", ret);
1024             } else {
1025                 ret = (pa_bytes_to_usec(buffer_attr->fragsize, sample_spec) + timing_info->configured_source_usec);
1026                 AUDIO_IO_LOGD("FINAL RECORD LATENCY[%" PRIu64 "]", ret);
1027             }
1028         } else {
1029             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED, "This version(ver.%d) is not supported", ver);
1030         }
1031
1032         if (isInThread() == false) {
1033             pa_threaded_mainloop_unlock(__mpMainloop);
1034         }
1035     } catch (CAudioError& e) {
1036         if (isInThread() == false) {
1037             pa_threaded_mainloop_unlock(__mpMainloop);
1038         }
1039         throw;
1040     }
1041
1042     return ret;
1043 }
1044
1045 CPulseAudioClient::EStreamDirection CPulseAudioClient::getStreamDirection() {
1046     return __mDirection;
1047 }
1048
1049 CPulseStreamSpec CPulseAudioClient::getStreamSpec() {
1050     return __mSpec;
1051 }