美文网首页视频开发音视频
ios 回声消除,基于Audio Unit

ios 回声消除,基于Audio Unit

作者: huisedediao | 来源:发表于2017-11-28 16:24 被阅读1083次

    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];
    

    相关文章

      网友评论

      • Tomychen:博主你好,我这边遇到一个问题:使用XBEchoCancellation进行录制,然后用AVAudioPlayer播放其他音乐,就会出现AVAudioPlayer播放的音乐声音很小的问题,不知道博主有没有遇到过?
        huisedediao:@Ctiy
        用AVAudioPlayer播放音乐前,设置下AudioSession
      • 强哥1号拖拉机1:博主,你好。我在使用你demo 的时候出现一个问题,看能不能帮忙解决一下。
        1,首先,我添加了背景音乐,我在点击开始录音的时候播放背景音乐,用扬声器播放出来。
        2,背景音乐播放时,我说话录音,40s后背景音乐播放完了,录音完成。
        3,最后点击播放录音的时候,发现录音不是很清晰,会出现说话断断续续,不连贯,偶尔出现一点点背景音乐。
        请问这是什么原因呢?是否有好的方法解决这个问题?谢谢!!!!!
        huisedediao:代码更新了,你试下。

        回调函数里不要做耗时的操作,包括分配内存,NSLog这些
      • jixiaojiid都被人抢了:[XBEchoCancellation shared].bl_output = ^(AudioBufferList *bufferList, UInt32 inNumberFrames) {
        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;
        }
        你好,我这样写什么声音都没有
        jixiaojiid都被人抢了:@huisedediao 检查过了,是一样的,是单声道
        huisedediao:@jixiaojiid都被人抢了
        检查下你音频的位数和码率是否和XBEchoCancellation设置的一样,检查下是否是单声道数据
      • 今年27:for (int i = 0 ; i < frames; i++) {
        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解码,解码后再弄,请问这样对吗? 反正声音不对
        今年27:@丶QianYe 我是两个手机之间的通话,码率肯定是一样的,不过我正在尝试,目前就是有杂音
        huisedediao:@今年27
        检查下码率、位数是不是和库里的一样,不一样的话,对_frame_size进行调整。
        检查下声道数是不是单声道,双声道数据要先转成单声道。
      • Unity与iOS的灵魂小白:在吗 一直输出。 没有开启声音输出回调 怎么回事啊 步骤都是对的 能帮我解决下吗
      • WKX_iOS:大神,有Demo可以看嘛,不会使用啊,刚接触这一块,也不知道怎么在录音的时候调用,怎么输出到文件并保存在本地
        huisedediao:@WKX_iOS
        GitHub更新了demo,可以参考下
        WKX_iOS:Audio Unit怎么录音和播放呢,目前只会操作AVAudioRecorder,player这些简单的
      • Libero_8573:-(void)playAudioFrame:(uint8_t *)buf withSize:(uint32_t)bufSize{

        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];

        }这样子还是播放声音不正常,采样率都是对的,求请教
        huisedediao:不好意思这段时间太忙,更新了demo,可以参考demo
      • 冬的天:-(void)decodeAudio:(char *)buffer Size:(unsigned int)size time:(unsigned int)time{

        XBEchoCancellation *echo = [XBEchoCancellation shared];
        echo.bl_output = ^(AudioBufferList *bufferList,UInt32 inNumberFrames){

        };
        [echo startOutput];
        }
        能请问一下我要怎么才能把我的buffer和size传进去?
        能帮下忙吗?谢谢🙏!
        huisedediao:更新了demo,可以参考下
        huisedediao:AudioBuffer buffer = bufferList->mBuffers[0];
        char data[buffer.mDataByteSize];

        //读取数据(数据从服务起来,已经做好了缓存),这里读取数据的方法看你是怎么写的
        int len = dataBuf->read_data(data, buffer.mDataByteSize);

        //把pcm数据赋值给buffer,下面这两句就是你要的把数据和size传给buffer
        memcpy(buffer.mData, data, len);
        buffer.mDataByteSize = len;
      • f9fd214fa70f:博主,实例化后并扬声器或听筒都没有声音输出,怎么用的?XBEchoCancellation *echo = [XBEchoCancellation shared];[echo startInput];[echo startOutput];
        huisedediao:@song_d6bc
        不是的。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;
        f9fd214fa70f:@丶QianYe 谢谢回复,因之前没有涉及音视频方向,不是很明白。pcm数据是从 echo.bl_input = ^(AudioBufferList *bufferList) {
        AudioBuffer buffer = bufferList->mBuffers[0];
        // buffer即从麦克风获取到的数据,默认已经消除了回音

        };里的AudioBuffer buffer 获取吗?怎么获取呢?又怎么赋值给bl_output 里的buffer呢?
        huisedediao:XBEchoCancellation *echo = [XBEchoCancellation shared];
        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)//位数
      • 小mark哥:有用,谢谢。
      • huisedediao:关于播放pcm音频数据这块的回调解释下,因为有的小伙伴有疑问。
        Audio Unit播放pcm的回调方法里,给的是一个指针,也就是地址,Audio Unit会播放该地址的数据,我们只要把要播放的声音数据填充到该地址即可
        BryanHong:@丶QianYe 播放的时候同时录音,会出现录音有时候没录到的问题,怎么解决呢

      本文标题:ios 回声消除,基于Audio Unit

      本文链接:https://www.haomeiwen.com/subject/zgkebxtx.html