audio-io fixed sync problem while reads pcm data, code refactoring
[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
21
22 using namespace std;
23 using namespace tizen_media_audio;
24
25
26 /**
27  * class CPulseAudioClient
28  */
29 const char* CPulseAudioClient::CLIENT_NAME = "AUDIO_IO_PA_CLIENT";
30
31 CPulseAudioClient::CPulseAudioClient(
32         EStreamDirection      direction,
33         CPulseStreamSpec&     spec,
34         IPulseStreamListener* listener) :
35     __mDirection(direction),
36     __mSpec(spec),
37     __mpListener(listener),
38     __mpMainloop(NULL),
39     __mpContext(NULL),
40     __mpStream(NULL),
41     __mpPropList(NULL),
42     __mIsInit(false),
43     __mIsOperationSuccess(false),
44     __mpSyncReadDataPtr(NULL),
45     __mSyncReadIndex(0),
46     __mSyncReadLength(0),
47     __mIsUsedSyncRead(false) {
48 }
49
50 CPulseAudioClient::~CPulseAudioClient() {
51     finalize();
52 }
53
54 void CPulseAudioClient::__contextStateChangeCb(pa_context* c, void* user_data) {
55     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
56     assert(pClient);
57     assert(c);
58
59     switch (pa_context_get_state(c)) {
60     case PA_CONTEXT_READY:
61         AUDIO_IO_LOGD("The context is ready!");
62     case PA_CONTEXT_FAILED:
63     case PA_CONTEXT_TERMINATED:
64         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
65         break;
66
67     case PA_CONTEXT_UNCONNECTED:
68     case PA_CONTEXT_CONNECTING:
69     case PA_CONTEXT_AUTHORIZING:
70     case PA_CONTEXT_SETTING_NAME:
71         break;
72     }
73 }
74
75 void CPulseAudioClient::__successContextCb(pa_context* c, int success, void* user_data) {
76     AUDIO_IO_LOGD("pa_context[%p], success[%d], user_data[%p]", c, success, user_data);
77     assert(c);
78     assert(user_data);
79
80     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
81     pClient->__mIsOperationSuccess = static_cast<bool>(success);
82
83     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
84 }
85
86 void CPulseAudioClient::__streamStateChangeCb(pa_stream* s, void* user_data) {
87     assert(s);
88     assert(user_data);
89
90     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
91
92     switch (pa_stream_get_state(s)) {
93     case PA_STREAM_READY:
94         AUDIO_IO_LOGD("The stream is ready!");
95         pClient->__mpListener->onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
96     case PA_STREAM_FAILED:
97     case PA_STREAM_TERMINATED:
98         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
99         break;
100
101     case PA_STREAM_UNCONNECTED:
102         break;
103     case PA_STREAM_CREATING:
104         break;
105     }
106 }
107
108 void CPulseAudioClient::__streamCaptureCb(pa_stream* s, size_t length, void* user_data) {
109     assert(s);
110     assert(user_data);
111
112     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
113     assert(pClient->__mpListener);
114     assert(pClient->__mpMainloop);
115
116     if (pClient->__mIsUsedSyncRead == true) {
117         pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
118     }
119
120     pClient->__mpListener->onStream(pClient, length);
121 }
122
123 void CPulseAudioClient::__streamPlaybackCb(pa_stream* s, size_t length, void* user_data) {
124     assert(s);
125     assert(user_data);
126
127     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
128     assert(pClient->__mpListener);
129
130     if (pClient->__mIsInit == false) {
131         AUDIO_IO_LOGD("Occurred this listener when an out stream is on the way to create : Write dummy, length[%d]", length);
132
133         char* dummy = new char[length];
134         memset(dummy, 0, length);
135         pa_stream_write(s, dummy, length, NULL, 0LL, PA_SEEK_RELATIVE);
136         delete [] dummy;
137
138         return;
139     }
140
141     pClient->__mpListener->onStream(pClient, length);
142 }
143
144 void CPulseAudioClient::__streamLatencyUpdateCb(pa_stream* s, void* user_data) {
145     assert(s);
146     assert(user_data);
147
148     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
149
150     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
151 }
152
153 void CPulseAudioClient::__successStreamCb(pa_stream* s, int success, void* user_data) {
154     AUDIO_IO_LOGD("pa_stream[%p], success[%d], user_data[%p]", s, success, user_data);
155     assert(s);
156     assert(user_data);
157
158     CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
159     pClient->__mIsOperationSuccess = static_cast<bool>(success);
160
161     pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
162 }
163
164 void CPulseAudioClient::initialize() throw (CAudioError) {
165     AUDIO_IO_LOGD("");
166     if (__mIsInit == true) {
167         return;
168     }
169
170     int ret = 0;
171     int err = 0;
172
173     try {
174         // Allocates PA proplist
175         __mpPropList = pa_proplist_new();
176         if (__mpPropList == NULL) {
177             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_proplist_new()");
178         }
179
180         // Adds values on proplist for delivery to PULSEAUDIO
181         char *streamType = NULL;
182         CAudioInfo::EAudioType audioType = __mSpec.getAudioInfo().getAudioType();
183         __mSpec.getAudioInfo().convertAudioType2StreamType(audioType, &streamType);
184         pa_proplist_sets(__mpPropList, PA_PROP_MEDIA_ROLE, streamType);
185
186         int index = __mSpec.getAudioInfo().getAudioIndex();
187         if (index >= 0) {
188             pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_PARENT_ID, "%u", (unsigned int) index);
189         }
190
191         // Adds latency on proplist for delivery to PULSEAUDIO
192         AUDIO_IO_LOGD("LATENCY : %s[%d]", __mSpec.getStreamLatencyToString(), __mSpec.getStreamLatency());
193         pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, "%s", __mSpec.getStreamLatencyToString());
194
195         // Allocates PA mainloop
196         __mpMainloop = pa_threaded_mainloop_new();
197         if (__mpMainloop == NULL) {
198             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_threaded_mainloop_new()");
199         }
200
201         // Allocates PA context
202         __mpContext = pa_context_new(pa_threaded_mainloop_get_api(__mpMainloop), CLIENT_NAME);
203         if (__mpContext == NULL) {
204             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_new()");
205         }
206
207         // Sets context state changed callback
208         pa_context_set_state_callback(__mpContext, __contextStateChangeCb, this);
209
210         // Connects this client with PA server
211         if (pa_context_connect(__mpContext, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) {
212             THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_connect()");
213         }
214
215         // LOCK for synchronous connection
216         pa_threaded_mainloop_lock(__mpMainloop);
217
218         // Start mainloop
219         if (pa_threaded_mainloop_start(__mpMainloop) < 0) {
220             pa_threaded_mainloop_unlock(__mpMainloop);
221             THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_threaded_mainloop_start()");
222         }
223
224         // Connection process is asynchronously
225         // So, this function will be waited when occurred context state change event
226         // If I got a signal, do next processing
227         while (true) {
228             pa_context_state_t state;
229             state = pa_context_get_state(__mpContext);
230
231             if (state == PA_CONTEXT_READY) {
232                 break;
233             }
234
235             if (!PA_CONTEXT_IS_GOOD(state)) {
236                 err = pa_context_errno(__mpContext);
237                 pa_threaded_mainloop_unlock(__mpMainloop);
238                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_context's state is not good : err[%d]", err);
239             }
240
241             /* Wait until the context is ready */
242             pa_threaded_mainloop_wait(__mpMainloop);
243         }
244
245         // Allocates PA stream
246         pa_sample_spec ss   = __mSpec.getSampleSpec();
247         pa_channel_map map  = __mSpec.getChannelMap();
248
249         __mpStream = pa_stream_new_with_proplist(__mpContext, __mSpec.getStreamName(), &ss, &map, __mpPropList);
250         if (__mpStream == NULL) {
251             pa_threaded_mainloop_unlock(__mpMainloop);
252             THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_new_with_proplist()");
253         }
254
255         // Sets stream callbacks
256         pa_stream_set_state_callback(__mpStream, __streamStateChangeCb, this);
257         pa_stream_set_read_callback(__mpStream, __streamCaptureCb, this);
258         pa_stream_set_write_callback(__mpStream, __streamPlaybackCb, this);
259         pa_stream_set_latency_update_callback(__mpStream, __streamLatencyUpdateCb, this);
260
261         // Connect stream with PA Server
262
263         if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
264             pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(
265                     PA_STREAM_INTERPOLATE_TIMING |
266                     PA_STREAM_ADJUST_LATENCY     |
267                     PA_STREAM_AUTO_TIMING_UPDATE);
268
269             ret = pa_stream_connect_playback(__mpStream, NULL, NULL, flags, NULL, NULL);
270         } else {
271             pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(
272                     PA_STREAM_INTERPOLATE_TIMING |
273                     PA_STREAM_ADJUST_LATENCY     |
274                     PA_STREAM_AUTO_TIMING_UPDATE);
275
276             ret = pa_stream_connect_record(__mpStream, NULL, NULL, flags);
277         }
278
279         if (ret != 0) {
280             err = pa_context_errno(__mpContext);
281             pa_threaded_mainloop_unlock(__mpMainloop);
282             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_connect() : err[%d]", err);
283         }
284
285         while (true) {
286             pa_stream_state_t state;
287             state = pa_stream_get_state(__mpStream);
288
289             if (state == PA_STREAM_READY) {
290                 AUDIO_IO_LOGD("STREAM READY");
291                 break;
292             }
293
294             if (!PA_STREAM_IS_GOOD(state)) {
295                 err = pa_context_errno(__mpContext);
296                 pa_threaded_mainloop_unlock(__mpMainloop);
297                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_stream's state is not good : err[%d]", err);
298             }
299
300             /* Wait until the stream is ready */
301             pa_threaded_mainloop_wait(__mpMainloop);
302         }
303
304         // End of synchronous
305         pa_threaded_mainloop_unlock(__mpMainloop);
306
307         __mIsInit = true;
308     } catch (CAudioError e) {
309         finalize();
310         throw e;
311     }
312 }
313
314 void CPulseAudioClient::finalize() {
315     AUDIO_IO_LOGD("");
316     if (__mIsInit == false) {
317         return;
318     }
319
320     if (__mpMainloop != NULL) {
321         pa_threaded_mainloop_stop(__mpMainloop);
322     }
323
324     if (__mpStream != NULL) {
325         pa_stream_disconnect(__mpStream);
326         pa_stream_unref(__mpStream);
327         __mpStream = NULL;
328     }
329
330     if (__mpContext != NULL) {
331         pa_context_disconnect(__mpContext);
332         pa_context_unref(__mpContext);
333         __mpContext = NULL;
334     }
335
336     if (__mpMainloop != NULL) {
337         pa_threaded_mainloop_free(__mpMainloop);
338         __mpMainloop = NULL;
339     }
340
341     if (__mpPropList != NULL) {
342         pa_proplist_free(__mpPropList);
343         __mpPropList = NULL;
344     }
345
346     __mIsInit = false;
347 }
348
349 int CPulseAudioClient::read(void* buffer, size_t length) throw (CAudioError) {
350     if (__mIsInit == false) {
351         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
352     }
353
354     checkRunningState();
355
356     if (buffer == NULL) {
357         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid : buffer[%p]", buffer);
358     }
359
360     if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
361         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
362     }
363
364     size_t lengthIter = length;
365     int ret = 0;
366
367     __mIsUsedSyncRead = true;
368
369     try {
370         pa_threaded_mainloop_lock(__mpMainloop);
371
372         while (lengthIter > 0) {
373             size_t l;
374
375             while (__mpSyncReadDataPtr == NULL) {
376                 ret = pa_stream_peek(__mpStream, &__mpSyncReadDataPtr, &__mSyncReadLength);
377                 if (ret != 0) {
378                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_peek() : ret[%d]", ret);
379                 }
380
381                 if (__mSyncReadLength <= 0) {
382 #ifdef _AUDIO_IO_DEBUG_TIMING_
383                     AUDIO_IO_LOGD("readLength(%d byte) is not valid. wait...", __mSyncReadLength);
384 #endif
385                     pa_threaded_mainloop_wait(__mpMainloop);
386                 } else if (__mpSyncReadDataPtr == NULL) {
387                     // Data peeked, but it doesn't have any data
388                     ret = pa_stream_drop(__mpStream);
389                     if (ret != 0) {
390                         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_drop() : ret[%d]", ret);
391                     }
392                 } else {
393                     __mSyncReadIndex = 0;
394                 }
395             }
396
397             if (__mSyncReadLength < lengthIter) {
398                 l = __mSyncReadLength;
399             } else {
400                 l = lengthIter;
401             }
402
403             // Copy partial pcm data on out parameter
404 #ifdef _AUDIO_IO_DEBUG_TIMING_
405             AUDIO_IO_LOGD("memcpy() that a peeked buffer[%], index[%d], length[%d] on out buffer", (const uint8_t*)(__mpSyncReadDataPtr) + __mSyncReadIndex, __mSyncReadIndex, l);
406 #endif
407             memcpy(buffer, (const uint8_t*)__mpSyncReadDataPtr + __mSyncReadIndex, l);
408
409             // Move next position
410             buffer = (uint8_t*)buffer + l;
411             lengthIter -= l;
412
413             // Adjusts the rest length
414             __mSyncReadIndex  += l;
415             __mSyncReadLength -= l;
416
417             if (__mSyncReadLength == 0) {
418 #ifdef _AUDIO_IO_DEBUG_TIMING_
419                 AUDIO_IO_LOGD("__mSyncReadLength is zero, do drop()");
420 #endif
421                 ret = pa_stream_drop(__mpStream);
422                 if (ret != 0) {
423                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_drop() : ret[%d]", ret);
424                 }
425
426                 // Reset the internal pointer
427                 __mpSyncReadDataPtr = NULL;
428                 __mSyncReadLength   = 0;
429                 __mSyncReadIndex    = 0;
430             }
431         }  // End of while (lengthIter > 0)
432
433         pa_threaded_mainloop_unlock(__mpMainloop);
434         __mIsUsedSyncRead = false;
435     } catch (CAudioError e) {
436         pa_threaded_mainloop_unlock(__mpMainloop);
437         __mIsUsedSyncRead = false;
438         throw e;
439     }
440
441     return length;
442 }
443
444 int CPulseAudioClient::peek(const void** buffer, size_t* length) throw (CAudioError) {
445     if (__mIsInit == false) {
446         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
447     }
448
449     checkRunningState();
450
451     if (buffer == NULL || length == NULL) {
452         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid : buffer[%p], length[%p]", buffer, length);
453     }
454
455     if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
456         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
457     }
458
459     int ret = 0;
460
461     if (isInThread() == false) {
462         pa_threaded_mainloop_lock(__mpMainloop);
463         ret = pa_stream_peek(__mpStream, buffer, length);
464         pa_threaded_mainloop_unlock(__mpMainloop);
465     } else {
466         ret = pa_stream_peek(__mpStream, buffer, length);
467     }
468
469 #ifdef _AUDIO_IO_DEBUG_TIMING_
470     AUDIO_IO_LOGD("buffer[%p], length[%d]", *buffer, *length);
471 #endif
472
473     if (ret < 0) {
474         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_peek() : err[%d]", ret);
475     }
476
477     return ret;
478 }
479
480 int CPulseAudioClient::drop() throw (CAudioError) {
481     if (__mIsInit == false) {
482         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
483     }
484
485 #ifdef _AUDIO_IO_DEBUG_TIMING_
486     AUDIO_IO_LOGD("");
487 #endif
488
489     checkRunningState();
490
491     if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
492         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
493     }
494
495     int ret = 0;
496
497     if (isInThread() == false) {
498         pa_threaded_mainloop_lock(__mpMainloop);
499         ret = pa_stream_drop(__mpStream);
500         pa_threaded_mainloop_unlock(__mpMainloop);
501     } else {
502         ret = pa_stream_drop(__mpStream);
503     }
504
505     if (ret < 0) {
506         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_drop() : err[%d]", ret);
507     }
508
509     return ret;
510 }
511
512 int CPulseAudioClient::write(const void* data, size_t length) throw (CAudioError) {
513     if (__mIsInit == false) {
514         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
515     }
516
517     checkRunningState();
518
519     if (data == NULL || length < 0) {
520         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid");
521     }
522
523     if (__mDirection == EStreamDirection::STREAM_DIRECTION_RECORD) {
524         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
525     }
526
527     int ret = 0;
528
529 #ifdef _AUDIO_IO_DEBUG_TIMING_
530     AUDIO_IO_LOGD("data[%p], length[%d]", data, length);
531 #endif
532
533     if (isInThread() == false) {
534         pa_threaded_mainloop_lock(__mpMainloop);
535         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
536         pa_threaded_mainloop_unlock(__mpMainloop);
537     } else {
538         ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
539     }
540
541     if (ret < 0) {
542         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_write() : err[%d]", ret);
543     }
544
545     return ret;
546 }
547
548 void CPulseAudioClient::cork(bool cork) throw (CAudioError) {
549     AUDIO_IO_LOGD("cork[%d]", cork);
550
551     if (__mIsInit == false) {
552         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
553     }
554
555     if (isInThread() == true) {
556         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This operation is not supported in callback");
557     }
558
559     checkRunningState();
560
561     if (isInThread() == false) {
562         pa_threaded_mainloop_lock(__mpMainloop);
563         pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
564         pa_threaded_mainloop_unlock(__mpMainloop);
565     } else {
566         pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
567     }
568
569     return;
570 }
571
572 bool CPulseAudioClient::isCorked() throw (CAudioError) {
573     if (__mIsInit == false) {
574         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
575     }
576
577     checkRunningState();
578
579     int isCork = 0;
580
581     if (isInThread() == false) {
582         pa_threaded_mainloop_lock(__mpMainloop);
583         isCork = pa_stream_is_corked(__mpStream);
584         pa_threaded_mainloop_unlock(__mpMainloop);
585     } else {
586         isCork = pa_stream_is_corked(__mpStream);
587     }
588
589     AUDIO_IO_LOGD("isCork[%d]", isCork);
590     return static_cast<bool>(isCork);
591 }
592
593 bool CPulseAudioClient::drain() throw (CAudioError) {
594     AUDIO_IO_LOGD("drain");
595
596     if (__mIsInit == false) {
597         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
598     }
599
600     checkRunningState();
601
602     if (isInThread() == false) {
603         pa_threaded_mainloop_lock(__mpMainloop);
604         pa_operation_unref(pa_stream_drain(__mpStream, __successStreamCb, this));
605         pa_threaded_mainloop_unlock(__mpMainloop);
606     } else {
607         pa_operation_unref(pa_stream_drain(__mpStream, __successStreamCb, this));
608     }
609
610     return true;
611 }
612
613 bool CPulseAudioClient::flush() throw (CAudioError) {
614     AUDIO_IO_LOGD("flush");
615
616     if (__mIsInit == false) {
617         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
618     }
619
620     checkRunningState();
621
622     if (isInThread() == false) {
623         pa_threaded_mainloop_lock(__mpMainloop);
624         pa_operation_unref(pa_stream_flush(__mpStream, __successStreamCb, this));
625         pa_threaded_mainloop_unlock(__mpMainloop);
626     } else {
627         pa_operation_unref(pa_stream_flush(__mpStream, __successStreamCb, this));
628     }
629
630     return true;
631 }
632
633 size_t CPulseAudioClient::getWritableSize() throw (CAudioError) {
634     if (__mIsInit == false) {
635         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
636     }
637
638     checkRunningState();
639
640     if (__mDirection != EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
641         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This client is used for Playback");
642     }
643
644     size_t ret = 0;
645
646     if (isInThread() == false) {
647         pa_threaded_mainloop_lock(__mpMainloop);
648         ret = pa_stream_writable_size(__mpStream);
649         pa_threaded_mainloop_unlock(__mpMainloop);
650     } else {
651         ret = pa_stream_writable_size(__mpStream);
652     }
653
654     return ret;
655 }
656
657 void CPulseAudioClient::checkRunningState() throw (CAudioError) {
658     if (__mIsInit == false) {
659         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
660     }
661
662     if (__mpContext == NULL || PA_CONTEXT_IS_GOOD(pa_context_get_state(__mpContext)) == 0) {
663         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] is not created or not good state", __mpContext);
664     }
665     if (__mpStream == NULL || PA_STREAM_IS_GOOD(pa_stream_get_state(__mpStream)) == 0) {
666         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The stream[%p] is not created or not good state", __mpStream);
667     }
668     if (pa_context_get_state(__mpContext) != PA_CONTEXT_READY || pa_stream_get_state(__mpStream)   != PA_STREAM_READY) {
669         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] or stream[%p] state is not ready", __mpContext, __mpStream);
670     }
671
672 #ifdef _AUDIO_IO_DEBUG_TIMING_
673     AUDIO_IO_LOGD("This client is running");
674 #endif
675 }
676
677 bool CPulseAudioClient::isInThread() throw (CAudioError) {
678     if (__mIsInit == false) {
679         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
680     }
681
682     int ret = pa_threaded_mainloop_in_thread(__mpMainloop);
683
684 #ifdef _AUDIO_IO_DEBUG_TIMING_
685     AUDIO_IO_LOGD("isInThread[%d]", ret);
686 #endif
687     return static_cast<bool>(ret);
688 }
689
690 size_t CPulseAudioClient::getReadableSize() throw (CAudioError) {
691     if (__mIsInit == false) {
692         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
693     }
694
695     checkRunningState();
696
697     if (__mDirection != EStreamDirection::STREAM_DIRECTION_RECORD) {
698         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This client is used for Capture");
699     }
700
701     size_t ret = 0;
702
703     if (isInThread() == false) {
704         pa_threaded_mainloop_lock(__mpMainloop);
705         ret = pa_stream_writable_size(__mpStream);
706         pa_threaded_mainloop_unlock(__mpMainloop);
707     } else {
708         ret = pa_stream_writable_size(__mpStream);
709     }
710
711     return ret;
712 }
713
714 size_t CPulseAudioClient::getBufferSize() throw (CAudioError) {
715     if (__mIsInit == false) {
716         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
717     }
718
719     checkRunningState();
720
721     size_t ret = 0;
722
723     try {
724         if (isInThread() == false) {
725             pa_threaded_mainloop_lock(__mpMainloop);
726         }
727
728         const pa_buffer_attr* attr = pa_stream_get_buffer_attr(__mpStream);
729         if (attr == NULL) {
730             int _err = pa_context_errno(__mpContext);
731             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_buffer_attr() : err[%d]", _err);
732         }
733
734         if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
735             ret = attr->tlength;
736             AUDIO_IO_LOGD("PLAYBACK buffer size[%d]", ret);
737         } else {
738             ret = attr->fragsize;
739             AUDIO_IO_LOGD("RECORD buffer size[%d]", ret);
740         }
741     } catch (CAudioError err) {
742         if (isInThread() == false) {
743             pa_threaded_mainloop_unlock(__mpMainloop);
744         }
745         throw err;
746     }
747
748     if (isInThread() == false) {
749         pa_threaded_mainloop_unlock(__mpMainloop);
750     }
751
752     return ret;
753 }
754
755 pa_usec_t CPulseAudioClient::getLatency() throw (CAudioError) {
756     if (__mIsInit == false) {
757         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
758     }
759
760     checkRunningState();
761
762     pa_usec_t ret = 0;
763     int negative  = 0;
764
765     if (isInThread() == false) {
766         if (pa_stream_get_latency(__mpStream, &ret, &negative) < 0) {
767             int _err = pa_context_errno(__mpContext);
768             if (_err != PA_ERR_NODATA) {
769                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() : err[%d]", _err);
770             }
771         }
772         return negative ? 0 : ret;
773     }
774
775     pa_threaded_mainloop_lock(__mpMainloop);
776
777     try {
778         while (true) {
779             if (pa_stream_get_latency(__mpStream, &ret, &negative) >= 0) {
780                 break;
781             }
782
783             int _err = pa_context_errno(__mpContext);
784             if (_err != PA_ERR_NODATA) {
785                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() : err[%d]", _err);
786             }
787
788             /* Wait until latency data is available again */
789             pa_threaded_mainloop_wait(__mpMainloop);
790         }
791     } catch (CAudioError e) {
792         pa_threaded_mainloop_unlock(__mpMainloop);
793         throw e;
794     }
795
796     pa_threaded_mainloop_unlock(__mpMainloop);
797
798     return negative ? 0 : ret;
799 }
800
801 pa_usec_t CPulseAudioClient::getFinalLatency() throw (CAudioError) {
802     if (__mIsInit == false) {
803         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
804     }
805
806     checkRunningState();
807
808     pa_usec_t ret = 0;
809     uint32_t  ver = 0;
810
811     try {
812         if (isInThread() == false) {
813             pa_threaded_mainloop_lock(__mpMainloop);
814         }
815
816         ver = pa_context_get_server_protocol_version(__mpContext);
817         if (ver >= 13) {
818             const pa_buffer_attr* buffer_attr = pa_stream_get_buffer_attr(__mpStream);
819             const pa_sample_spec* sample_spec = pa_stream_get_sample_spec(__mpStream);
820             const pa_timing_info* timing_info = pa_stream_get_timing_info(__mpStream);
821
822             if (buffer_attr == NULL || sample_spec == NULL || timing_info == NULL) {
823                 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",
824                         buffer_attr, sample_spec, timing_info);
825             }
826
827             if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
828                 ret = (pa_bytes_to_usec(buffer_attr->tlength, sample_spec) + timing_info->configured_sink_usec);
829                 AUDIO_IO_LOGD("FINAL PLAYBACK LATENCY[%d]", ret);
830             } else {
831                 ret = (pa_bytes_to_usec(buffer_attr->fragsize, sample_spec) + timing_info->configured_source_usec);
832                 AUDIO_IO_LOGD("FINAL RECORD LATENCY[%d]", ret);
833             }
834         } else {
835             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED, "This version(ver.%d) is not supported", ver);
836         }
837
838         if (isInThread() == false) {
839             pa_threaded_mainloop_unlock(__mpMainloop);
840         }
841     } catch (CAudioError e) {
842         if (isInThread() == false) {
843             pa_threaded_mainloop_unlock(__mpMainloop);
844         }
845         throw e;
846     }
847
848     return ret;
849 }
850
851 CPulseAudioClient::EStreamDirection CPulseAudioClient::getStreamDirection() {
852     return __mDirection;
853 }
854
855 CPulseStreamSpec CPulseAudioClient::getStreamSpec() {
856     return __mSpec;
857 }