Add noise suppression functionality
[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     mByPolicy = byPolicy;
99
100     if (mState == mStatePrev)
101         return;
102
103     static const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
104
105     AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
106                   state_string[static_cast<int>(mStatePrev)],
107                   static_cast<int>(mStatePrev),
108                   state_string[static_cast<int>(mState)],
109                   static_cast<int>(mState),
110                   mByPolicy);
111
112     if (mStateChangedCallback.onStateChanged)
113         mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
114 }
115
116 void CAudioIO::setState(CAudioInfo::EAudioIOState state) {
117     mStatePrev = mState;
118     mState = state;
119 }
120
121 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
122     onStateChanged(state, false);
123 }
124
125 CAudioInfo::EAudioIOState CAudioIO::getState() noexcept {
126     return mState;
127 }
128
129 void CAudioIO::prepare() {
130     if (!__mIsInit)
131         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
132 }
133
134 void CAudioIO::unprepare() {
135     if (!__mIsInit)
136         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
137 }
138
139 void CAudioIO::pause() {
140     if (!__mIsInit || !IsReady())
141         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
142
143     AUDIO_IO_LOGD("pause");
144     mpPulseAudioClient->cork(true);
145 }
146
147 void CAudioIO::resume() {
148     if (!__mIsInit || !IsReady())
149         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
150
151     mpPulseAudioClient->cork(false);
152 }
153
154 void CAudioIO::flush() {
155     if (!__mIsInit || !IsReady())
156         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); //LCOV_EXCL_LINE
157
158     mpPulseAudioClient->flush();
159 }
160
161 CAudioInfo& CAudioIO::getAudioInfo() {
162     if (!__mIsInit)
163         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
164
165     return mAudioInfo;
166 }
167
168 void CAudioIO::setStreamCallback(SStreamCallback callback) {
169     if (!__mIsInit)
170         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
171
172     mStreamCallback = callback;
173 }
174
175 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
176     if (!__mIsInit)
177         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
178
179     return mStreamCallback;
180 }
181
182 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
183     if (!__mIsInit)
184         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
185
186     mStateChangedCallback = callback;
187 }
188
189 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
190     if (!__mIsInit)
191         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
192
193     return mStateChangedCallback;
194 }
195
196 void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
197     if (!stream_info)
198         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL"); //LCOV_EXCL_LINE
199
200     if (!__mIsInit)
201         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); //LCOV_EXCL_LINE
202
203     if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
204         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started"); //LCOV_EXCL_LINE
205
206     int errorCode = SOUND_MANAGER_ERROR_NONE;
207     char *type = nullptr;
208     int index = -1;
209     bool avail = false;
210
211     if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
212         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
213     if (!avail)
214         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported"); //LCOV_EXCL_LINE
215
216     if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
217         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
218     if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
219         getAudioInfo().setAudioTypeByInputStreamType(type);
220     else
221         getAudioInfo().setAudioTypeByOutputStreamType(type);
222
223     if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
224         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode); //LCOV_EXCL_LINE
225     getAudioInfo().setAudioIndex(index);
226
227     if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN) {
228         int device_id;
229         bool enabled;
230
231         if ((errorCode = sound_manager_get_echo_cancel_reference_device(stream_info, &device_id)) != SOUND_MANAGER_ERROR_NONE)
232             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Can't get reference device [ret:%d]", errorCode); //LCOV_EXCL_LINE
233
234         if (device_id != SOUND_MANAGER_STREAM_NO_REFERENCE_DEVICE)
235             getAudioInfo().bindEchoCancelReferenceDeviceId(device_id);
236
237         if ((errorCode = sound_manager_get_noise_suppression(stream_info, &enabled)) != SOUND_MANAGER_ERROR_NONE)
238             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Can't get noise suppression status [ret:%d]", errorCode); //LCOV_EXCL_LINE
239
240         if (enabled)
241             getAudioInfo().setNoiseSuppression(enabled);
242
243     }
244 }