1 #include "wakeup_audio_manager.h"
2 #include "wakeup_manager_main.h"
3 #include "dependency_resolver.h"
4 #include "heap_tracer.h"
10 #include <sound_manager.h>
11 #include <sound_manager_internal.h>
13 namespace multiassistant
18 /* Need to check whether this value needs to be configurable */
19 static int g_speech_pcm_wait_count = 800;
21 static long long get_current_milliseconds_after_epoch()
23 auto now = chrono::steady_clock::now();
24 auto now_ms = chrono::time_point_cast<chrono::milliseconds>(now);
25 /* number of milliseconds since the epoch of system_clock */
26 auto value = now_ms.time_since_epoch();
31 CAudioManager::CAudioManager()
35 CAudioManager::~CAudioManager()
39 CAudioManager::CAudioManager(IAudioEventObserver *observer) : CAudioManager()
44 void recording_focus_state_watch_cb(int id, sound_stream_focus_mask_e focus_mask,
45 sound_stream_focus_state_e focus_state, sound_stream_focus_change_reason_e reason,
46 const char *extra_info, void *user_data)
48 MWR_LOGD("[Recorder] focus_mask : %d, focus_state : %d, reason : %d, [%s]",
49 focus_mask, focus_state, reason, extra_info);
51 if (nullptr == user_data) return;
53 /* The API description states that calling sound_manager_get_current_recording_focus()
54 function inside sound_stream_focus_state_watch_cb() function is prohibited */
55 ecore_main_loop_thread_safe_call_async(
57 CAudioManager *manager = static_cast<CAudioManager*>(data);
59 manager->sound_focus_changed();
64 int CAudioManager::initialize(void)
66 sound_manager_add_focus_state_watch_cb(SOUND_STREAM_FOCUS_FOR_RECORDING,
67 recording_focus_state_watch_cb, this, &mSoundFocusWatchId);
71 int CAudioManager::deinitialize(void)
74 if (mStreamingThread.joinable()) {
75 MWR_LOGD("mStreamingThread is joinable, trying join()");
76 mStopStreamingThread.store(true);
78 mStreamingThread.join();
79 } catch (std::exception &e) {
80 MWR_LOGE("Exception thrown : %s", e.what());
83 mStopStreamingThread.store(false);
85 sound_manager_remove_focus_state_watch_cb(mSoundFocusWatchId);
90 void CAudioManager::sound_focus_changed()
92 sound_stream_focus_change_reason_e acquired_by;
94 char* extra_info = NULL;
95 int focus = sound_manager_get_current_recording_focus(&acquired_by, &sound_behavior, &extra_info);
96 MWR_LOGD("[Recorder] sound focus has changed : %d %d %d %s", focus,
97 (SOUND_MANAGER_ERROR_NO_DATA != focus ? acquired_by : -1),
98 (SOUND_MANAGER_ERROR_NO_DATA != focus ? sound_behavior : -1),
99 (SOUND_MANAGER_ERROR_NO_DATA != focus ? extra_info : ""));
100 if (SOUND_MANAGER_ERROR_NO_DATA == focus) {
101 if (mRecordingRequired && !mIsRecording) {
102 MWR_LOGD("[Recorder] Currently no other process has acquired sound focus, start recording");
103 start_recording(false);
107 MWR_LOGW("[Recorder] Sound focus acquired by other process, stop recording");
108 stop_recording(false);
117 void CAudioManager::subscribe(IAudioEventObserver *observer)
120 mObservers.push_back(observer);
124 void CAudioManager::unsubscribe(IAudioEventObserver *observer)
126 auto iter = find(mObservers.begin(), mObservers.end(), observer);
127 if (iter != mObservers.end()) {
128 mObservers.erase(iter);
132 void CAudioManager::stop_recording(bool proactive)
134 dependency_resolver_stop_recording();
136 mRecordingRequired = false;
138 mIsRecording = false;
141 void CAudioManager::start_recording(bool proactive)
144 stop_recording(false);
147 mRecordingRequired = true;
150 sound_stream_focus_change_reason_e acquired_by;
152 char* extra_info = NULL;
153 if (SOUND_MANAGER_ERROR_NO_DATA == sound_manager_get_current_recording_focus(&acquired_by, &sound_behavior, &extra_info)) {
154 MWR_LOGD("[Recorder] Currently no other process has acquired sound focus, start recording");
155 dependency_resolver_start_recording();
158 MWR_LOGW("[Recorder] Currently sound focus is acquired by other process, skip recording");
166 void CAudioManager::set_recording_session(recording_session session)
168 dependency_resolver_set_recording_session((unsigned int)session);
171 /* Need to consider adapting conventional producer-consumer model */
172 void CAudioManager::streaming_previous_audio_data_thread_func()
176 unique_lock<mutex> lock(mMutex, defer_lock);
178 /* get feedback data */
179 size_t audio_data_size = 0;
181 audio_data_size = mPreviousAudioData.size();
182 for (int index = 0; index < audio_data_size; index++) {
183 mas_speech_data& speech_data = mPreviousAudioData.at(index).data;
184 for (const auto& observer : mObservers) {
186 if (!observer->on_streaming_audio_data(
187 speech_data.event, speech_data.buffer, speech_data.len)) {
188 LOGE("[Recorder WARNING] One of the observer returned false");
192 if (MAS_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
193 MWR_LOGI("[INFO] Finish to send previous speech data");
198 if (mStopStreamingThread.load()) {
199 MWR_LOGI("[INFO] Stop Streaming Requested, returning");
208 void CAudioManager::streaming_audio_data_thread_func(long long start_time)
212 unique_lock<mutex> lock(mMutex, defer_lock);
213 bool finish_event_sent = false;
216 auto lead = mAudioData.begin();
218 while (lead != mAudioData.end() && lead->time < start_time) {
222 MWR_LOGI("data_count : %zu", mAudioData.size());
225 while (!(mStopStreamingThread.load())) {
229 /* get feedback data */
231 auto end = mAudioData.end();
235 MWR_LOGD("[DEBUG] No feedback data. Waiting mode : %d", ret);
238 while (!(mStopStreamingThread.load())) {
239 this_thread::sleep_for(chrono::milliseconds(10));
241 end = mAudioData.end();
242 auto begin = mAudioData.begin();
253 MWR_LOGD("[INFO] Resume thread");
256 if (g_speech_pcm_wait_count < cnt) {
257 unsigned char final_buffer[2] = {'\0', };
258 MWR_LOGE("[ERROR] Wrong request, there's no pcm data");
259 for (const auto& observer : mObservers) {
261 if (!observer->on_streaming_audio_data(
262 MAS_SPEECH_STREAMING_EVENT_FAIL, NULL, 0)) {
263 LOGE("[Recorder WARNING] One of the observer returned false");
265 if (!observer->on_streaming_audio_data(
266 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
267 LOGE("[Recorder WARNING] One of the observer returned false");
275 MWR_LOGD("[INFO] Finish to wait for new feedback data come");
277 /* resume feedback thread */
281 /* FIXME : Extracted audio data here should be used as previous audio data*/
284 end = mAudioData.end();
288 mas_speech_data& speech_data = iter->data;
289 for (const auto& observer : mObservers) {
291 if (!observer->on_streaming_audio_data(
292 speech_data.event, speech_data.buffer, speech_data.len)) {
293 LOGE("[Recorder WARNING] One of the observer returned false");
298 if (MAS_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
299 MWR_LOGI("[INFO] Finish to get and send speech data");
300 finish_event_sent = true;
309 if (true != finish_event_sent) {
310 unsigned char final_buffer[2] = {'\0', };
311 for (const auto& observer : mObservers) {
313 if (!observer->on_streaming_audio_data(
314 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
315 LOGE("[Recorder WARNING] One of the observer returned false");
323 void CAudioManager::add_audio_data(mas_speech_data& data, long long time)
325 long long delta = mAudioRecordingDurationMilliseconds;
327 notify_audio_data_recording(time, data.buffer, data.len);
329 mas_speech_data_with_time data_with_time;
330 data_with_time.data = data;
331 data_with_time.time = time;
333 lock_guard<mutex> lock(mMutex);
335 /* Pop items only when the streaming is not activated */
336 while(false == mAudioData.empty() && mAudioData.front().time < time - delta) {
337 const auto &front = mAudioData.front();
338 if (front.data.buffer) {
339 vm_free_simple(front.data.buffer);
341 mAudioData.pop_front();
343 mAudioData.push_back(data_with_time);
346 void CAudioManager::feed_audio_data(mas_speech_streaming_event_e event, void* buffer, int len)
348 if (NULL == buffer || 0 == len) return;
350 mas_speech_data speech_data;
351 speech_data.buffer = vm_malloc_simple(len);
352 if (speech_data.buffer) {
353 long long time = get_current_milliseconds_after_epoch();
355 speech_data.event = event;
356 speech_data.len = len;
357 memcpy(speech_data.buffer, buffer, len);
358 add_audio_data(speech_data, time);
362 void CAudioManager::finalize_audio_data()
364 unsigned char final_buffer[2] = {'\0', };
365 mas_speech_data speech_data;
366 speech_data.event = MAS_SPEECH_STREAMING_EVENT_FINISH;
367 speech_data.len = sizeof(final_buffer);
368 speech_data.buffer = vm_malloc_simple(speech_data.len);
369 if (speech_data.buffer) {
370 long long time = get_current_milliseconds_after_epoch();
372 memcpy(speech_data.buffer, final_buffer, speech_data.len);
373 add_audio_data(speech_data, time);
377 void CAudioManager::clear_audio_data()
379 lock_guard<mutex> lock(mMutex);
380 while(!mAudioData.empty()) {
381 const auto &front = mAudioData.front();
382 if (front.data.buffer) {
383 vm_free_simple(front.data.buffer);
385 mAudioData.pop_front();
390 void CAudioManager::notify_audio_data_recording(long time, void* data, int len)
392 for (const auto& observer : mObservers) {
394 if (!observer->on_recording_audio_data(time, data, len)) {
395 LOGE("[Recorder WARNING] One of the observer returned false");
401 void CAudioManager::start_streaming_current_utterance_data(long long start_time)
403 if (mStreamingThread.joinable()) {
404 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
407 lock_guard<mutex> lock(mMutex);
408 mStreamingThread = thread(&CAudioManager::streaming_audio_data_thread_func, this, start_time);
411 void CAudioManager::stop_streaming_current_utterance_data()
413 if (mStreamingThread.joinable()) {
414 MWR_LOGD("mStreamingThread is joinable, trying join()");
415 mStopStreamingThread.store(true);
417 mStreamingThread.join();
418 } catch (std::exception &e) {
419 MWR_LOGE("Exception thrown : %s", e.what());
422 mStopStreamingThread.store(false);
424 /* FIXME : Need to move all the speech data to previous speech data for later use */
427 void CAudioManager::start_streaming_previous_utterance_data()
429 if (mStreamingPreviousThread.joinable()) {
430 MWR_LOGE("ERROR : mStreamingPreviousThread is joinable, will not start a new thread");
433 lock_guard<mutex> lock(mMutex);
434 mStreamingPreviousThread = thread(&CAudioManager::streaming_previous_audio_data_thread_func, this);
437 void CAudioManager::stop_streaming_previous_utterance_data()
439 if (mStreamingPreviousThread.joinable()) {
440 MWR_LOGD("mStreamingPreviousThread is joinable, trying join()");
441 mStopStreamingPreviousThread.store(true);
443 mStreamingPreviousThread.join();
444 } catch (std::exception &e) {
445 MWR_LOGE("Exception thrown : %s", e.what());
448 mStopStreamingThread.store(false);
451 void CAudioManager::start_streaming_follow_up_data()
453 if (mStreamingThread.joinable()) {
454 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
458 mStreamingThread = thread(&CAudioManager::streaming_audio_data_thread_func, this, 0);
461 void CAudioManager::stop_streaming_follow_up_data()
463 if (mStreamingThread.joinable()) {
464 MWR_LOGD("mStreamingThread is joinable, trying join()");
465 mStopStreamingThread.store(true);
466 mStreamingThread.join();
468 mStopStreamingThread.store(false);
471 void CAudioManager::set_background_volume(double ratio)
473 dependency_resolver_set_background_volume(ratio);