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 MWR_LOGI("No FINISH event sent yet, adding to finalize streaming session");
314 if (!observer->on_streaming_audio_data(
315 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
316 LOGE("[Recorder WARNING] One of the observer returned false");
324 void CAudioManager::add_audio_data(mas_speech_data& data, long long time)
326 long long delta = mAudioRecordingDurationMilliseconds;
328 notify_audio_data_recording(time, data.buffer, data.len);
330 mas_speech_data_with_time data_with_time;
331 data_with_time.data = data;
332 data_with_time.time = time;
334 lock_guard<mutex> lock(mMutex);
336 /* Pop items only when the streaming is not activated */
337 while(false == mAudioData.empty() && mAudioData.front().time < time - delta) {
338 const auto &front = mAudioData.front();
339 if (front.data.buffer) {
340 vm_free_simple(front.data.buffer);
342 mAudioData.pop_front();
344 mAudioData.push_back(data_with_time);
347 void CAudioManager::feed_audio_data(mas_speech_streaming_event_e event, void* buffer, int len)
349 if (NULL == buffer || 0 == len) return;
351 mas_speech_data speech_data;
352 speech_data.buffer = vm_malloc_simple(len);
353 if (speech_data.buffer) {
354 long long time = get_current_milliseconds_after_epoch();
356 speech_data.event = event;
357 speech_data.len = len;
358 memcpy(speech_data.buffer, buffer, len);
359 add_audio_data(speech_data, time);
363 void CAudioManager::finalize_audio_data()
365 MWR_LOGI("Adding FINISH event to audio data list");
366 unsigned char final_buffer[2] = {'\0', };
367 mas_speech_data speech_data;
368 speech_data.event = MAS_SPEECH_STREAMING_EVENT_FINISH;
369 speech_data.len = sizeof(final_buffer);
370 speech_data.buffer = vm_malloc_simple(speech_data.len);
371 if (speech_data.buffer) {
372 long long time = get_current_milliseconds_after_epoch();
374 memcpy(speech_data.buffer, final_buffer, speech_data.len);
375 add_audio_data(speech_data, time);
379 void CAudioManager::clear_audio_data()
381 lock_guard<mutex> lock(mMutex);
382 while(!mAudioData.empty()) {
383 const auto &front = mAudioData.front();
384 if (front.data.buffer) {
385 vm_free_simple(front.data.buffer);
387 mAudioData.pop_front();
392 void CAudioManager::notify_audio_data_recording(long time, void* data, int len)
394 for (const auto& observer : mObservers) {
396 if (!observer->on_recording_audio_data(time, data, len)) {
397 LOGE("[Recorder WARNING] One of the observer returned false");
403 void CAudioManager::start_streaming_current_utterance_data(long long start_time)
406 if (mStreamingThread.joinable()) {
407 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
410 lock_guard<mutex> lock(mMutex);
411 mStreamingThread = thread(&CAudioManager::streaming_audio_data_thread_func, this, start_time);
414 void CAudioManager::stop_streaming_current_utterance_data()
417 if (mStreamingThread.joinable()) {
418 MWR_LOGD("mStreamingThread is joinable, trying join()");
419 mStopStreamingThread.store(true);
421 mStreamingThread.join();
422 } catch (std::exception &e) {
423 MWR_LOGE("Exception thrown : %s", e.what());
426 mStopStreamingThread.store(false);
428 /* FIXME : Need to move all the speech data to previous speech data for later use */
431 void CAudioManager::start_streaming_previous_utterance_data()
434 if (mStreamingPreviousThread.joinable()) {
435 MWR_LOGE("ERROR : mStreamingPreviousThread is joinable, will not start a new thread");
438 lock_guard<mutex> lock(mMutex);
439 mStreamingPreviousThread = thread(&CAudioManager::streaming_previous_audio_data_thread_func, this);
442 void CAudioManager::stop_streaming_previous_utterance_data()
445 if (mStreamingPreviousThread.joinable()) {
446 MWR_LOGD("mStreamingPreviousThread is joinable, trying join()");
447 mStopStreamingPreviousThread.store(true);
449 mStreamingPreviousThread.join();
450 } catch (std::exception &e) {
451 MWR_LOGE("Exception thrown : %s", e.what());
454 mStopStreamingThread.store(false);
457 void CAudioManager::start_streaming_follow_up_data()
460 if (mStreamingThread.joinable()) {
461 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
465 mStreamingThread = thread(&CAudioManager::streaming_audio_data_thread_func, this, 0);
468 void CAudioManager::stop_streaming_follow_up_data()
471 if (mStreamingThread.joinable()) {
472 MWR_LOGD("mStreamingThread is joinable, trying join()");
473 mStopStreamingThread.store(true);
474 mStreamingThread.join();
476 mStopStreamingThread.store(false);
479 void CAudioManager::set_background_volume(double ratio)
481 dependency_resolver_set_background_volume(ratio);