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