Remove 3.0 deprecated API implementation
[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 <mm.h>
19 #include <pthread.h>
20 #include <assert.h>
21 #include <glib.h>
22 #include "CAudioIODef.h"
23 #include <sound_manager_internal.h>
24
25 using namespace std;
26 using namespace tizen_media_audio;
27
28
29 /**
30  * class CAudioIO
31  */
32 CAudioIO::CAudioIO() :
33     mpPulseAudioClient(NULL),
34     __mMutex(PTHREAD_MUTEX_INITIALIZER),
35     __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
36     __mCond(PTHREAD_COND_INITIALIZER),
37     __mIsInit(false) {
38     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
39     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
40     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
41     mByPolicy = false;
42 }
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()");
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()");
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()");
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()");
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);
150         error_occured = true;
151     }
152
153     ret = pthread_mutex_destroy(&__mCondMutex);
154     if (ret != 0) {
155         AUDIO_IO_LOGE("Failed cond pthread_mutex_destroy(%p) errno:%d", &__mCondMutex, ret);
156         error_occured = true;
157     }
158
159     ret = pthread_cond_destroy(&__mCond);
160     if (ret != 0) {
161         AUDIO_IO_LOGE("Failed pthread_cond_destroy(%p) errno:%d", &__mCond, ret);
162         error_occured = true;
163     }
164
165     if (error_occured)
166         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Finalize Failed");
167
168     __mIsInit = false;
169 }
170
171 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
172     assert(__mIsInit == true);
173     assert(pClient != NULL);
174     assert(length > 0);
175
176 #ifdef _AUDIO_IO_DEBUG_TIMING_
177     AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
178 #endif
179
180     if (mStreamCallback.onStream != NULL)
181         mStreamCallback.onStream(length, mStreamCallback.mUserData);
182 }
183
184 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
185     assert(__mIsInit == true);
186     assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
187
188     mStatePrev = mState;
189     mState = state;
190     mByPolicy = byPolicy;
191
192     if (mState == mStatePrev)
193         return;
194
195     const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
196
197     AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
198                   state_string[static_cast<int>(mStatePrev)],
199                   static_cast<int>(mStatePrev),
200                   state_string[static_cast<int>(mState)],
201                   static_cast<int>(mState),
202                   mByPolicy);
203
204     if (mStateChangedCallback.onStateChanged != NULL)
205         mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
206 }
207
208 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
209     onStateChanged(state, false);
210 }
211
212 CAudioInfo::EAudioIOState CAudioIO::getState() {
213     return mState;
214 }
215
216 void CAudioIO::prepare() {
217     if (__mIsInit == false)
218         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
219 }
220
221 void CAudioIO::unprepare() {
222     if (__mIsInit == false)
223         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
224 }
225
226 void CAudioIO::pause() {
227     if (__mIsInit == false || IsReady() == false)
228         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
229
230     try {
231         internalLock();
232         AUDIO_IO_LOGD("pause");
233         mpPulseAudioClient->cork(true);
234         internalUnlock();
235     } catch (CAudioError& e) {
236         internalUnlock();
237         throw;
238     }
239 }
240
241 void CAudioIO::resume() {
242     if (__mIsInit == false || IsReady() == false)
243         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
244
245     try {
246         internalLock();
247         AUDIO_IO_LOGD("resume");
248         mpPulseAudioClient->cork(false);
249         internalUnlock();
250     } catch (CAudioError& e) {
251         internalUnlock();
252         throw;
253     }
254 }
255
256 void CAudioIO::drain() {
257     if (__mIsInit == false || IsReady() == false)
258         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
259
260     try {
261         if (mpPulseAudioClient->isInThread()) {
262             mpPulseAudioClient->drain();
263         } else {
264             internalLock();
265             mpPulseAudioClient->drain();
266             internalUnlock();
267         }
268     } catch (CAudioError& e) {
269         if (!mpPulseAudioClient->isInThread())
270             internalUnlock();
271         throw;
272     }
273 }
274
275 void CAudioIO::flush() {
276     if (__mIsInit == false || IsReady() == false)
277         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
278
279     try {
280         if (mpPulseAudioClient->isInThread()) {
281             mpPulseAudioClient->flush();
282         } else {
283             internalLock();
284             mpPulseAudioClient->flush();
285             internalUnlock();
286         }
287     } catch (CAudioError& e) {
288         if (!mpPulseAudioClient->isInThread())
289             internalUnlock();
290         throw;
291     }
292 }
293
294 CAudioInfo& CAudioIO::getAudioInfo() {
295     if (__mIsInit == false)
296         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
297
298     return mAudioInfo;
299 }
300
301 void CAudioIO::setStreamCallback(SStreamCallback callback) {
302     if (__mIsInit == false)
303         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
304
305     mStreamCallback = callback;
306 }
307
308 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
309     if (__mIsInit == false)
310         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
311
312     return mStreamCallback;
313 }
314
315 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
316     if (__mIsInit == false)
317         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
318
319     mStateChangedCallback = callback;
320 }
321
322 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
323     if (__mIsInit == false)
324         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
325
326     return mStateChangedCallback;
327 }
328
329 void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
330     if (stream_info == NULL)
331         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL");
332
333     if (__mIsInit == false)
334         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
335
336     try {
337         if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
338             THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started");
339
340         int errorCode = SOUND_MANAGER_ERROR_NONE;
341         CAudioInfo::EAudioType audioType = CAudioInfo::EAudioType::AUDIO_IN_TYPE_MEDIA;
342         char *type = NULL;
343         int index = -1;
344         bool avail = false;
345
346         if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
347             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode);
348         if (!avail)
349             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported");
350
351         if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
352             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode);
353         if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
354             getAudioInfo().convertInputStreamType2AudioType(type, &audioType);
355         else
356             getAudioInfo().convertOutputStreamType2AudioType(type, &audioType);
357         getAudioInfo().setAudioType(audioType);
358
359         if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
360             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode);
361         getAudioInfo().setAudioIndex(index);
362
363     } catch (CAudioError& e) {
364         throw;
365     }
366 }