2018.03.28
----- 好多同学私信不会用,GitHub项目添加了示例demo,具体使用参考demo
----- 添加了pcm转WAV的方法(我只是搬运工)
先说下为什么会有回声。
由于手机app(A端)需要一边录音一边播放声音。A端 在通过麦克风采集输入声音的时候,把手机正在播放的声音(由 B端 传输过来)也采集进去了,并将采集到的声音传到 B端 播放,因此在 B端 听起来除了有 A端 原本想要传的声音,还有 B端 之前传出去的声音,就造成了所谓的回声。
原理明白就好解决了,回声消除,就是将采集到的声音数据中的属于手机播放的那部分声音去除,Audio Unit 已经集成了回声消除功能,直接调用就行。
基于Audio Unit封装了一个回声消除的库,包括回声消除和对pcm数据进行播放。
传送门: XBEchoCancellation
使用:
获取麦克风输入:
XBEchoCancellation *echo = [XBEchoCancellation shared];
echo.bl_input = ^(AudioBufferList *bufferList) {
AudioBuffer buffer = bufferList->mBuffers[0];
// buffer即从麦克风获取到的数据,默认已经消除了回音
};
[echo startInput];
播放pcm音频数据:
XBEchoCancellation *echo = [XBEchoCancellation shared];
echo.bl_output = ^(AudioBufferList *bufferList, UInt32 inNumberFrames) {
AudioBuffer buffer = bufferList->mBuffers[0];
// 这里把要传给发声设备的pcm数据赋给buffer
};
[echo startOutput];
网友评论
用AVAudioPlayer播放音乐前,设置下AudioSession
1,首先,我添加了背景音乐,我在点击开始录音的时候播放背景音乐,用扬声器播放出来。
2,背景音乐播放时,我说话录音,40s后背景音乐播放完了,录音完成。
3,最后点击播放录音的时候,发现录音不是很清晰,会出现说话断断续续,不连贯,偶尔出现一点点背景音乐。
请问这是什么原因呢?是否有好的方法解决这个问题?谢谢!!!!!
回调函数里不要做耗时的操作,包括分配内存,NSLog这些
AudioBuffer buffer = bufferList->mBuffers[0];
char data[buffer.mDataByteSize];
int len = readPcmData(data, buffer.mDataByteSize, newPcmData);
memcpy(buffer.mData, data, len);
};
int readPcmData(char *data, int len, NSMutableData *dataStore)
{
NSData *subData = [dataStore subdataWithRange:NSMakeRange(_readerLength, len)];
Byte *tempByte = (Byte *)[subData bytes];
memcpy(data,tempByte,len);
_readerLength = _readerLength + len;
return len;
}
你好,我这样写什么声音都没有
检查下你音频的位数和码率是否和XBEchoCancellation设置的一样,检查下是否是单声道数据
NSData* out_data = [data subdataWithRange:NSMakeRange(i*_frame_size + 4, _frame_size)];
int nDecodedByte = sizeof(short) * [_speex decode:(Byte*)out_data.bytes length:_frame_size output:out_buffer];
NSData* decodeData = [NSData dataWithBytes:out_buffer length:nDecodedByte];
// [_audioDataPlayer inputNewDataFromBuffer:(Byte*)out_buffer size:nDecodedByte];
[XBEchoCancellation shared].bl_output = ^(AudioBufferList *bufferList, UInt32 inNumberFrames) {
AudioBuffer buffer = bufferList->mBuffers[0];
memcpy(buffer.mData, decodeData.bytes, nDecodedByte);
buffer.mDataByteSize = nDecodedByte;
NSLog(@"buffer:---->%d", nDecodedByte);
};
}
我对收到的数据先要用speex解码,解码后再弄,请问这样对吗? 反正声音不对
检查下码率、位数是不是和库里的一样,不一样的话,对_frame_size进行调整。
检查下声道数是不是单声道,双声道数据要先转成单声道。
GitHub更新了demo,可以参考下
iosAudio.bl_output = ^(AudioBufferList *bufferList, UInt32 inNumberFrames) {
AudioBuffer buffer = bufferList->mBuffers[0];
//读取数据(数据从服务起来,已经做好了缓存),这里读取数据的方法看你是怎么写的
//把pcm数据赋值给buffer,下面这两句就是你要的把数据和size传给buffer
memcpy(buffer.mData, buf, bufSize);
buffer.mDataByteSize = bufSize;
};
[iosAudio startOutput];
}这样子还是播放声音不正常,采样率都是对的,求请教
XBEchoCancellation *echo = [XBEchoCancellation shared];
echo.bl_output = ^(AudioBufferList *bufferList,UInt32 inNumberFrames){
};
[echo startOutput];
}
能请问一下我要怎么才能把我的buffer和size传进去?
能帮下忙吗?谢谢🙏!
char data[buffer.mDataByteSize];
//读取数据(数据从服务起来,已经做好了缓存),这里读取数据的方法看你是怎么写的
int len = dataBuf->read_data(data, buffer.mDataByteSize);
//把pcm数据赋值给buffer,下面这两句就是你要的把数据和size传给buffer
memcpy(buffer.mData, data, len);
buffer.mDataByteSize = len;
不是的。bl_input和bl_output是两个独立的回调。
bl_input这个回调,获取到的是你手机麦克风采集到的声音,你可以通过下面的代码获取到数据和数据的长度,传给服务器或者需要接收这个数据的设备:
AudioBuffer buffer = bufferList->mBuffers[0];
SInt16 *editBuffer = (SInt16 *)buffer.mData;
int length = buffer.mDataByteSize;
bl_output这个回调,是用来播放pcm数据的。pcm数据一般是从你的服务器或者摄像头这类的设备传输过来的,首先你要读取到数据,然后通过memcpy函数把数据赋给buffer,下面的代码你参考下:
char data[buffer.mDataByteSize];
//读取数据(数据从服务起来,已经做好了缓存)
int len = dataBuf->read_data(data, buffer.mDataByteSize);
//把pcm数据赋值给buffer
memcpy(buffer.mData, result, len);
buffer.mDataByteSize = len;
AudioBuffer buffer = bufferList->mBuffers[0];
// buffer即从麦克风获取到的数据,默认已经消除了回音
};里的AudioBuffer buffer 获取吗?怎么获取呢?又怎么赋值给bl_output 里的buffer呢?
echo.bl_output = ^(AudioBufferList *bufferList, UInt32 inNumberFrames) {
AudioBuffer buffer = bufferList->mBuffers[0];
// 这里把要传给发声设备的pcm数据赋给buffer
};
想要有声音输出,在上面的回调里,你得把你的pcm数据赋给上面的buffer,调用startOutput即可。
如果已经把数据赋值给buffer还是没声音或者都是杂音,看看声音数据的采样率、声道数和位数是不是和XBEchoCancellation默认的设置一样:
#define kRate (XBEchoCancellationRate_8k) //采样率
#define kChannels (1)//声道数
#define kBits (16)//位数
Audio Unit播放pcm的回调方法里,给的是一个指针,也就是地址,Audio Unit会播放该地址的数据,我们只要把要播放的声音数据填充到该地址即可