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.
20 #include "CAudioIODef.h"
21 #include <sound_manager_internal.h>
26 using namespace tizen_media_audio;
33 CAudioIO::CAudioIO() :
34 mpPulseAudioClient(nullptr),
35 __mMutex(PTHREAD_MUTEX_INITIALIZER),
36 __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
37 __mCond(PTHREAD_COND_INITIALIZER),
39 mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
40 mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
41 mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
46 CAudioIO::CAudioIO(CAudioInfo& audioInfo) :
47 mpPulseAudioClient(nullptr),
48 __mMutex(PTHREAD_MUTEX_INITIALIZER),
49 __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
50 __mCond(PTHREAD_COND_INITIALIZER),
52 mAudioInfo = audioInfo;
53 mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
54 mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
55 mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
59 void CAudioIO::setInit(bool flag) {
63 bool CAudioIO::isInit() {
67 bool CAudioIO::IsReady() {
68 return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING ||
69 mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED));
72 void CAudioIO::internalLock() {
74 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
76 if (pthread_mutex_lock(&__mMutex) != 0)
77 THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); //LCOV_EXCL_LINE
79 #ifdef _AUDIO_IO_DEBUG_TIMING_
80 AUDIO_IO_LOGD(COLOR_RED "%p LOCKED" COLOR_END, &__mMutex);
84 void CAudioIO::internalUnlock() {
86 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
88 if (pthread_mutex_unlock(&__mMutex) != 0)
89 THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); //LCOV_EXCL_LINE
91 #ifdef _AUDIO_IO_DEBUG_TIMING_
92 AUDIO_IO_LOGD(COLOR_GREEN "%p UNLOCKED" COLOR_END, &__mMutex);
96 void CAudioIO::internalWait() {
98 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
100 #ifdef _AUDIO_IO_DEBUG_TIMING_
101 AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
103 pthread_mutex_lock(&__mCondMutex);
105 struct timeval now = { 0, };
106 struct timeval to_wait = { 0, };
107 struct timeval until = { 0, };
108 struct timespec until_ts = { 0, };
110 constexpr int COND_TIMEOUT_MS = 200;
112 gettimeofday(&now, nullptr);
113 to_wait.tv_sec = COND_TIMEOUT_MS / 1000UL;
114 to_wait.tv_usec = (COND_TIMEOUT_MS % 1000UL) * 1000UL;
115 timeradd(&now, &to_wait, &until);
116 until_ts.tv_sec = until.tv_sec;
117 until_ts.tv_nsec = until.tv_usec * 1000UL;
119 if (pthread_cond_timedwait(&__mCond, &__mCondMutex, &until_ts) != 0) {
121 AUDIO_IO_LOGE("pthread_cond_timedwait error=%s", strerror_r(errno, str_error, sizeof(str_error)));
124 pthread_mutex_unlock(&__mCondMutex);
127 void CAudioIO::internalSignal() {
129 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
131 #ifdef _AUDIO_IO_DEBUG_TIMING_
132 AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
135 pthread_mutex_lock(&__mCondMutex);
136 pthread_cond_signal(&__mCond);
137 pthread_mutex_unlock(&__mCondMutex);
140 void CAudioIO::initialize() {
144 AUDIO_IO_LOGD("initialize");
146 int ret = pthread_mutex_init(&__mMutex, NULL);
148 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()"); //LCOV_EXCL_LINE
150 ret = pthread_cond_init(&__mCond, NULL);
152 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()"); //LCOV_EXCL_LINE
157 void CAudioIO::finalize() {
161 AUDIO_IO_LOGD("finalize");
163 bool error_occured = false;
164 int ret = pthread_mutex_destroy(&__mMutex);
167 AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mMutex, ret);
168 error_occured = true;
172 ret = pthread_mutex_destroy(&__mCondMutex);
175 AUDIO_IO_LOGE("Failed cond pthread_mutex_destroy(%p) errno:%d", &__mCondMutex, ret);
176 error_occured = true;
180 ret = pthread_cond_destroy(&__mCond);
183 AUDIO_IO_LOGE("Failed pthread_cond_destroy(%p) errno:%d", &__mCond, ret);
184 error_occured = true;
189 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Finalize Failed"); //LCOV_EXCL_LINE
194 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
199 #ifdef _AUDIO_IO_DEBUG_TIMING_
200 AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
203 if (mStreamCallback.onStream)
204 mStreamCallback.onStream(length, mStreamCallback.mUserData);
207 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
209 assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
213 mByPolicy = byPolicy;
215 if (mState == mStatePrev)
218 static const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
220 AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
221 state_string[static_cast<int>(mStatePrev)],
222 static_cast<int>(mStatePrev),
223 state_string[static_cast<int>(mState)],
224 static_cast<int>(mState),
227 if (mStateChangedCallback.onStateChanged)
228 mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
231 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
232 onStateChanged(state, false);
235 CAudioInfo::EAudioIOState CAudioIO::getState() noexcept {
239 void CAudioIO::prepare() {
241 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
244 void CAudioIO::unprepare() {
246 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
249 void CAudioIO::pause() {
250 if (!__mIsInit || !IsReady())
251 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
255 AUDIO_IO_LOGD("pause");
256 mpPulseAudioClient->cork(true);
258 } catch (const CAudioError& e) {
264 void CAudioIO::resume() {
265 if (!__mIsInit || !IsReady())
266 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
270 AUDIO_IO_LOGD("resume");
271 mpPulseAudioClient->cork(false);
273 } catch (const CAudioError& e) {
279 void CAudioIO::drain() {
280 if (!__mIsInit || !IsReady())
281 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
284 if (mpPulseAudioClient->isInThread()) {
285 mpPulseAudioClient->drain();
288 mpPulseAudioClient->drain();
291 } catch (const CAudioError& e) {
292 if (!mpPulseAudioClient->isInThread())
298 void CAudioIO::flush() {
299 if (!__mIsInit || !IsReady())
300 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
303 if (mpPulseAudioClient->isInThread()) {
304 mpPulseAudioClient->flush();
307 mpPulseAudioClient->flush();
310 } catch (const CAudioError& e) {
311 if (!mpPulseAudioClient->isInThread())
317 CAudioInfo& CAudioIO::getAudioInfo() {
319 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
324 void CAudioIO::setStreamCallback(SStreamCallback callback) {
326 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
328 mStreamCallback = callback;
331 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
333 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
335 return mStreamCallback;
338 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
340 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
342 mStateChangedCallback = callback;
345 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
347 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
349 return mStateChangedCallback;
352 void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
354 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL"); //LCOV_EXCL_LINE
357 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
359 if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
360 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started"); //LCOV_EXCL_LINE
362 int errorCode = SOUND_MANAGER_ERROR_NONE;
363 char *type = nullptr;
367 if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
368 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
370 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported"); //LCOV_EXCL_LINE
372 if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
373 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
374 if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
375 getAudioInfo().setAudioTypeByInputStreamType(type);
377 getAudioInfo().setAudioTypeByOutputStreamType(type);
379 if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
380 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
381 getAudioInfo().setAudioIndex(index);