Revise cpp codes (mutex/cond)
[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 <assert.h>
19 #include "CAudioIODef.h"
20 #include <sound_manager_internal.h>
21 #include <sys/time.h>
22 #include <string.h>
23
24 using namespace std;
25 using namespace tizen_media_audio;
26
27
28 /**
29  * class CAudioIO
30  */
31 //LCOV_EXCL_START
32 CAudioIO::CAudioIO() :
33     mpPulseAudioClient(nullptr),
34     __mIsInit(false) {
35     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
36     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
37     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
38     mByPolicy = false;
39 }
40 //LCOV_EXCL_STOP
41
42 CAudioIO::CAudioIO(CAudioInfo& audioInfo) :
43     mpPulseAudioClient(nullptr),
44     __mIsInit(false) {
45     mAudioInfo = audioInfo;
46     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
47     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
48     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
49     mByPolicy = false;
50 }
51
52 void CAudioIO::setInit(bool flag) {
53     __mIsInit = flag;
54 }
55
56 bool CAudioIO::isInit() {
57     return __mIsInit;
58 }
59
60 bool CAudioIO::IsReady() {
61     return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING ||
62              mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED));
63 }
64
65 void CAudioIO::initialize() {
66     if (__mIsInit)
67         return;
68
69     AUDIO_IO_LOGD("initialize");
70     __mIsInit = true;
71 }
72
73 void CAudioIO::finalize() {
74     if (!__mIsInit)
75         return;
76
77     AUDIO_IO_LOGD("finalize");
78     __mIsInit = false;
79 }
80
81 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
82     assert(__mIsInit);
83     assert(pClient);
84     assert(length > 0);
85
86 #ifdef _AUDIO_IO_DEBUG_TIMING_
87     AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
88 #endif
89
90     if (mStreamCallback.onStream)
91         mStreamCallback.onStream(length, mStreamCallback.mUserData);
92 }
93
94 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
95     assert(__mIsInit);
96     assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
97
98     mStatePrev = mState;
99     mState = state;
100     mByPolicy = byPolicy;
101
102     if (mState == mStatePrev)
103         return;
104
105     static const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
106
107     AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
108                   state_string[static_cast<int>(mStatePrev)],
109                   static_cast<int>(mStatePrev),
110                   state_string[static_cast<int>(mState)],
111                   static_cast<int>(mState),
112                   mByPolicy);
113
114     if (mStateChangedCallback.onStateChanged)
115         mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
116 }
117
118 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
119     onStateChanged(state, false);
120 }
121
122 CAudioInfo::EAudioIOState CAudioIO::getState() noexcept {
123     return mState;
124 }
125
126 void CAudioIO::prepare() {
127     if (!__mIsInit)
128         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
129 }
130
131 void CAudioIO::unprepare() {
132     if (!__mIsInit)
133         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
134 }
135
136 void CAudioIO::pause() {
137     if (!__mIsInit || !IsReady())
138         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
139
140     std::lock_guard<std::mutex> guard(mMutex);
141     AUDIO_IO_LOGD("pause");
142     mpPulseAudioClient->cork(true);
143 }
144
145 void CAudioIO::resume() {
146     if (!__mIsInit || !IsReady())
147         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
148
149     std::lock_guard<std::mutex> guard(mMutex);
150     mpPulseAudioClient->cork(false);
151 }
152
153 void CAudioIO::flush() {
154     if (!__mIsInit || !IsReady())
155         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
156
157     std::unique_lock<std::mutex> defer_mutex(mMutex, std::defer_lock);
158     if (!mpPulseAudioClient->isInThread())
159         defer_mutex.lock();
160     mpPulseAudioClient->flush();
161 }
162
163 CAudioInfo& CAudioIO::getAudioInfo() {
164     if (!__mIsInit)
165         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
166
167     return mAudioInfo;
168 }
169
170 void CAudioIO::setStreamCallback(SStreamCallback callback) {
171     if (!__mIsInit)
172         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
173
174     mStreamCallback = callback;
175 }
176
177 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
178     if (!__mIsInit)
179         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
180
181     return mStreamCallback;
182 }
183
184 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
185     if (!__mIsInit)
186         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
187
188     mStateChangedCallback = callback;
189 }
190
191 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
192     if (!__mIsInit)
193         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
194
195     return mStateChangedCallback;
196 }
197
198 void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
199     if (!stream_info)
200         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL"); //LCOV_EXCL_LINE
201
202     if (!__mIsInit)
203         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
204
205     if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
206         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started"); //LCOV_EXCL_LINE
207
208     int errorCode = SOUND_MANAGER_ERROR_NONE;
209     char *type = nullptr;
210     int index = -1;
211     bool avail = false;
212
213     if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
214         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
215     if (!avail)
216         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported"); //LCOV_EXCL_LINE
217
218     if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
219         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
220     if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
221         getAudioInfo().setAudioTypeByInputStreamType(type);
222     else
223         getAudioInfo().setAudioTypeByOutputStreamType(type);
224
225     if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
226         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
227     getAudioInfo().setAudioIndex(index);
228 }