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