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