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 <audio-session-manager.h>
22 #include "CAudioIODef.h"
24 #define AUDIO_IO_DEBUG
27 using namespace tizen_media_audio;
33 CAudioIO::CAudioIO() : mIsInit(false), mForceIgnore(false), mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL) {
34 mState = CAudioInfo::AUDIO_IO_STATE_NONE;
35 mStatePrev = CAudioInfo::AUDIO_IO_STATE_NONE;
39 CAudioIO::CAudioIO(CAudioInfo& audioInfo) : mIsInit(false), mForceIgnore(false), mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL) {
40 mAudioInfo = audioInfo;
41 mState = CAudioInfo::AUDIO_IO_STATE_NONE;
42 mStatePrev = CAudioInfo::AUDIO_IO_STATE_NONE;
46 CAudioIO::~CAudioIO() {
49 void CAudioIO::setInit(bool flag) {
53 bool CAudioIO::isInit() {
57 bool CAudioIO::IsReady() {
58 return ((mState == CAudioInfo::AUDIO_IO_STATE_RUNNING || mState == CAudioInfo::AUDIO_IO_STATE_PAUSED)? true : false);
61 void CAudioIO::internalLock() throw (CAudioError) {
62 if (mIsInit == false) {
63 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
66 if (pthread_mutex_lock(&mMutex) != 0) {
67 THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
69 #ifdef _AUDIO_IO_DEBUG_TIMING_
70 AUDIO_IO_LOGD(COLOR_RED"LOCK"COLOR_END);
74 void CAudioIO::internalUnlock() throw (CAudioError) {
75 if (mIsInit == false) {
76 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
79 if (pthread_mutex_unlock(&mMutex) != 0) {
80 THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
82 #ifdef _AUDIO_IO_DEBUG_TIMING_
83 AUDIO_IO_LOGD(COLOR_GREEN"UNLOCK"COLOR_END);
87 void CAudioIO::internalWait() throw (CAudioError) {
88 if (mIsInit == false) {
89 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
92 #ifdef _AUDIO_IO_DEBUG_TIMING_
93 AUDIO_IO_LOGD(COLOR_RED"WAIT"COLOR_END);
96 pthread_cond_wait(&mCond, &mMutex);
99 void CAudioIO::internalSignal() throw (CAudioError) {
100 if (mIsInit == false) {
101 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
104 #ifdef _AUDIO_IO_DEBUG_TIMING_
105 AUDIO_IO_LOGD(COLOR_GREEN"SIGNAL"COLOR_END);
108 pthread_cond_signal(&mCond);
111 bool CAudioIO::isForceIgnore() {
115 void CAudioIO::initialize() throw (CAudioError) {
116 if (mIsInit == true) {
120 AUDIO_IO_LOGD("initialize");
122 int ret = pthread_mutex_init(&mMutex, NULL);
124 THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()");
127 ret = pthread_cond_init(&mCond, NULL);
129 THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()");
135 void CAudioIO::finalize() {
136 if (mIsInit == false) {
140 AUDIO_IO_LOGD("finalize");
142 int ret = pthread_mutex_destroy(&mMutex);
144 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret);
147 ret = pthread_cond_destroy(&mCond);
149 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret);
155 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
156 assert(mIsInit == true);
157 assert(pClient != NULL);
160 if (mStreamCallback.onStream != NULL) {
161 mStreamCallback.onStream(length, mStreamCallback.mUserData);
165 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
166 assert(mIsInit == true);
171 mByPolicy = byPolicy;
173 AUDIO_IO_LOGD("current(%d), previous(%d), by_policy(%d)", mState, mStatePrev, mByPolicy);
175 if (mStateChangedCallback.onStateChanged != NULL) {
176 mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
180 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
181 onStateChanged(state, false);
184 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) {
187 int session_option = pHandler->getOptions();
190 ///////////////////////////////////////
191 // Triggered by 'focus watch callback'
192 ///////////////////////////////////////
194 if (session_option & (ASM_SESSION_OPTION_PAUSE_OTHERS | ASM_SESSION_OPTION_UNINTERRUPTIBLE)) {
195 AUDIO_IO_LOGD("Session option is pausing others or uninterruptible, skip...");
199 if (state == FOCUS_IS_RELEASED) {
200 // Focus handle(id) of the other application was released, do resume if possible
203 mpPulseAudioClient->cork(false);
204 onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING);
208 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
209 state = FOCUS_IS_ACQUIRED;
210 } else if (state == FOCUS_IS_ACQUIRED) {
211 // Focus handle(id) of the other application was acquired, do pause if possible
213 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::STREAM_DIRECTION_PLAYBACK) {
214 if (mpPulseAudioClient->drain() == false) {
215 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
219 mpPulseAudioClient->cork(true);
220 onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED);
224 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
225 state = FOCUS_IS_RELEASED;
228 ///////////////////////////////////////
229 // Triggered by 'focus callback'
230 ///////////////////////////////////////
232 if (pHandler->getId() != id) {
233 AUDIO_IO_LOGW("Id is different, why? [mId : %d]", pHandler->getId());
236 if (session_option & ASM_SESSION_OPTION_UNINTERRUPTIBLE) {
237 AUDIO_IO_LOGD("Session option is uninterruptible, skip...");
241 if (state == FOCUS_IS_RELEASED) {
242 // Focus handle(id) was released, do pause here
244 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::STREAM_DIRECTION_PLAYBACK) {
245 if (mpPulseAudioClient->drain() == false) {
246 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
250 mpPulseAudioClient->cork(true);
251 onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED);
254 } else if (state == FOCUS_IS_ACQUIRED) {
255 // Focus handle(id) was acquired again,
256 // check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...)
257 // do resume here and call interrupt completed callback to application.
260 mpPulseAudioClient->cork(false);
261 onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING);
267 if (mInterruptCallback.onInterrupt != NULL) {
268 IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::INTERRUPT_COMPLETED;
269 e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change);
270 mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData);
274 void CAudioIO::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
277 if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
278 if (value == 1 && pHandler->getSubscribeId() >= 0) {
279 // Unregister focus watch callback & disable session handler
280 pHandler->disableSessionHandler();
281 AUDIO_IO_LOGD("Session handler disabled by signal");
282 } else if (value == 0) {
283 // Currently do nothing...
288 void CAudioIO::prepare() throw (CAudioError) {
289 if (mIsInit == false) {
290 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
295 AUDIO_IO_LOGD("prepare");
298 } catch (CAudioError e) {
304 void CAudioIO::unprepare() throw (CAudioError) {
305 if (mIsInit == false) {
306 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
311 AUDIO_IO_LOGD("unprepare");
314 } catch (CAudioError e) {
320 void CAudioIO::pause() throw (CAudioError) {
321 if (mIsInit == false || IsReady() == false) {
322 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
327 AUDIO_IO_LOGD("pause");
328 mpPulseAudioClient->cork(true);
330 } catch (CAudioError e) {
336 void CAudioIO::resume() throw (CAudioError) {
337 if (mIsInit == false || IsReady() == false) {
338 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
343 AUDIO_IO_LOGD("resume");
344 mpPulseAudioClient->cork(false);
346 } catch (CAudioError e) {
352 void CAudioIO::drain() throw (CAudioError) {
353 if (mIsInit == false || IsReady() == false) {
354 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
359 AUDIO_IO_LOGD("drain");
360 mpPulseAudioClient->drain();
362 } catch (CAudioError e) {
368 void CAudioIO::flush() throw (CAudioError) {
369 if (mIsInit == false || IsReady() == false) {
370 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
375 AUDIO_IO_LOGD("flush");
376 mpPulseAudioClient->flush();
378 } catch (CAudioError e) {
384 CAudioInfo CAudioIO::getAudioInfo() throw (CAudioError) {
385 if (mIsInit == false) {
386 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
392 void CAudioIO::setStreamCallback(SStreamCallback callback) throw (CAudioError) {
393 if (mIsInit == false) {
394 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
398 mStreamCallback = callback;
402 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() throw (CAudioError) {
403 if (mIsInit == false) {
404 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
407 return mStreamCallback;
410 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) throw (CAudioError) {
411 if (mIsInit == false) {
412 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
416 mStateChangedCallback = callback;
420 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() throw (CAudioError) {
421 if (mIsInit == false) {
422 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
425 return mStateChangedCallback;
428 void CAudioIO::setInterruptCallback(SInterruptCallback callback) throw (CAudioError) {
429 if (mIsInit == false) {
430 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
433 mInterruptCallback = callback;
436 CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() throw (CAudioError) {
437 if (mIsInit == false) {
438 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
441 return mInterruptCallback;
445 void CAudioIO::ignoreSession() throw (CAudioError) {
446 if (mIsInit == false) {
447 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
453 if (mpPulseAudioClient != NULL && mpPulseAudioClient->isCorked() == false) {
454 THROW_ERROR_MSG(CAudioError::ERROR_INVALID_OPERATION, "An Operation is not permitted while started");
457 bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
458 if (isSkip == false && mpAudioSessionHandler->getId() >= 0) {
459 mpAudioSessionHandler->unregisterSound();
462 } catch (CAudioError e) {