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