Modify noise suppression functionality 01/292801/6 accepted/tizen_unified_dev accepted/tizen/unified/20230620.022505 accepted/tizen/unified/dev/20230726.115817
authorJaechul Lee <jcsing.lee@samsung.com>
Mon, 15 May 2023 05:06:20 +0000 (14:06 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Fri, 16 Jun 2023 04:09:32 +0000 (13:09 +0900)
This commit added actual NS functionality to audio-io.
Furthermore audio_io_process_test was added.

[Version] 0.5.56
[Issue Type] New feature

Change-Id: Iff85c712541654c764b1fbf7edb279627cdef587
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
include/CAudioInfo.h
packaging/capi-media-audio-io.spec
src/cpp/CAudioIO.cpp
src/cpp/CAudioInfo.cpp
src/cpp/CPulseAudioClient.cpp
test/CMakeLists.txt
test/audio_io_process_test.c [new file with mode: 0644]
test/audio_io_test.c

index 4800cad..1b1163b 100644 (file)
@@ -21,6 +21,9 @@
 #ifdef __cplusplus
 
 #include <type_traits>
+#include <string>
+#include <sound_manager.h>
+#include <sound_manager_internal.h>
 
 namespace tizen_media_audio {
 
@@ -139,10 +142,10 @@ namespace tizen_media_audio {
         int getAudioIndex() noexcept;
         void setAudioIndex(int audioIndex) noexcept;
         int getSampleSize() noexcept;
-        void bindEchoCancelReferenceDeviceId(int id) noexcept;
+        void bindEchoCancelReferenceDeviceId(int id, sound_acoustic_echo_cancel_type_e type);
         int getEchoCancelReferenceDeviceId() noexcept;
-        void setNoiseSuppression(bool enable) noexcept;
-        bool getNoiseSuppression() noexcept;
+        void setNoiseSuppression(bool enable, sound_noise_suppression_type_e type);
+        std::string& getProcessorProperty() noexcept;
 
         /* Setter & Getter Utilities */
         const char* getConvertedStreamType();
@@ -200,6 +203,7 @@ namespace tizen_media_audio {
         int          __mAudioIndex;
         int          __mReferenceDeviceId;
         bool         __mNoiseSuppression;
+        std::string  __mProcessorProperty;
     };
 
 
index ba35f46..98554a2 100644 (file)
@@ -1,6 +1,6 @@
 Name:           capi-media-audio-io
 Summary:        An Audio Input & Audio Output library in Tizen Native API
-Version:        0.5.55
+Version:        0.5.56
 Release:        0
 Group:          Multimedia/API
 License:        Apache-2.0
@@ -91,6 +91,7 @@ find . -name '*.gcno' -exec cp --parents '{}' "$gcno_obj_dir" ';'
 %files tool
 %manifest %{name}.manifest
 %{_prefix}/bin/audio_io_test
+%{_prefix}/bin/audio_io_process_test
 
 %if 0%{?gcov:1}
 %files gcov
index 0131b4e..e337973 100644 (file)
@@ -226,19 +226,20 @@ void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
 
     if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN) {
         int device_id;
-        bool enabled;
+        bool noise_suppression_enabled;
+        sound_acoustic_echo_cancel_type_e aec_type;
+        sound_noise_suppression_type_e ns_type;
 
-        if ((errorCode = sound_manager_get_echo_cancel_reference_device(stream_info, &device_id)) != SOUND_MANAGER_ERROR_NONE)
+        if ((errorCode = sound_manager_get_echo_cancel_reference_device(stream_info, &device_id, &aec_type)) != SOUND_MANAGER_ERROR_NONE)
             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Can't get reference device [ret:%d]", errorCode); //LCOV_EXCL_LINE
 
         if (device_id != SOUND_MANAGER_STREAM_NO_REFERENCE_DEVICE)
-            getAudioInfo().bindEchoCancelReferenceDeviceId(device_id);
+            getAudioInfo().bindEchoCancelReferenceDeviceId(device_id, aec_type);
 
-        if ((errorCode = sound_manager_get_noise_suppression(stream_info, &enabled)) != SOUND_MANAGER_ERROR_NONE)
+        if ((errorCode = sound_manager_get_noise_suppression(stream_info, &noise_suppression_enabled, &ns_type)) != SOUND_MANAGER_ERROR_NONE)
             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Can't get noise suppression status [ret:%d]", errorCode); //LCOV_EXCL_LINE
 
-        if (enabled)
-            getAudioInfo().setNoiseSuppression(enabled);
-
+        if (noise_suppression_enabled)
+            getAudioInfo().setNoiseSuppression(noise_suppression_enabled, ns_type);
     }
 }
index 1fb506b..f5d2666 100644 (file)
@@ -125,7 +125,15 @@ int CAudioInfo::getSampleSize() noexcept {
     return bytes_in_sample * static_cast<int>(__mChannel);
 }
 
-void CAudioInfo::bindEchoCancelReferenceDeviceId(int id) noexcept {
+void CAudioInfo::bindEchoCancelReferenceDeviceId(int id, sound_acoustic_echo_cancel_type_e type) {
+    if (type == SOUND_ACOUSTIC_ECHO_CANCEL_VOICE_CALL)
+        __mProcessorProperty += "webrtc,";
+    else if (type == SOUND_ACOUSTIC_ECHO_CANCEL_REFERENCE_COPY)
+        __mProcessorProperty += "reference_copy,";
+    else
+        THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE,
+                               "The echo cancel is not supported [type:%d]", type);
+
     __mReferenceDeviceId = id;
 }
 
@@ -133,12 +141,21 @@ int CAudioInfo::getEchoCancelReferenceDeviceId() noexcept {
     return __mReferenceDeviceId;
 }
 
-void CAudioInfo::setNoiseSuppression(bool enable) noexcept {
+void CAudioInfo::setNoiseSuppression(bool enable, sound_noise_suppression_type_e type) {
+    if (type == SOUND_NOISE_SUPPRESSION_VOICE_CALL) {
+        __mProcessorProperty += "rnnoise,";
+    } else if (type == SOUND_NOISE_SUPPRESSION_VOICE_RECOGNITION) {
+        __mProcessorProperty += "pse,";
+    } else {
+        THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE,
+                               "The noise suppression type is not supported [type:%d]", type);
+    }
+
     __mNoiseSuppression = enable;
 }
 
-bool CAudioInfo::getNoiseSuppression() noexcept {
-    return __mNoiseSuppression;
+std::string& CAudioInfo::getProcessorProperty() noexcept {
+    return __mProcessorProperty;
 }
 
 const char* CAudioInfo::getConvertedStreamType() {
index 8d4bb43..34f769a 100644 (file)
@@ -414,12 +414,12 @@ void CPulseAudioClient::initialize() {
         if (__mDirection == EStreamDirection::STREAM_DIRECTION_RECORD) {
             int reference_id = __mSpec.getAudioInfo().getEchoCancelReferenceDeviceId();
             if (reference_id > 0) {
-                pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_ECHO_CANCEL_METHOD, "%s", ec_method);
                 pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_ECHO_CANCEL_REFERENCE_DEVICE, "%d", reference_id);
             }
 
-            if (__mSpec.getAudioInfo().getNoiseSuppression())
-                pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_NOISE_SUPPRESSION_ENABLE, "%d", true);
+            if (!__mSpec.getAudioInfo().getProcessorProperty().empty())
+                pa_proplist_setf(__mpPropList, PA_PROP_MEDIA_PREPROCESSOR_METHOD, "%s",
+                                    __mSpec.getAudioInfo().getProcessorProperty().c_str());
         }
 
         // Adds latency on proplist for delivery to PULSEAUDIO
index 9505dff..9684f82 100644 (file)
@@ -17,3 +17,4 @@ FOREACH(src ${sources})
 ENDFOREACH()
 
 INSTALL(TARGETS audio_io_test DESTINATION bin)
+INSTALL(TARGETS audio_io_process_test DESTINATION bin)
diff --git a/test/audio_io_process_test.c b/test/audio_io_process_test.c
new file mode 100644 (file)
index 0000000..d0e1bfb
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sound_manager.h>
+#include <sound_manager_internal.h>
+#include <audio_io.h>
+
+static bool arg_aec_is_set;
+static int arg_aec_ref;
+static sound_acoustic_echo_cancel_type_e arg_aec_type;
+
+static bool arg_ns_is_set;
+static sound_noise_suppression_type_e arg_ns_type;
+
+static int arg_samplerate;
+static audio_channel_e arg_channels;
+static audio_sample_type_e arg_format;
+
+static char arg_filename[256];
+
+static int ch_table[] = { 0, AUDIO_CHANNEL_MONO, AUDIO_CHANNEL_STEREO,
+                          AUDIO_CHANNEL_MULTI_3, AUDIO_CHANNEL_MULTI_4, AUDIO_CHANNEL_MULTI_5,
+                          AUDIO_CHANNEL_MULTI_6, AUDIO_CHANNEL_MULTI_7, AUDIO_CHANNEL_MULTI_8,
+                          AUDIO_CHANNEL_MULTI_9, AUDIO_CHANNEL_MULTI_10, AUDIO_CHANNEL_MULTI_11,
+                          AUDIO_CHANNEL_MULTI_12, AUDIO_CHANNEL_MULTI_13, AUDIO_CHANNEL_MULTI_14,
+                          AUDIO_CHANNEL_MULTI_15, AUDIO_CHANNEL_MULTI_16 };
+static void record()
+{
+       int ret, size;
+       sound_stream_info_h stream_info;
+       audio_in_h input = NULL;
+       FILE *fp = NULL;
+       char *buffer = NULL;
+
+       sound_device_list_h device_list = NULL;
+       sound_device_h device;
+       bool found = false;
+       int id;
+
+       ret = audio_in_create(arg_samplerate, ch_table[arg_channels], AUDIO_SAMPLE_TYPE_S16_LE, &input);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               printf("audio in create error = 0x%x\n", ret);
+               goto out;
+       }
+
+       ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
+       if (ret) {
+               printf("fail to sound_manager_create_stream_information(), ret(0x%x)\n", ret);
+               goto out;
+       }
+
+       if (arg_aec_is_set) {
+               if (sound_manager_get_device_list(SOUND_DEVICE_ALL_MASK, &device_list) != SOUND_MANAGER_ERROR_NONE) {
+                       printf("fail to get device list");
+                       goto out;
+               }
+
+               while (sound_manager_get_next_device(device_list, &device) == SOUND_MANAGER_ERROR_NONE) {
+                       if (sound_manager_get_device_id(device, &id) != SOUND_MANAGER_ERROR_NONE)
+                               goto out;
+
+                       if (arg_aec_ref == id) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       printf("Failed to find reference device");
+                       goto out;
+               }
+
+               ret = sound_manager_set_echo_cancel_reference_device(stream_info, device, arg_aec_type);
+               if (ret != SOUND_MANAGER_ERROR_NONE) {
+                       printf("fail to sound_manager_set_echo_cancel_reference_device(), ret(0x%x)\n", ret);
+                       goto out;
+               }
+
+               /* verify */
+               {
+                       int device_id;
+                       int id;
+                       sound_acoustic_echo_cancel_type_e aec_type;
+
+                       ret = sound_manager_get_echo_cancel_reference_device(stream_info, &device_id, &aec_type);
+                       if (ret != SOUND_MANAGER_ERROR_NONE) {
+                               printf("fail to sound_manager_get_echo_cancel_reference_device(), ret(0x%x)\n", ret);
+                               goto out;
+                       }
+
+                       if (sound_manager_get_device_id(device, &id)) {
+                               printf("fail to sound_manager_device_id\n");
+                               goto out;
+                       }
+
+                       if (device_id != id || arg_aec_type != aec_type) {
+                               printf("fail to verify aec args\n");
+                               goto out;
+                       }
+               }
+       }
+
+       if (arg_ns_is_set) {
+               ret = sound_manager_set_noise_suppression(stream_info, arg_ns_is_set, arg_ns_type);
+               if (ret != SOUND_MANAGER_ERROR_NONE) {
+                       printf("failed to sound_manager_set_noise_suppression(), ret(0x%x)\n", ret);
+                       goto out;
+               }
+
+               /* verify */
+               {
+                       bool ns_enabled;
+                       sound_noise_suppression_type_e ns_type;
+
+                       ret = sound_manager_get_noise_suppression(stream_info, &ns_enabled, &ns_type);
+                       if (ret != SOUND_MANAGER_ERROR_NONE) {
+                               printf("fail to sound_manager_get_echo_cancel_reference_device(), ret(0x%x)\n", ret);
+                               goto out;
+                       }
+
+                       if (arg_ns_is_set != ns_enabled || arg_ns_type != ns_type) {
+                               printf("fail to verify ns args\n");
+                               goto out;
+                       }
+               }
+       }
+
+       ret = audio_in_set_sound_stream_info(input, stream_info);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               printf("fail to audio_in_set_sound_stream_info(), ret(0x%x)\n", ret);
+               goto out;
+       }
+
+       ret = audio_in_prepare(input);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               printf("ERROR, prepare\n");
+               goto out;
+       }
+
+       ret = audio_in_get_buffer_size(input, &size);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               printf("ERROR, get_buffer_size\n");
+               goto out;
+       }
+
+       fp = fopen(arg_filename, "wb+");
+       if (fp == NULL) {
+               printf("ERROR, file open failed\n");
+               goto out;
+       }
+
+       buffer = alloca(size);
+
+       while (1) {
+               ret = audio_in_read(input, (void *)buffer, size);
+               if (ret <= 0) {
+                       printf("FAIL, size=%d, ret=0x%x\n", size, ret);
+                       goto out;
+               }
+
+               fwrite(buffer, size, sizeof(char), fp);
+       }
+
+out:
+       if (fp)
+               fclose(fp);
+
+       if (input) {
+               audio_in_unprepare(input);
+               audio_in_destroy(input);
+       }
+
+       if (device_list)
+               if (sound_manager_free_device_list(device_list) != SOUND_MANAGER_ERROR_NONE)
+                       printf("fail to free device list\n");
+
+       return;
+}
+
+int main(int argc, char **argv)
+{
+       setbuf(stdout, NULL);
+       const char *optstring = "r:c:f:a:n:o:d:";
+       int option;
+
+       arg_channels = AUDIO_CHANNEL_MONO;
+       arg_format = AUDIO_SAMPLE_TYPE_S16_LE;
+
+       printf("===== Arguments information =====\n");
+       while (-1 != (option = getopt(argc, argv, optstring))) {
+               switch (option) {
+                       case 'r': /* rate */
+                               arg_samplerate = atoi(optarg);
+                               printf("Samplerate : %d\n", arg_samplerate);
+                               break;
+                       case 'd': /* reference device */
+                               arg_aec_ref = atoi(optarg);
+                               arg_aec_is_set = true;
+                               printf("AEC reference device : %d\n", arg_aec_ref);
+                               break;
+                       case 'a': /* AEC method */
+                               arg_aec_type = atoi(optarg);
+                               arg_aec_is_set = true;
+                               printf("AEC reference type: %d\n", arg_aec_type);
+                               break;
+                       case 'n': /* Noise suppression method */
+                               arg_ns_type = atoi(optarg);
+                               arg_ns_is_set = true;
+                               printf("Noise Suppression Type : %d\n", arg_ns_type);
+                               break;
+                       case 'o': /* output file */
+                               snprintf(arg_filename, sizeof(arg_filename), "%s", optarg);
+                               printf("Output filename : %s\n", arg_filename);
+                               break;
+                       case 'c': /* channels */
+                               arg_channels = atoi(optarg);
+                               printf("Channels : %d\n", arg_channels);
+                               break;
+                       case 'f': /* format */
+                               arg_format = atoi(optarg);
+                               printf("Format : %d\n", arg_format);
+                               break;
+                       case 'h':
+                       default:
+                               printf("audio_io_process_test -r [sample] [-d:reference_device_id] [-a:AEC type] [-n:NS type] -o [output filename]\n");
+                               printf("audio_io_process_test -r 16000 -d 1 -a 0 -n 0 -o filename\n");
+                               return 0;
+               }
+       }
+       printf("=================================\n");
+
+       record();
+       printf("END\n");
+
+       return 0;
+}
index b1f81b9..a339872 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -314,7 +314,7 @@ static void *_record_echo_cancel_thread(void *userdata)
                        goto out;
                }
 
-               ret = sound_manager_set_echo_cancel_reference_device(stream_info, device);
+               ret = sound_manager_set_echo_cancel_reference_device(stream_info, device, SOUND_ACOUSTIC_ECHO_CANCEL_VOICE_CALL);
                if (ret != SOUND_MANAGER_ERROR_NONE) {
                        printf("fail to sound_manager_set_echo_cancel_reference_device(), ret(0x%x)\n", ret);
                        goto out;