原创作品,允许转载,转载时请务必以超链接形式标明文章
原始出处 、作者信息和本声明。否则将追究法律责任。
http://billhoo.blog.51cto.com/2337751/1213801
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
/***
* Summary
* types:
* NSinst_t : the type of noise suppression instance structure.
* NsHandle : actually the same type of NSinst_t, defined in
* "noise_suppression.h" as a empty struct type named
* "NsHandleT".
*
* Note:
* 1.You have no need to pass env and jclazz to these functions,
* cus' JVM will does it for you.
* 2.We only support 10ms frames, that means you can only input 320
* Bytes a time.
**/
/**
* This function wraps the "WebRtcNs_Create" function in "noise_suppression.c".
* Input:
* none.
* Output:
* the handler of created noise suppression instance.
* Return value:
* -1 : error occurs.
* other value : available handler of created NS instance.
*
* @author billhoo
* @version 1.0 2013-1-29
*/
JNIEXPORT jint JNICALL
Java_你的类限定名_createNSInstance(JNIEnv *env,
jclass jclazz) {
NsHandle *hNS = NULL;
//create a pointer to NsHandle on native stack.
if
(WebRtcNs_Create(&hNS) == -1) {
//allocate dynamic memory on native heap for NS instance pointed by hNS.
return
-1;
//error occurs
}
else
{
return
((
int
) (NSinst_t *) hNS);
//returns the address of NS instance on native heap.
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/**
* This function wraps the "WebRtcNs_Init" function in
* "noise_suppression.c".
* Initializes a NS instance and has to be called before any other
* processing is made.
*
* Input:
* - nsHandler - Handler of NS instance that should be
* initialized.
* - sf - sampling frequency, only 8000, 16000, 32000
* are available.
* Output:
* nsHandler - the handler of initialized instance.
* Return value:
* 0 - OK
* -1 - Error
*
* @author billhoo
* @version 1.0 2013-1-29
*/
JNIEXPORT jint JNICALL
Java_你的类限定名_initiateNSInstance(JNIEnv *env,
jclass jclazz, jint nsHandler, jlong sf) {
NsHandle *hNS = (NsHandle*) nsHandler;
return
WebRtcNs_Init(hNS, sf);
}
|
1
2
3
4
5
6
7
8
9
|
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := webrtc_ns
LOCAL_SRC_FILES := \
noise_suppression.c \
ns_core.c \
fft4g.c \
ns_jni_wrapper.c
include $(BUILD_SHARED_LIBRARY)
|
![]() |
39人
| 了这篇文章 |
2013-06-14 13:52:06
你好,请问能把ns_jni_wrapper.c发给我参考下怎么写好么?我的总是编译不成so文件,谢谢帮助
2013-06-14 17:18:33
2013-06-26 19:54:24
BillHoo你好, 我是从StackOverflow追到这里来的。有一个问题不知道楼主有没有遇到过: WebRtcAecm_Process在去掉回声的同时把与回声重叠的那部分的原声也去掉了。还有一个问题啊,麦克风采集的PCM的buffer是作为WebRtcAecm_Process的第二个参数吗?不胜感激。
2013-06-26 21:07:14
回复 WebRtc_Aecm:
[4楼]
你好,很高兴你能追到这里来 1)我没有弄懂你说的回声和原声重叠是什么意思。消回声把原声消掉了,这种情况我仅在回环路径测试时遇到过,两台设备进行测试不会有此问题。 2)process函数原型如下 int32_t WebRtcAecm_Process(void* aecmInst,
const int16_t* nearendNoisy,
const int16_t* nearendClean,
int16_t* out,
int16_t nrOfSamples,
int16_t msInSndCardBuf);
其中 nearendNoisy 表示带有噪声的buf,nearendClean 表示经过降噪处理的 buf,建议首先使用NS将采集到的buf降噪,然后将原buf传给nearendNoisy ,降噪后的buf传给 nearendClean,如果不降噪,直接将buf传给nearendNoisy ,nearendClean置为NULL即可。
你好,很高兴你能追到这里来 1)我没有弄懂你说的回声和原声重叠是什么意思。消回声把原声消掉了,这种情况我仅在回环路径测试时遇到过,两台设备进行测试不会有此问题。 2)process函数原型如下 int32_t WebRtcAecm_Process(void* aecmInst,
const int16_t* nearendNoisy,
const int16_t* nearendClean,
int16_t* out,
int16_t nrOfSamples,
int16_t msInSndCardBuf);
其中 nearendNoisy 表示带有噪声的buf,nearendClean 表示经过降噪处理的 buf,建议首先使用NS将采集到的buf降噪,然后将原buf传给nearendNoisy ,降噪后的buf传给 nearendClean,如果不降噪,直接将buf传给nearendNoisy ,nearendClean置为NULL即可。
2013-06-27 09:54:30
回复 Bill_Hoo:
[5楼]
多谢你的回复!
回声和原声重叠的意思是回声和原声同一时刻进入到麦克风,我将它称之为“重叠”
回环路径测试是怎样的场景和配置呢?
我现在的测试环境是这样搭的: 从手机SD卡中以80字节为单位顺序读取一个pcm文件,送入到扬声器,同时调用WebRtcAecm_BufferFarend(), 然后读取麦克风采集到的数据的80字节,调用Process。再将out写入到aec.pcm文件。分析这个aec.pcm文件时,发现回声是被消除了,但是与回声处于同一时刻的原声也被消除了。
我这种测试思路有问题吗?
还有一个问题,降噪与否对回声抑制的效果影响大吗?
多谢 :)
多谢你的回复!
回声和原声重叠的意思是回声和原声同一时刻进入到麦克风,我将它称之为“重叠”
回环路径测试是怎样的场景和配置呢?
我现在的测试环境是这样搭的: 从手机SD卡中以80字节为单位顺序读取一个pcm文件,送入到扬声器,同时调用WebRtcAecm_BufferFarend(), 然后读取麦克风采集到的数据的80字节,调用Process。再将out写入到aec.pcm文件。分析这个aec.pcm文件时,发现回声是被消除了,但是与回声处于同一时刻的原声也被消除了。
我这种测试思路有问题吗?
还有一个问题,降噪与否对回声抑制的效果影响大吗?
多谢 :)
2013-06-27 11:47:35
回复 WebRtc_Aecm:
[6楼]
1.首先,我在stackoverflow里看到你调用时传的是8000Hz的采样率,也就是说你每次应该传入80个采样点,一个采样点是2个字节,你应该采集160字节/次才对。
2.对于AECM的测试,首先可以使用同一个PCM文件,分别放入FAREND和PROCESS,如果出来的结果接近全零,则验证你提取的AECM模块工作正常。
3.在验证AECM模块能够正常工作的前提下,你需要两台设备,每台设备两个线程,线程一用来采集和PROCESS,线程二用来播放和FAREND。
4.降噪与否对回声消除的效果:我的实验结果为:先消回声再降噪效果比先降噪再消回声好。
1.首先,我在stackoverflow里看到你调用时传的是8000Hz的采样率,也就是说你每次应该传入80个采样点,一个采样点是2个字节,你应该采集160字节/次才对。
2.对于AECM的测试,首先可以使用同一个PCM文件,分别放入FAREND和PROCESS,如果出来的结果接近全零,则验证你提取的AECM模块工作正常。
3.在验证AECM模块能够正常工作的前提下,你需要两台设备,每台设备两个线程,线程一用来采集和PROCESS,线程二用来播放和FAREND。
4.降噪与否对回声消除的效果:我的实验结果为:先消回声再降噪效果比先降噪再消回声好。
2013-06-27 13:17:45
回复 Bill_Hoo:
[8楼]
对于第1点,我也测试过传160字节,效果和80字节是差不多的。
对于第2点,结果会接近全零,但是在本地也有声音进入麦克风的情况下,与回声重叠的那部分原声也会被消掉(预期应该是不会被消掉的,这和你的回环路径测试不一样,因为进入麦克风的"Normal Voice"没有再次进入扬声器,也就算不上是回声,而我猜你的回环路径测试是会再次被扬声器播放出来吧?)。
这就是我遇到的最主要问题。AECM是可以工作的,但是结果没有达到预期。我看了你的StackOverflow的回复,这一点应该是和时延没有关系的。
对于第1点,我也测试过传160字节,效果和80字节是差不多的。
对于第2点,结果会接近全零,但是在本地也有声音进入麦克风的情况下,与回声重叠的那部分原声也会被消掉(预期应该是不会被消掉的,这和你的回环路径测试不一样,因为进入麦克风的"Normal Voice"没有再次进入扬声器,也就算不上是回声,而我猜你的回环路径测试是会再次被扬声器播放出来吧?)。
这就是我遇到的最主要问题。AECM是可以工作的,但是结果没有达到预期。我看了你的StackOverflow的回复,这一点应该是和时延没有关系的。
2013-06-27 14:05:17
回复 WebRtcAecm:
[9楼]
你好,我仔细看了下你的思路
“从手机SD卡中读取一个pcm文件,送入到扬声器,同时调用WebRtcAecm_BufferFarend(), 然后读取麦克风采集到的数据,调用Process。再将out写入到aec.pcm文件。分析这个aec.pcm文件。”
发现你这里面根本不存在“原声”,何来原声被消除呢?
你使用固定文件作为声音来源,我们假设输入PCM数据为“A”,那么你送到扬声器的声音就为“A”,而麦克风采集到的声音为扬声器的“A”再加上背景噪声“B”(现在的B才是实际意义上的“原声”,假设你没说话),AECM的处理结果就是从“A+B”中找到被扬声器播放出去的“A”并进行消除,留下了“B”,而背景噪声也许比较小,结果也就仍然接近全零了,绕了一圈,你做的这个流程和我用同一个PCM文件分别放入farend和process是一个道理。
如果需要做回声测试,你需要两台设备,如我上一个回复所说。
希望对你有所帮助。
你好,我仔细看了下你的思路
“从手机SD卡中读取一个pcm文件,送入到扬声器,同时调用WebRtcAecm_BufferFarend(), 然后读取麦克风采集到的数据,调用Process。再将out写入到aec.pcm文件。分析这个aec.pcm文件。”
发现你这里面根本不存在“原声”,何来原声被消除呢?
你使用固定文件作为声音来源,我们假设输入PCM数据为“A”,那么你送到扬声器的声音就为“A”,而麦克风采集到的声音为扬声器的“A”再加上背景噪声“B”(现在的B才是实际意义上的“原声”,假设你没说话),AECM的处理结果就是从“A+B”中找到被扬声器播放出去的“A”并进行消除,留下了“B”,而背景噪声也许比较小,结果也就仍然接近全零了,绕了一圈,你做的这个流程和我用同一个PCM文件分别放入farend和process是一个道理。
如果需要做回声测试,你需要两台设备,如我上一个回复所说。
希望对你有所帮助。
2013-06-27 14:40:17
2013-06-27 14:54:04
回复 WebRtcAecm:
[11楼]
也就是说你的问题不在AECM这个模块上,而是你的测试思路。
你的问题就在于 —— 你的测试方法测出来本来就应该是这个结果,而你的预期却错误地认为会是另外一个结果。
搞清什么是“原声”,什么是“回声”就OK了。
也就是说你的问题不在AECM这个模块上,而是你的测试思路。
你的问题就在于 —— 你的测试方法测出来本来就应该是这个结果,而你的预期却错误地认为会是另外一个结果。
搞清什么是“原声”,什么是“回声”就OK了。
2013-06-27 14:59:41
回复 Bill_Hoo:
[12楼]
预期:"AECM的处理结果就是从“A+B”中找到被扬声器播放出去的“A”并进行消除,留下了“B”"
现在的结果是: B没有被完全留下,有一部分被消掉了。你假设我没有说话,实际我放了音乐并且被麦克风采集到了啊,这个音乐不是从扬声器出来的,这不算回声吗?我觉得这个音乐应该是被保留的吧?现在被部分消掉了。
预期:"AECM的处理结果就是从“A+B”中找到被扬声器播放出去的“A”并进行消除,留下了“B”"
现在的结果是: B没有被完全留下,有一部分被消掉了。你假设我没有说话,实际我放了音乐并且被麦克风采集到了啊,这个音乐不是从扬声器出来的,这不算回声吗?我觉得这个音乐应该是被保留的吧?现在被部分消掉了。
2013-06-27 15:11:10
音乐是连续的音源,和人声是有很大区别的,连续乐音中很可能某一段的数据被认为是和A中的数据匹配从而导致被消除,如果你非要这样测,应该在运行时说话,而不是放音乐。