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.
21 #include "CAudioIODef.h"
24 using namespace tizen_media_audio;
30 CAudioIO::CAudioIO() :
31 mpAudioSessionHandler(NULL),
32 mpPulseAudioClient(NULL),
33 __mMutex(PTHREAD_MUTEX_INITIALIZER),
34 __mCond(PTHREAD_COND_INITIALIZER),
36 __mForceIgnore(false) {
37 mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
38 mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
42 CAudioIO::CAudioIO(CAudioInfo& audioInfo) :
43 mpAudioSessionHandler(NULL),
44 mpPulseAudioClient(NULL),
45 __mMutex(PTHREAD_MUTEX_INITIALIZER),
46 __mCond(PTHREAD_COND_INITIALIZER),
48 __mForceIgnore(false) {
49 mAudioInfo = audioInfo;
50 mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
51 mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
55 CAudioIO::~CAudioIO() {
58 void CAudioIO::setInit(bool flag) {
62 bool CAudioIO::isInit() {
66 bool CAudioIO::IsReady() {
67 return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING || mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED)? true : false);
70 void CAudioIO::internalLock() throw(CAudioError) {
71 if (__mIsInit == false) {
72 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
75 if (pthread_mutex_lock(&__mMutex) != 0) {
76 THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
78 #ifdef _AUDIO_IO_DEBUG_TIMING_
79 AUDIO_IO_LOGD(COLOR_RED "LOCK" COLOR_END);
83 void CAudioIO::internalUnlock() throw(CAudioError) {
84 if (__mIsInit == false) {
85 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
88 if (pthread_mutex_unlock(&__mMutex) != 0) {
89 THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
91 #ifdef _AUDIO_IO_DEBUG_TIMING_
92 AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK" COLOR_END);
96 void CAudioIO::internalWait() throw(CAudioError) {
97 if (__mIsInit == false) {
98 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
101 #ifdef _AUDIO_IO_DEBUG_TIMING_
102 AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
105 pthread_cond_wait(&__mCond, &__mMutex);
108 void CAudioIO::internalSignal() throw(CAudioError) {
109 if (__mIsInit == false) {
110 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
113 #ifdef _AUDIO_IO_DEBUG_TIMING_
114 AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
117 pthread_cond_signal(&__mCond);
120 bool CAudioIO::isForceIgnore() {
121 return __mForceIgnore;
124 void CAudioIO::initialize() throw(CAudioError) {
125 if (__mIsInit == true) {
129 AUDIO_IO_LOGD("initialize");
131 int ret = pthread_mutex_init(&__mMutex, NULL);
133 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()");
136 ret = pthread_cond_init(&__mCond, NULL);
138 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()");
144 void CAudioIO::finalize() {
145 if (__mIsInit == false) {
149 AUDIO_IO_LOGD("finalize");
151 int ret = pthread_mutex_destroy(&__mMutex);
153 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret);
156 ret = pthread_cond_destroy(&__mCond);
158 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret);
164 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
165 assert(__mIsInit == true);
166 assert(pClient != NULL);
169 #ifdef _AUDIO_IO_DEBUG_TIMING_
170 AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
173 if (mStreamCallback.onStream != NULL) {
174 mStreamCallback.onStream(length, mStreamCallback.mUserData);
178 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
179 assert(__mIsInit == true);
180 assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
184 mByPolicy = byPolicy;
186 if (mState == mStatePrev)
189 const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
191 AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
192 state_string[(int)mStatePrev], mStatePrev, state_string[(int)mState], mState, mByPolicy);
194 if (mStateChangedCallback.onStateChanged != NULL) {
195 mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
199 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
200 onStateChanged(state, false);
203 CAudioInfo::EAudioIOState CAudioIO::getState() {
207 void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) {
210 int session_option = pHandler->getOptions();
213 ///////////////////////////////////////
214 // Triggered by 'focus watch callback'
215 ///////////////////////////////////////
217 if (session_option & (MM_SESSION_OPTION_PAUSE_OTHERS | MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
218 AUDIO_IO_LOGD("Session option is pausing others or uninterruptible, skip...");
222 if (state == FOCUS_IS_RELEASED) {
223 // Focus handle(id) of the other application was released, do resume if possible
226 mpPulseAudioClient->cork(false);
227 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
231 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
232 state = FOCUS_IS_ACQUIRED;
233 } else if (state == FOCUS_IS_ACQUIRED) {
234 // Focus handle(id) of the other application was acquired, do pause if possible
237 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
238 if (mpPulseAudioClient->drain() == false) {
239 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
243 mpPulseAudioClient->cork(true);
244 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
248 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
249 state = FOCUS_IS_RELEASED;
252 ///////////////////////////////////////
253 // Triggered by 'focus callback'
254 ///////////////////////////////////////
256 if (pHandler->getId() != id) {
257 AUDIO_IO_LOGW("Id is different, why? [mId : %d]", pHandler->getId());
260 if (session_option & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
261 AUDIO_IO_LOGD("Session option is uninterruptible, skip...");
265 if (state == FOCUS_IS_RELEASED) {
266 // Focus handle(id) was released, do pause here
269 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
270 if (mpPulseAudioClient->drain() == false) {
271 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
275 mpPulseAudioClient->cork(true);
276 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
279 } else if (state == FOCUS_IS_ACQUIRED) {
280 // Focus handle(id) was acquired again,
281 // check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...)
282 // do resume here and call interrupt completed callback to application.
285 mpPulseAudioClient->cork(false);
286 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
292 if (mInterruptCallback.onInterrupt != NULL) {
293 IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::EInterruptCode::INTERRUPT_COMPLETED;
294 e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change);
295 mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData);
299 void CAudioIO::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
302 if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
303 if (value == 1 && pHandler->getSubscribeId() > 0) {
304 // Unregister focus watch callback & disable session handler
305 pHandler->disableSessionHandler();
306 AUDIO_IO_LOGD("Session handler disabled by signal");
307 } else if (value == 0) {
308 // Currently do nothing...
313 void CAudioIO::prepare() throw(CAudioError) {
314 if (__mIsInit == false) {
315 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
319 AUDIO_IO_LOGD("------> prepare done");
321 } catch (CAudioError e) {
326 void CAudioIO::unprepare() throw(CAudioError) {
327 if (__mIsInit == false) {
328 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
332 AUDIO_IO_LOGD("unprepare ----->");
334 } catch (CAudioError e) {
339 void CAudioIO::pause() throw(CAudioError) {
340 if (__mIsInit == false || IsReady() == false) {
341 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
346 AUDIO_IO_LOGD("pause");
347 mpPulseAudioClient->cork(true);
349 } catch (CAudioError e) {
355 void CAudioIO::resume() throw(CAudioError) {
356 if (__mIsInit == false || IsReady() == false) {
357 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
362 AUDIO_IO_LOGD("resume");
363 mpPulseAudioClient->cork(false);
365 } catch (CAudioError e) {
371 void CAudioIO::drain() throw(CAudioError) {
372 if (__mIsInit == false || IsReady() == false) {
373 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
377 if (mpPulseAudioClient->isInThread()) {
378 mpPulseAudioClient->drain();
381 mpPulseAudioClient->drain();
384 } catch (CAudioError e) {
385 if (!mpPulseAudioClient->isInThread()) {
392 void CAudioIO::flush() throw(CAudioError) {
393 if (__mIsInit == false || IsReady() == false) {
394 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
398 if (mpPulseAudioClient->isInThread()) {
399 mpPulseAudioClient->flush();
402 mpPulseAudioClient->flush();
405 } catch (CAudioError e) {
406 if (!mpPulseAudioClient->isInThread()) {
413 CAudioInfo& CAudioIO::getAudioInfo() throw(CAudioError) {
414 if (__mIsInit == false) {
415 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
421 void CAudioIO::setStreamCallback(SStreamCallback callback) throw(CAudioError) {
422 if (__mIsInit == false) {
423 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
426 mStreamCallback = callback;
429 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() throw(CAudioError) {
430 if (__mIsInit == false) {
431 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
434 return mStreamCallback;
437 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) throw(CAudioError) {
438 if (__mIsInit == false) {
439 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
442 mStateChangedCallback = callback;
445 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() throw(CAudioError) {
446 if (__mIsInit == false) {
447 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
450 return mStateChangedCallback;
453 void CAudioIO::setInterruptCallback(SInterruptCallback callback) throw(CAudioError) {
454 if (__mIsInit == false) {
455 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
458 mInterruptCallback = callback;
461 CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() throw(CAudioError) {
462 if (__mIsInit == false) {
463 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
466 return mInterruptCallback;
470 void CAudioIO::ignoreSession() throw(CAudioError) {
471 if (__mIsInit == false)
472 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
477 if (mpPulseAudioClient != NULL && mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING)
478 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "An Operation is not permitted while started");
480 bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
481 if (isSkip == false && mpAudioSessionHandler->getId() >= 0)
482 mpAudioSessionHandler->unregisterSound();
484 mpAudioSessionHandler->finalize();
485 __mForceIgnore = true;
488 } catch (CAudioError e) {