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()
40 CAudioManager::CAudioManager(IAudioEventObserver *observer) : CAudioManager()
45 void recording_focus_state_watch_cb(int id, sound_stream_focus_mask_e focus_mask,
46 sound_stream_focus_state_e focus_state, sound_stream_focus_change_reason_e reason,
47 const char *extra_info, void *user_data)
49 MWR_LOGD("[Recorder] focus_mask : %d, focus_state : %d, reason : %d, [%s]",
50 focus_mask, focus_state, reason, extra_info);
52 if (nullptr == user_data) return;
54 /* The API description states that calling sound_manager_get_current_recording_focus()
55 function inside sound_stream_focus_state_watch_cb() function is prohibited */
56 ecore_main_loop_thread_safe_call_async(
58 CAudioManager *manager = static_cast<CAudioManager*>(data);
60 manager->sound_focus_changed();
65 int CAudioManager::initialize(void)
67 sound_manager_add_focus_state_watch_cb(SOUND_STREAM_FOCUS_FOR_RECORDING,
68 recording_focus_state_watch_cb, this, &mSoundFocusWatchId);
72 int CAudioManager::deinitialize(void)
75 if (mStreamingThread.joinable()) {
76 MWR_LOGD("mStreamingThread is joinable, trying join()");
77 mStopStreamingThread.store(true);
79 mStreamingThread.join();
80 } catch (std::exception &e) {
81 MWR_LOGE("Exception thrown : %s", e.what());
84 mStopStreamingThread.store(false);
86 sound_manager_remove_focus_state_watch_cb(mSoundFocusWatchId);
91 void CAudioManager::sound_focus_changed()
93 sound_stream_focus_change_reason_e acquired_by;
95 char* extra_info = NULL;
96 int focus = sound_manager_get_current_recording_focus(&acquired_by, &sound_behavior, &extra_info);
97 MWR_LOGD("[Recorder] sound focus has changed : %d %d %d %s", focus,
98 (SOUND_MANAGER_ERROR_NO_DATA != focus ? acquired_by : -1),
99 (SOUND_MANAGER_ERROR_NO_DATA != focus ? sound_behavior : -1),
100 (SOUND_MANAGER_ERROR_NO_DATA != focus ? extra_info : ""));
101 if (SOUND_MANAGER_ERROR_NO_DATA == focus) {
102 if (mRecordingRequired && !mIsRecording) {
103 MWR_LOGD("[Recorder] Currently no other process has acquired sound focus, start recording");
104 start_recording(false);
108 MWR_LOGW("[Recorder] Sound focus acquired by other process, stop recording");
109 stop_recording(false);
118 void CAudioManager::subscribe(IAudioEventObserver *observer)
120 lock_guard<mutex> lock(mMutex);
122 mObservers.push_back(observer);
126 void CAudioManager::unsubscribe(IAudioEventObserver *observer)
128 lock_guard<mutex> lock(mMutex);
129 auto iter = find(mObservers.begin(), mObservers.end(), observer);
130 if (iter != mObservers.end()) {
131 mObservers.erase(iter);
135 void CAudioManager::stop_recording(bool proactive)
137 dependency_resolver_stop_recording();
139 mRecordingRequired = false;
141 mIsRecording = false;
144 void CAudioManager::start_recording(bool proactive)
147 stop_recording(false);
150 mRecordingRequired = true;
153 sound_stream_focus_change_reason_e acquired_by;
155 char* extra_info = NULL;
156 if (SOUND_MANAGER_ERROR_NO_DATA == sound_manager_get_current_recording_focus(&acquired_by, &sound_behavior, &extra_info)) {
157 MWR_LOGD("[Recorder] Currently no other process has acquired sound focus, start recording");
158 dependency_resolver_start_recording();
161 MWR_LOGW("[Recorder] Currently sound focus is acquired by other process, skip recording");
169 void CAudioManager::set_recording_session(recording_session session)
171 dependency_resolver_set_recording_session((unsigned int)session);
174 /* Need to consider adapting conventional producer-consumer model */
175 void CAudioManager::streaming_previous_audio_data_thread_func()
179 unique_lock<mutex> lock(mMutex, defer_lock);
181 /* get feedback data */
182 size_t audio_data_size = 0;
184 audio_data_size = mPreviousAudioData.size();
185 for (int index = 0; index < audio_data_size; index++) {
186 mas_speech_data& speech_data = mPreviousAudioData.at(index).data;
187 for (const auto& observer : mObservers) {
189 if (!observer->on_streaming_audio_data(
190 speech_data.event, speech_data.buffer, speech_data.len)) {
191 LOGE("[Recorder WARNING] One of the observer returned false");
195 if (MAS_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
196 MWR_LOGI("[INFO] Finish to send previous speech data");
201 if (mStopStreamingThread.load()) {
202 MWR_LOGI("[INFO] Stop Streaming Requested, returning");
211 static void validate_audio_data_event_field(const mas_speech_data &data)
213 if (data.event == MAS_SPEECH_STREAMING_EVENT_CONTINUE ||
214 data.event == MAS_SPEECH_STREAMING_EVENT_START ||
215 data.event == MAS_SPEECH_STREAMING_EVENT_FINISH ||
216 data.event == MAS_SPEECH_STREAMING_EVENT_FAIL) {
219 MWR_LOGE("mas_speech_data has event field : %d", data.event);
222 void CAudioManager::streaming_audio_data_thread_func(long long start_time)
226 mStreamingThreadActive.store(true);
228 unique_lock<mutex> lock(mMutex, defer_lock);
229 bool finish_event_sent = false;
232 auto lead = mAudioData.begin();
234 while (lead != mAudioData.end() && lead->time < start_time) {
238 MWR_LOGE("data_count : %zu", mAudioData.size());
241 while (!(mStopStreamingThread.load())) {
245 /* get feedback data */
247 auto end = mAudioData.end();
251 MWR_LOGD("[DEBUG] No feedback data. Waiting mode : %d", ret);
254 while (!(mStopStreamingThread.load())) {
255 this_thread::sleep_for(chrono::milliseconds(10));
257 end = mAudioData.end();
258 auto begin = mAudioData.begin();
259 vector<IAudioEventObserver*> observers = mObservers;
270 MWR_LOGD("[INFO] Resume thread");
273 if (g_speech_pcm_wait_count < cnt) {
274 unsigned char final_buffer[2] = {'\0', };
275 MWR_LOGE("[ERROR] Wrong request, there's no pcm data");
276 for (const auto& observer : observers) {
278 if (!observer->on_streaming_audio_data(
279 MAS_SPEECH_STREAMING_EVENT_FAIL, NULL, 0)) {
280 LOGE("[Recorder WARNING] One of the observer returned false");
282 if (!observer->on_streaming_audio_data(
283 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
284 LOGE("[Recorder WARNING] One of the observer returned false");
288 mStreamingThreadActive.store(false);
293 MWR_LOGD("[INFO] Finish to wait for new feedback data come");
295 /* resume feedback thread */
299 /* FIXME : Extracted audio data here should be used as previous audio data*/
302 end = mAudioData.end();
303 vector<IAudioEventObserver*> observers = mObservers;
307 mas_speech_data& speech_data = iter->data;
308 for (const auto& observer : observers) {
310 validate_audio_data_event_field(speech_data);
311 if (!observer->on_streaming_audio_data(
312 speech_data.event, speech_data.buffer, speech_data.len)) {
313 LOGE("[Recorder WARNING] One of the observer returned false");
318 if (MAS_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
319 MWR_LOGE("[INFO] Finish to get and send speech data");
320 finish_event_sent = true;
329 if (true != finish_event_sent) {
330 unsigned char final_buffer[2] = {'\0', };
332 vector<IAudioEventObserver*> observers = mObservers;
334 for (const auto& observer : observers) {
336 MWR_LOGE("No FINISH event sent yet, adding to finalize streaming session");
337 if (!observer->on_streaming_audio_data(
338 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
339 LOGE("[Recorder WARNING] One of the observer returned false");
344 mStreamingThreadActive.store(false);
348 void CAudioManager::add_audio_data(mas_speech_data& data, long long time)
350 long long delta = mAudioRecordingDurationMilliseconds;
352 notify_audio_data_recording(time, data.buffer, data.len);
354 mas_speech_data_with_time data_with_time;
355 data_with_time.data = data;
356 data_with_time.time = time;
358 static unsigned int num = 0;
359 const std::chrono::seconds interval(3);
360 static auto last = std::chrono::steady_clock::now();
361 auto now = std::chrono::steady_clock::now();
362 if (now - last > interval) {
363 MWR_LOGE("Feeding audio data : num(%d), now(%" PRId64 "), %d %zu",
364 num, now.time_since_epoch().count(),
365 mStreamingThreadActive.load(), mAudioData.size());
370 lock_guard<mutex> lock(mMutex);
372 /* Pop items only when the streaming is not activated */
373 if (!mStreamingThreadActive.load()) {
374 while(false == mAudioData.empty() && mAudioData.front().time < time - delta) {
375 const auto &front = mAudioData.front();
376 if (front.data.buffer) {
377 vm_free_simple(front.data.buffer);
379 mAudioData.pop_front();
382 validate_audio_data_event_field(data);
383 mAudioData.push_back(data_with_time);
386 void CAudioManager::feed_audio_data(mas_speech_streaming_event_e event, void* buffer, int len)
388 if (NULL == buffer || 0 == len) return;
390 mas_speech_data speech_data;
391 speech_data.buffer = vm_malloc_simple(len);
392 if (speech_data.buffer) {
393 long long time = get_current_milliseconds_after_epoch();
395 speech_data.event = event;
396 speech_data.len = len;
397 memcpy(speech_data.buffer, buffer, len);
398 add_audio_data(speech_data, time);
402 void CAudioManager::finalize_audio_data()
404 MWR_LOGI("Adding FINISH event to audio data list");
405 unsigned char final_buffer[2] = {'\0', };
406 mas_speech_data speech_data;
407 speech_data.event = MAS_SPEECH_STREAMING_EVENT_FINISH;
408 speech_data.len = sizeof(final_buffer);
409 speech_data.buffer = vm_malloc_simple(speech_data.len);
410 if (speech_data.buffer) {
411 long long time = get_current_milliseconds_after_epoch();
413 memcpy(speech_data.buffer, final_buffer, speech_data.len);
414 add_audio_data(speech_data, time);
418 void CAudioManager::clear_audio_data()
420 lock_guard<mutex> lock(mMutex);
421 while(!mAudioData.empty()) {
422 const auto &front = mAudioData.front();
423 if (front.data.buffer) {
424 vm_free_simple(front.data.buffer);
426 mAudioData.pop_front();
431 void CAudioManager::notify_audio_data_recording(long time, void* data, int len)
433 unique_lock<mutex> lock(mMutex, defer_lock);
435 vector<IAudioEventObserver*> observers = mObservers;
437 for (const auto& observer : observers) {
439 if (!observer->on_recording_audio_data(time, data, len)) {
440 LOGE("[Recorder WARNING] One of the observer returned false");
446 void CAudioManager::start_streaming_current_utterance_data(long long start_time)
449 if (mStreamingThread.joinable()) {
450 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
453 lock_guard<mutex> lock(mMutex);
454 mStreamingThread = thread(&CAudioManager::streaming_audio_data_thread_func, this, start_time);
457 void CAudioManager::stop_streaming_current_utterance_data()
460 if (mStreamingThread.joinable()) {
461 MWR_LOGD("mStreamingThread is joinable, trying join()");
462 mStopStreamingThread.store(true);
464 mStreamingThread.join();
465 } catch (std::exception &e) {
466 MWR_LOGE("Exception thrown : %s", e.what());
469 mStopStreamingThread.store(false);
471 /* FIXME : Need to move all the speech data to previous speech data for later use */
474 void CAudioManager::start_streaming_previous_utterance_data()
477 if (mStreamingPreviousThread.joinable()) {
478 MWR_LOGE("ERROR : mStreamingPreviousThread is joinable, will not start a new thread");
481 lock_guard<mutex> lock(mMutex);
482 mStreamingPreviousThread = thread(&CAudioManager::streaming_previous_audio_data_thread_func, this);
485 void CAudioManager::stop_streaming_previous_utterance_data()
488 if (mStreamingPreviousThread.joinable()) {
489 MWR_LOGD("mStreamingPreviousThread is joinable, trying join()");
490 mStopStreamingPreviousThread.store(true);
492 mStreamingPreviousThread.join();
493 } catch (std::exception &e) {
494 MWR_LOGE("Exception thrown : %s", e.what());
497 mStopStreamingThread.store(false);
500 void CAudioManager::start_streaming_follow_up_data()
503 if (mStreamingThread.joinable()) {
504 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
508 mStreamingThread = thread(&CAudioManager::streaming_audio_data_thread_func, this, 0);
511 void CAudioManager::stop_streaming_follow_up_data()
514 if (mStreamingThread.joinable()) {
515 MWR_LOGD("mStreamingThread is joinable, trying join()");
516 mStopStreamingThread.store(true);
517 mStreamingThread.join();
519 mStopStreamingThread.store(false);
522 void CAudioManager::set_background_volume(double ratio)
524 dependency_resolver_set_background_volume(ratio);