2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "CAudioIODef.h"
23 using namespace tizen_media_audio;
27 * class CPulseAudioClient
29 const char* CPulseAudioClient::CLIENT_NAME = "AUDIO_IO_PA_CLIENT";
31 CPulseAudioClient::CPulseAudioClient(
32 EStreamDirection direction,
33 CPulseStreamSpec& spec,
34 IPulseStreamListener* listener) :
35 __mDirection(direction),
37 __mpListener(listener),
43 __mIsOperationSuccess(false),
44 __mpSyncReadDataPtr(NULL),
47 __mIsUsedSyncRead(false) {
50 CPulseAudioClient::~CPulseAudioClient() {
54 void CPulseAudioClient::__contextStateChangeCb(pa_context* c, void* user_data) {
55 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
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);
65 case PA_CONTEXT_FAILED:
66 case PA_CONTEXT_TERMINATED:
67 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
70 case PA_CONTEXT_UNCONNECTED:
71 case PA_CONTEXT_CONNECTING:
72 case PA_CONTEXT_AUTHORIZING:
73 case PA_CONTEXT_SETTING_NAME:
78 void CPulseAudioClient::__successContextCb(pa_context* c, int success, void* user_data) {
79 AUDIO_IO_LOGD("pa_context[%p], success[%d], user_data[%p]", c, success, user_data);
83 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
84 pClient->__mIsOperationSuccess = static_cast<bool>(success);
86 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
89 void CPulseAudioClient::__streamStateChangeCb(pa_stream* s, void* user_data) {
93 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
95 switch (pa_stream_get_state(s)) {
97 AUDIO_IO_LOGD("The stream is ready!");
98 pClient->__mpListener->onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
99 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
102 case PA_STREAM_FAILED:
103 case PA_STREAM_TERMINATED:
104 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
107 case PA_STREAM_UNCONNECTED:
108 case PA_STREAM_CREATING:
113 void CPulseAudioClient::__streamCaptureCb(pa_stream* s, size_t length, void* user_data) {
117 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
118 assert(pClient->__mpListener);
119 assert(pClient->__mpMainloop);
121 if (pClient->__mIsUsedSyncRead == true) {
122 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
125 pClient->__mpListener->onStream(pClient, length);
128 void CPulseAudioClient::__streamPlaybackCb(pa_stream* s, size_t length, void* user_data) {
132 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
133 assert(pClient->__mpListener);
135 if (pClient->__mIsInit == false) {
136 AUDIO_IO_LOGD("Occurred this listener when an out stream is on the way to create : Write dummy, length[%d]", length);
138 char* dummy = new char[length];
139 memset(dummy, 0, length);
140 pa_stream_write(s, dummy, length, NULL, 0LL, PA_SEEK_RELATIVE);
146 pClient->__mpListener->onStream(pClient, length);
149 void CPulseAudioClient::__streamLatencyUpdateCb(pa_stream* s, void* user_data) {
153 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
155 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
158 void CPulseAudioClient::__successStreamCb(pa_stream* s, int success, void* user_data) {
159 AUDIO_IO_LOGD("pa_stream[%p], success[%d], user_data[%p]", s, success, user_data);
163 CPulseAudioClient* pClient = static_cast<CPulseAudioClient*>(user_data);
164 pClient->__mIsOperationSuccess = static_cast<bool>(success);
166 pa_threaded_mainloop_signal(pClient->__mpMainloop, 0);
169 void CPulseAudioClient::initialize() throw(CAudioError) {
171 if (__mIsInit == true) {
179 // Allocates PA proplist
180 __mpPropList = pa_proplist_new();
181 if (__mpPropList == NULL) {
182 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_proplist_new()");
185 // Adds values on proplist for delivery to PULSEAUDIO
186 char *streamType = NULL;
187 CAudioInfo::EAudioType audioType = __mSpec.getAudioInfo().getAudioType();
188 __mSpec.getAudioInfo().convertAudioType2StreamType(audioType, &streamType);
189 pa_proplist_sets(__mpPropList, PA_PROP_MEDIA_ROLE, streamType);
191 int index = __mSpec.getAudioInfo().getAudioIndex();
193 pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_PARENT_ID, "%u", (unsigned int) index);
196 // Adds latency on proplist for delivery to PULSEAUDIO
197 AUDIO_IO_LOGD("LATENCY : %s[%d]", __mSpec.getStreamLatencyToString(), __mSpec.getStreamLatency());
198 pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, "%s", __mSpec.getStreamLatencyToString());
200 // Allocates PA mainloop
201 __mpMainloop = pa_threaded_mainloop_new();
202 if (__mpMainloop == NULL) {
203 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_threaded_mainloop_new()");
206 // Allocates PA context
207 __mpContext = pa_context_new(pa_threaded_mainloop_get_api(__mpMainloop), CLIENT_NAME);
208 if (__mpContext == NULL) {
209 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_new()");
212 // Sets context state changed callback
213 pa_context_set_state_callback(__mpContext, __contextStateChangeCb, this);
215 // Connects this client with PA server
216 if (pa_context_connect(__mpContext, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) {
217 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_connect()");
220 // LOCK for synchronous connection
221 pa_threaded_mainloop_lock(__mpMainloop);
224 if (pa_threaded_mainloop_start(__mpMainloop) < 0) {
225 pa_threaded_mainloop_unlock(__mpMainloop);
226 THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_threaded_mainloop_start()");
229 // Connection process is asynchronously
230 // So, this function will be waited when occurred context state change event
231 // If I got a signal, do next processing
233 pa_context_state_t state;
234 state = pa_context_get_state(__mpContext);
236 if (state == PA_CONTEXT_READY) {
240 if (!PA_CONTEXT_IS_GOOD(state)) {
241 err = pa_context_errno(__mpContext);
242 pa_threaded_mainloop_unlock(__mpMainloop);
243 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_context's state is not good : err[%d]", err);
246 /* Wait until the context is ready */
247 pa_threaded_mainloop_wait(__mpMainloop);
250 // Allocates PA stream
251 pa_sample_spec ss = __mSpec.getSampleSpec();
252 pa_channel_map map = __mSpec.getChannelMap();
254 __mpStream = pa_stream_new_with_proplist(__mpContext, __mSpec.getStreamName(), &ss, &map, __mpPropList);
255 if (__mpStream == NULL) {
256 pa_threaded_mainloop_unlock(__mpMainloop);
257 THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_new_with_proplist()");
260 // Sets stream callbacks
261 pa_stream_set_state_callback(__mpStream, __streamStateChangeCb, this);
262 pa_stream_set_read_callback(__mpStream, __streamCaptureCb, this);
263 pa_stream_set_write_callback(__mpStream, __streamPlaybackCb, this);
264 pa_stream_set_latency_update_callback(__mpStream, __streamLatencyUpdateCb, this);
266 // Connect stream with PA Server
268 if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
269 pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(
270 PA_STREAM_INTERPOLATE_TIMING |
271 PA_STREAM_ADJUST_LATENCY |
272 PA_STREAM_AUTO_TIMING_UPDATE);
274 ret = pa_stream_connect_playback(__mpStream, NULL, NULL, flags, NULL, NULL);
276 pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(
277 PA_STREAM_INTERPOLATE_TIMING |
278 PA_STREAM_ADJUST_LATENCY |
279 PA_STREAM_AUTO_TIMING_UPDATE);
281 ret = pa_stream_connect_record(__mpStream, NULL, NULL, flags);
285 err = pa_context_errno(__mpContext);
286 pa_threaded_mainloop_unlock(__mpMainloop);
287 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_connect() : err[%d]", err);
291 pa_stream_state_t state;
292 state = pa_stream_get_state(__mpStream);
294 if (state == PA_STREAM_READY) {
295 AUDIO_IO_LOGD("STREAM READY");
299 if (!PA_STREAM_IS_GOOD(state)) {
300 err = pa_context_errno(__mpContext);
301 pa_threaded_mainloop_unlock(__mpMainloop);
302 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_stream's state is not good : err[%d]", err);
305 /* Wait until the stream is ready */
306 pa_threaded_mainloop_wait(__mpMainloop);
309 // End of synchronous
310 pa_threaded_mainloop_unlock(__mpMainloop);
313 } catch (CAudioError e) {
319 void CPulseAudioClient::finalize() {
321 if (__mIsInit == false) {
325 if (__mpMainloop != NULL) {
326 pa_threaded_mainloop_stop(__mpMainloop);
329 if (__mpStream != NULL) {
330 pa_stream_disconnect(__mpStream);
331 pa_stream_unref(__mpStream);
335 if (__mpContext != NULL) {
336 pa_context_disconnect(__mpContext);
337 pa_context_unref(__mpContext);
341 if (__mpMainloop != NULL) {
342 pa_threaded_mainloop_free(__mpMainloop);
346 if (__mpPropList != NULL) {
347 pa_proplist_free(__mpPropList);
354 int CPulseAudioClient::read(void* buffer, size_t length) throw(CAudioError) {
355 if (__mIsInit == false) {
356 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
361 if (buffer == NULL) {
362 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid : buffer[%p]", buffer);
365 if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
366 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
369 size_t lengthIter = length;
372 __mIsUsedSyncRead = true;
375 pa_threaded_mainloop_lock(__mpMainloop);
377 while (lengthIter > 0) {
380 while (__mpSyncReadDataPtr == NULL) {
381 ret = pa_stream_peek(__mpStream, &__mpSyncReadDataPtr, &__mSyncReadLength);
383 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_peek() : ret[%d]", ret);
386 if (__mSyncReadLength <= 0) {
387 #ifdef _AUDIO_IO_DEBUG_TIMING_
388 AUDIO_IO_LOGD("readLength(%d byte) is not valid. wait...", __mSyncReadLength);
390 pa_threaded_mainloop_wait(__mpMainloop);
391 } else if (__mpSyncReadDataPtr == NULL) {
392 // Data peeked, but it doesn't have any data
393 ret = pa_stream_drop(__mpStream);
395 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_drop() : ret[%d]", ret);
398 __mSyncReadIndex = 0;
402 if (__mSyncReadLength < lengthIter) {
403 l = __mSyncReadLength;
408 // Copy partial pcm data on out parameter
409 #ifdef _AUDIO_IO_DEBUG_TIMING_
410 AUDIO_IO_LOGD("memcpy() that a peeked buffer[%], index[%d], length[%d] on out buffer", (const uint8_t*)(__mpSyncReadDataPtr) + __mSyncReadIndex, __mSyncReadIndex, l);
412 memcpy(buffer, (const uint8_t*)__mpSyncReadDataPtr + __mSyncReadIndex, l);
414 // Move next position
415 buffer = (uint8_t*)buffer + l;
418 // Adjusts the rest length
419 __mSyncReadIndex += l;
420 __mSyncReadLength -= l;
422 if (__mSyncReadLength == 0) {
423 #ifdef _AUDIO_IO_DEBUG_TIMING_
424 AUDIO_IO_LOGD("__mSyncReadLength is zero, do drop()");
426 ret = pa_stream_drop(__mpStream);
428 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pa_stream_drop() : ret[%d]", ret);
431 // Reset the internal pointer
432 __mpSyncReadDataPtr = NULL;
433 __mSyncReadLength = 0;
434 __mSyncReadIndex = 0;
436 } // End of while (lengthIter > 0)
438 pa_threaded_mainloop_unlock(__mpMainloop);
439 __mIsUsedSyncRead = false;
440 } catch (CAudioError e) {
441 pa_threaded_mainloop_unlock(__mpMainloop);
442 __mIsUsedSyncRead = false;
449 int CPulseAudioClient::peek(const void** buffer, size_t* length) throw(CAudioError) {
450 if (__mIsInit == false) {
451 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
456 if (buffer == NULL || length == NULL) {
457 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid : buffer[%p], length[%p]", buffer, length);
460 if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
461 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
466 if (isInThread() == false) {
467 pa_threaded_mainloop_lock(__mpMainloop);
468 ret = pa_stream_peek(__mpStream, buffer, length);
469 pa_threaded_mainloop_unlock(__mpMainloop);
471 ret = pa_stream_peek(__mpStream, buffer, length);
474 #ifdef _AUDIO_IO_DEBUG_TIMING_
475 AUDIO_IO_LOGD("buffer[%p], length[%d]", *buffer, *length);
479 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_peek() : err[%d]", ret);
485 int CPulseAudioClient::drop() throw(CAudioError) {
486 if (__mIsInit == false) {
487 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
490 #ifdef _AUDIO_IO_DEBUG_TIMING_
496 if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
497 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
502 if (isInThread() == false) {
503 pa_threaded_mainloop_lock(__mpMainloop);
504 ret = pa_stream_drop(__mpStream);
505 pa_threaded_mainloop_unlock(__mpMainloop);
507 ret = pa_stream_drop(__mpStream);
511 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_drop() : err[%d]", ret);
517 int CPulseAudioClient::write(const void* data, size_t length) throw(CAudioError) {
518 if (__mIsInit == false) {
519 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
525 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The parameter is invalid");
528 if (__mDirection == EStreamDirection::STREAM_DIRECTION_RECORD) {
529 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function");
534 #ifdef _AUDIO_IO_DEBUG_TIMING_
535 AUDIO_IO_LOGD("data[%p], length[%d]", data, length);
538 if (isInThread() == false) {
539 pa_threaded_mainloop_lock(__mpMainloop);
540 ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
541 pa_threaded_mainloop_unlock(__mpMainloop);
543 ret = pa_stream_write(__mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
547 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_write() : err[%d]", ret);
553 void CPulseAudioClient::cork(bool cork) throw(CAudioError) {
554 AUDIO_IO_LOGD("cork[%d]", cork);
556 if (__mIsInit == false) {
557 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
560 if (isInThread() == true) {
561 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This operation is not supported in callback");
566 if (isInThread() == false) {
567 pa_threaded_mainloop_lock(__mpMainloop);
568 pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
569 pa_threaded_mainloop_unlock(__mpMainloop);
571 pa_operation_unref(pa_stream_cork(__mpStream, static_cast<int>(cork), __successStreamCb, this));
577 bool CPulseAudioClient::isCorked() throw(CAudioError) {
578 if (__mIsInit == false) {
579 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
586 if (isInThread() == false) {
587 pa_threaded_mainloop_lock(__mpMainloop);
588 isCork = pa_stream_is_corked(__mpStream);
589 pa_threaded_mainloop_unlock(__mpMainloop);
591 isCork = pa_stream_is_corked(__mpStream);
594 AUDIO_IO_LOGD("isCork[%d]", isCork);
595 return static_cast<bool>(isCork);
598 bool CPulseAudioClient::drain() throw(CAudioError) {
599 AUDIO_IO_LOGD("drain");
601 if (__mIsInit == false) {
602 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
607 if (isInThread() == false) {
608 pa_threaded_mainloop_lock(__mpMainloop);
609 pa_operation_unref(pa_stream_drain(__mpStream, __successStreamCb, this));
610 pa_threaded_mainloop_unlock(__mpMainloop);
612 pa_operation_unref(pa_stream_drain(__mpStream, __successStreamCb, this));
618 bool CPulseAudioClient::flush() throw(CAudioError) {
619 AUDIO_IO_LOGD("flush");
621 if (__mIsInit == false) {
622 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
627 if (isInThread() == false) {
628 pa_threaded_mainloop_lock(__mpMainloop);
629 pa_operation_unref(pa_stream_flush(__mpStream, __successStreamCb, this));
630 pa_threaded_mainloop_unlock(__mpMainloop);
632 pa_operation_unref(pa_stream_flush(__mpStream, __successStreamCb, this));
638 size_t CPulseAudioClient::getWritableSize() throw(CAudioError) {
639 if (__mIsInit == false) {
640 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
645 if (__mDirection != EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
646 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This client is used for Playback");
651 if (isInThread() == false) {
652 pa_threaded_mainloop_lock(__mpMainloop);
653 ret = pa_stream_writable_size(__mpStream);
654 pa_threaded_mainloop_unlock(__mpMainloop);
656 ret = pa_stream_writable_size(__mpStream);
662 void CPulseAudioClient::checkRunningState() throw(CAudioError) {
663 if (__mIsInit == false) {
664 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
667 if (__mpContext == NULL || PA_CONTEXT_IS_GOOD(pa_context_get_state(__mpContext)) == 0) {
668 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] is not created or not good state", __mpContext);
670 if (__mpStream == NULL || PA_STREAM_IS_GOOD(pa_stream_get_state(__mpStream)) == 0) {
671 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The stream[%p] is not created or not good state", __mpStream);
673 if (pa_context_get_state(__mpContext) != PA_CONTEXT_READY || pa_stream_get_state(__mpStream) != PA_STREAM_READY) {
674 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_INITIALIZED, "The context[%p] or stream[%p] state is not ready", __mpContext, __mpStream);
677 #ifdef _AUDIO_IO_DEBUG_TIMING_
678 AUDIO_IO_LOGD("This client is running");
682 bool CPulseAudioClient::isInThread() throw(CAudioError) {
683 if (__mIsInit == false) {
684 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
687 int ret = pa_threaded_mainloop_in_thread(__mpMainloop);
689 #ifdef _AUDIO_IO_DEBUG_TIMING_
690 AUDIO_IO_LOGD("isInThread[%d]", ret);
692 return static_cast<bool>(ret);
695 size_t CPulseAudioClient::getReadableSize() throw(CAudioError) {
696 if (__mIsInit == false) {
697 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
702 if (__mDirection != EStreamDirection::STREAM_DIRECTION_RECORD) {
703 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "This client is used for Capture");
708 if (isInThread() == false) {
709 pa_threaded_mainloop_lock(__mpMainloop);
710 ret = pa_stream_writable_size(__mpStream);
711 pa_threaded_mainloop_unlock(__mpMainloop);
713 ret = pa_stream_writable_size(__mpStream);
719 size_t CPulseAudioClient::getBufferSize() throw(CAudioError) {
720 if (__mIsInit == false) {
721 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
729 if (isInThread() == false) {
730 pa_threaded_mainloop_lock(__mpMainloop);
733 const pa_buffer_attr* attr = pa_stream_get_buffer_attr(__mpStream);
735 int _err = pa_context_errno(__mpContext);
736 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_buffer_attr() : err[%d]", _err);
739 if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
741 AUDIO_IO_LOGD("PLAYBACK buffer size[%d]", ret);
743 ret = attr->fragsize;
744 AUDIO_IO_LOGD("RECORD buffer size[%d]", ret);
746 } catch (CAudioError err) {
747 if (isInThread() == false) {
748 pa_threaded_mainloop_unlock(__mpMainloop);
753 if (isInThread() == false) {
754 pa_threaded_mainloop_unlock(__mpMainloop);
760 pa_usec_t CPulseAudioClient::getLatency() throw(CAudioError) {
761 if (__mIsInit == false) {
762 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
770 if (isInThread() == false) {
771 if (pa_stream_get_latency(__mpStream, &ret, &negative) < 0) {
772 int _err = pa_context_errno(__mpContext);
773 if (_err != PA_ERR_NODATA) {
774 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() : err[%d]", _err);
777 return negative ? 0 : ret;
780 pa_threaded_mainloop_lock(__mpMainloop);
784 if (pa_stream_get_latency(__mpStream, &ret, &negative) >= 0) {
788 int _err = pa_context_errno(__mpContext);
789 if (_err != PA_ERR_NODATA) {
790 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() : err[%d]", _err);
793 /* Wait until latency data is available again */
794 pa_threaded_mainloop_wait(__mpMainloop);
796 } catch (CAudioError e) {
797 pa_threaded_mainloop_unlock(__mpMainloop);
801 pa_threaded_mainloop_unlock(__mpMainloop);
803 return negative ? 0 : ret;
806 pa_usec_t CPulseAudioClient::getFinalLatency() throw(CAudioError) {
807 if (__mIsInit == false) {
808 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient");
817 if (isInThread() == false) {
818 pa_threaded_mainloop_lock(__mpMainloop);
821 ver = pa_context_get_server_protocol_version(__mpContext);
823 const pa_buffer_attr* buffer_attr = pa_stream_get_buffer_attr(__mpStream);
824 const pa_sample_spec* sample_spec = pa_stream_get_sample_spec(__mpStream);
825 const pa_timing_info* timing_info = pa_stream_get_timing_info(__mpStream);
827 if (buffer_attr == NULL || sample_spec == NULL || timing_info == NULL) {
828 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to get buffer_attr[%p] or sample_spec[%p] or timing_info[%p] from a pa_stream",
829 buffer_attr, sample_spec, timing_info);
832 if (__mDirection == EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
833 ret = (pa_bytes_to_usec(buffer_attr->tlength, sample_spec) + timing_info->configured_sink_usec);
834 AUDIO_IO_LOGD("FINAL PLAYBACK LATENCY[%d]", ret);
836 ret = (pa_bytes_to_usec(buffer_attr->fragsize, sample_spec) + timing_info->configured_source_usec);
837 AUDIO_IO_LOGD("FINAL RECORD LATENCY[%d]", ret);
840 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED, "This version(ver.%d) is not supported", ver);
843 if (isInThread() == false) {
844 pa_threaded_mainloop_unlock(__mpMainloop);
846 } catch (CAudioError e) {
847 if (isInThread() == false) {
848 pa_threaded_mainloop_unlock(__mpMainloop);
856 CPulseAudioClient::EStreamDirection CPulseAudioClient::getStreamDirection() {
860 CPulseStreamSpec CPulseAudioClient::getStreamSpec() {