1d44607e3de7725a1680df94b83a5adb68bc22dc
[platform/core/api/audio-io.git] / src / cpp / CAudioIO.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 <pthread.h>
19 #include <assert.h>
20 #include "CAudioIODef.h"
21 #include <sound_manager_internal.h>
22
23 using namespace std;
24 using namespace tizen_media_audio;
25
26
27 /**
28  * class CAudioIO
29  */
30 //LCOV_EXCL_START
31 CAudioIO::CAudioIO() :
32     mpPulseAudioClient(NULL),
33     __mMutex(PTHREAD_MUTEX_INITIALIZER),
34     __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
35     __mCond(PTHREAD_COND_INITIALIZER),
36     __mIsInit(false) {
37     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
38     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
39     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
40     mByPolicy = false;
41 }
42 //LCOV_EXCL_STOP
43
44 CAudioIO::CAudioIO(CAudioInfo& audioInfo) :
45     mpPulseAudioClient(NULL),
46     __mMutex(PTHREAD_MUTEX_INITIALIZER),
47     __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
48     __mCond(PTHREAD_COND_INITIALIZER),
49     __mIsInit(false) {
50     mAudioInfo = audioInfo;
51     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
52     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
53     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
54     mByPolicy = false;
55 }
56
57 CAudioIO::~CAudioIO() {
58 }
59
60 void CAudioIO::setInit(bool flag) {
61     __mIsInit = flag;
62 }
63
64 bool CAudioIO::isInit() {
65     return __mIsInit;
66 }
67
68 bool CAudioIO::IsReady() {
69     return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING ||
70              mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED)? true : false);
71 }
72
73 void CAudioIO::internalLock() {
74     if (__mIsInit == false)
75         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
76
77     if (pthread_mutex_lock(&__mMutex) != 0)
78         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); //LCOV_EXCL_LINE
79
80 #ifdef _AUDIO_IO_DEBUG_TIMING_
81     AUDIO_IO_LOGD(COLOR_RED "%p LOCKED" COLOR_END, &__mMutex);
82 #endif
83 }
84
85 void CAudioIO::internalUnlock() {
86     if (__mIsInit == false)
87         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
88
89     if (pthread_mutex_unlock(&__mMutex) != 0)
90         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); //LCOV_EXCL_LINE
91
92 #ifdef _AUDIO_IO_DEBUG_TIMING_
93     AUDIO_IO_LOGD(COLOR_GREEN "%p UNLOCKED" COLOR_END, &__mMutex);
94 #endif
95 }
96
97 void CAudioIO::internalWait() {
98     if (__mIsInit == false)
99         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
100
101 #ifdef _AUDIO_IO_DEBUG_TIMING_
102     AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
103 #endif
104
105     pthread_mutex_lock(&__mCondMutex);
106     pthread_cond_wait(&__mCond, &__mCondMutex);
107     pthread_mutex_unlock(&__mCondMutex);
108 }
109
110 void CAudioIO::internalSignal() {
111     if (__mIsInit == false)
112         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
113
114 #ifdef _AUDIO_IO_DEBUG_TIMING_
115     AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
116 #endif
117
118     pthread_mutex_lock(&__mCondMutex);
119     pthread_cond_signal(&__mCond);
120     pthread_mutex_unlock(&__mCondMutex);
121 }
122
123 void CAudioIO::initialize() {
124     if (__mIsInit == true)
125         return;
126
127     AUDIO_IO_LOGD("initialize");
128
129     int ret = pthread_mutex_init(&__mMutex, NULL);
130     if (ret != 0)
131         THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()"); //LCOV_EXCL_LINE
132
133     ret = pthread_cond_init(&__mCond, NULL);
134     if (ret != 0)
135         THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()"); //LCOV_EXCL_LINE
136
137     __mIsInit = true;
138 }
139
140 void CAudioIO::finalize() {
141     if (__mIsInit == false)
142         return;
143
144     AUDIO_IO_LOGD("finalize");
145
146     bool error_occured = false;
147     int ret = pthread_mutex_destroy(&__mMutex);
148     if (ret != 0) {
149         AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mMutex, ret); //LCOV_EXCL_LINE
150         error_occured = true;
151     }
152
153     ret = pthread_mutex_destroy(&__mCondMutex);
154     if (ret != 0) {
155 //LCOV_EXCL_START
156         AUDIO_IO_LOGE("Failed cond pthread_mutex_destroy(%p) errno:%d", &__mCondMutex, ret);
157         error_occured = true;
158 //LCOV_EXCL_STOP
159     }
160
161     ret = pthread_cond_destroy(&__mCond);
162     if (ret != 0) {
163 //LCOV_EXCL_START
164         AUDIO_IO_LOGE("Failed pthread_cond_destroy(%p) errno:%d", &__mCond, ret);
165         error_occured = true;
166 //LCOV_EXCL_STOP
167     }
168
169     if (error_occured)
170         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Finalize Failed");
171
172     __mIsInit = false;
173 }
174
175 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
176     assert(__mIsInit == true);
177     assert(pClient != NULL);
178     assert(length > 0);
179
180 #ifdef _AUDIO_IO_DEBUG_TIMING_
181     AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
182 #endif
183
184     if (mStreamCallback.onStream != NULL)
185         mStreamCallback.onStream(length, mStreamCallback.mUserData);
186 }
187
188 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
189     assert(__mIsInit == true);
190     assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
191
192     mStatePrev = mState;
193     mState = state;
194     mByPolicy = byPolicy;
195
196     if (mState == mStatePrev)
197         return;
198
199     const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
200
201     AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
202                   state_string[static_cast<int>(mStatePrev)],
203                   static_cast<int>(mStatePrev),
204                   state_string[static_cast<int>(mState)],
205                   static_cast<int>(mState),
206                   mByPolicy);
207
208     if (mStateChangedCallback.onStateChanged != NULL)
209         mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
210 }
211
212 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
213     onStateChanged(state, false);
214 }
215
216 CAudioInfo::EAudioIOState CAudioIO::getState() {
217     return mState;
218 }
219
220 void CAudioIO::prepare() {
221     if (__mIsInit == false)
222         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
223 }
224
225 void CAudioIO::unprepare() {
226     if (__mIsInit == false)
227         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
228 }
229
230 void CAudioIO::pause() {
231     if (__mIsInit == false || IsReady() == false)
232         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
233
234     try {
235         internalLock();
236         AUDIO_IO_LOGD("pause");
237         mpPulseAudioClient->cork(true);
238         internalUnlock();
239     } catch (CAudioError& e) {
240         internalUnlock();
241         throw;
242     }
243 }
244
245 void CAudioIO::resume() {
246     if (__mIsInit == false || IsReady() == false)
247         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
248
249     try {
250         internalLock();
251         AUDIO_IO_LOGD("resume");
252         mpPulseAudioClient->cork(false);
253         internalUnlock();
254     } catch (CAudioError& e) {
255         internalUnlock();
256         throw;
257     }
258 }
259
260 void CAudioIO::drain() {
261     if (__mIsInit == false || IsReady() == false)
262         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
263
264     try {
265         if (mpPulseAudioClient->isInThread()) {
266             mpPulseAudioClient->drain();
267         } else {
268             internalLock();
269             mpPulseAudioClient->drain();
270             internalUnlock();
271         }
272     } catch (CAudioError& e) {
273         if (!mpPulseAudioClient->isInThread())
274             internalUnlock();
275         throw;
276     }
277 }
278
279 void CAudioIO::flush() {
280     if (__mIsInit == false || IsReady() == false)
281         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
282
283     try {
284         if (mpPulseAudioClient->isInThread()) {
285             mpPulseAudioClient->flush();
286         } else {
287             internalLock();
288             mpPulseAudioClient->flush();
289             internalUnlock();
290         }
291     } catch (CAudioError& e) {
292         if (!mpPulseAudioClient->isInThread())
293             internalUnlock();
294         throw;
295     }
296 }
297
298 CAudioInfo& CAudioIO::getAudioInfo() {
299     if (__mIsInit == false)
300         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
301
302     return mAudioInfo;
303 }
304
305 void CAudioIO::setStreamCallback(SStreamCallback callback) {
306     if (__mIsInit == false)
307         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
308
309     mStreamCallback = callback;
310 }
311
312 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
313     if (__mIsInit == false)
314         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
315
316     return mStreamCallback;
317 }
318
319 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
320     if (__mIsInit == false)
321         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
322
323     mStateChangedCallback = callback;
324 }
325
326 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
327     if (__mIsInit == false)
328         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
329
330     return mStateChangedCallback;
331 }
332
333 void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
334     if (stream_info == NULL)
335         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL");
336
337     if (__mIsInit == false)
338         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
339
340     try {
341         if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
342             THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started");
343
344         int errorCode = SOUND_MANAGER_ERROR_NONE;
345         CAudioInfo::EAudioType audioType = CAudioInfo::EAudioType::AUDIO_IN_TYPE_MEDIA;
346         char *type = NULL;
347         int index = -1;
348         bool avail = false;
349
350         if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
351             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode);
352         if (!avail)
353             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported");
354
355         if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
356             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
357         if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
358             getAudioInfo().convertInputStreamType2AudioType(type, &audioType);
359         else
360             getAudioInfo().convertOutputStreamType2AudioType(type, &audioType);
361         getAudioInfo().setAudioType(audioType);
362
363         if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
364             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
365         getAudioInfo().setAudioIndex(index);
366
367     } catch (CAudioError& e) {
368         throw;
369     }
370 }