首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >启用扬声器时失真的麦克风音频(Xamarin.iOS)

启用扬声器时失真的麦克风音频(Xamarin.iOS)
EN

Stack Overflow用户
提问于 2021-03-12 08:44:59
回答 1查看 159关注 0票数 0

我正在维护一个推到谈的VoIP应用程序。当PTT调用运行时,应用程序创建一个音频会话

代码语言:javascript
运行
复制
m_AudioSession = AVAudioSession.SharedInstance();

NSError error;
if (!m_AudioSession.SetCategory(AVAudioSession.CategoryPlayAndRecord, AVAudioSessionCategoryOptions.DefaultToSpeaker | AVAudioSessionCategoryOptions.AllowBluetooth, out error))
{
    IOSErrorLogger.Log(DammLoggerLevel.Error, TAG, error, "Error setting the category");
}

if (!m_AudioSession.SetMode(AVAudioSession.ModeVoiceChat, out error))
{
    IOSErrorLogger.Log(DammLoggerLevel.Error, TAG, error, "Error setting the mode");
}

if (!m_AudioSession.OverrideOutputAudioPort(AVAudioSessionPortOverride.Speaker, out error))
{
    IOSErrorLogger.Log(DammLoggerLevel.Error, TAG, error, "Error redirecting the audio to the loudspeaker");
}

if (!m_AudioSession.SetPreferredIOBufferDuration(0.06, out error)) // 60 milli seconds
{
    IOSErrorLogger.Log(DammLoggerLevel.Error, TAG, error, "Error setting the preferred buffer duration");
}

if (!m_AudioSession.SetPreferredSampleRate(8000, out error)) // kHz
{
    IOSErrorLogger.Log(DammLoggerLevel.Error, TAG, error, "Error setting the preferred sample rate");
}

if (!m_AudioSession.SetActive(true, out error))
{
    IOSErrorLogger.Log(DammLoggerLevel.Error, TAG, error, "Error activating the audio session");
}

接收到的音频使用OutputAudioQueue播放,麦克风音频使用语音处理I/O单元捕获(如Apple:https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616455-voicechat中提到的那样)。语音处理I/O单元的初始化代码是:

代码语言:javascript
运行
复制
            AudioStreamBasicDescription audioFormat = new AudioStreamBasicDescription()
            {
                SampleRate = SAMPLERATE_8000,
                Format = AudioFormatType.LinearPCM,
                FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger | AudioFormatFlags.LinearPCMIsPacked,
                FramesPerPacket = 1,
                ChannelsPerFrame = CHANNELS,
                BitsPerChannel = BITS_X_SAMPLE,
                BytesPerPacket = BYTES_X_SAMPLE,
                BytesPerFrame = BYTES_X_FRAME,
                Reserved = 0
            };

            AudioComponent audioComp = AudioComponent.FindComponent(AudioTypeOutput.VoiceProcessingIO);
            AudioUnit.AudioUnit voiceProcessing = new AudioUnit.AudioUnit(audioComp);

            AudioUnitStatus unitStatus = AudioUnitStatus.NoError;

            unitStatus = voiceProcessing.SetEnableIO(true, AudioUnitScopeType.Input, ELEM_Mic);
            if (unitStatus != AudioUnitStatus.NoError)
            {
                DammLogger.Log(DammLoggerLevel.Warn, TAG, "Audio Unit SetEnableIO(true, AudioUnitScopeType.Input, ELEM_Mic) returned: {0}", unitStatus);
            }

            unitStatus = voiceProcessing.SetEnableIO(true, AudioUnitScopeType.Output, ELEM_Speaker);
            if (unitStatus != AudioUnitStatus.NoError)
            {
                DammLogger.Log(DammLoggerLevel.Warn, TAG, "Audio Unit SetEnableIO(false, AudioUnitScopeType.Output, ELEM_Speaker) returned: {0}", unitStatus);
            }


            unitStatus = voiceProcessing.SetFormat(audioFormat, AudioUnitScopeType.Output, ELEM_Mic);
            if (unitStatus != AudioUnitStatus.NoError)
            {
                DammLogger.Log(DammLoggerLevel.Warn, TAG, "Audio Unit SetFormat (MIC-OUTPUT) returned: {0}", unitStatus);
            }

            unitStatus = voiceProcessing.SetFormat(audioFormat, AudioUnitScopeType.Input, ELEM_Speaker);
            if (unitStatus != AudioUnitStatus.NoError)
            {
                DammLogger.Log(DammLoggerLevel.Warn, TAG, "Audio Unit SetFormat (ELEM 0-INPUT) returned: {0}", unitStatus);
            }

            unitStatus = voiceProcessing.SetRenderCallback(AudioUnit_RenderCallback, AudioUnitScopeType.Input, ELEM_Speaker);
            if (unitStatus != AudioUnitStatus.NoError)
            {
                DammLogger.Log(DammLoggerLevel.Warn, TAG, "Audio Unit SetRenderCallback returned: {0}", unitStatus);
            }
            
            ...
            
            voiceProcessing.Initialize();
            voiceProcessing.Start();

RenderCallback函数是:

代码语言:javascript
运行
复制
private AudioUnitStatus AudioUnit_RenderCallback(AudioUnitRenderActionFlags actionFlags, AudioTimeStamp timeStamp, uint busNumber, uint numberFrames, AudioBuffers data)
{
    AudioUnit.AudioUnit voiceProcessing = m_VoiceProcessing;
    if (voiceProcessing != null)
    {
        // getting microphone input signal
        var status = voiceProcessing.Render(ref actionFlags, timeStamp, ELEM_Mic, numberFrames, data);
        if (status != AudioUnitStatus.OK)
        {
            return status;
        }

        if (data.Count > 0)
        {
            unsafe
            {
                short* samples = (short*)data[0].Data.ToPointer();

                for (uint idxSrcFrame = 0; idxSrcFrame < numberFrames; idxSrcFrame++)
                {
                   ... send the collected microphone audio (samples[idxSrcFrame])
                }
            }
        }
    }

    return AudioUnitStatus.NoError;
}

我所面临的问题是,如果启用了扬声器: m_AudioSession.OverrideOutputAudioPort(AVAudioSessionPortOverride.Speaker,out错误),那么麦克风音频就会损坏(有时无法理解该讲话)。如果没有启用扬声器(没有设置AVAudioSessionPortOverride.Speaker ),那么音频是非常好的。

我已经验证了渲染函数返回的NumberChannels中的AudioBuffer是1(单音频)。

任何帮助解决问题的命中都是非常感谢的。谢谢

更新: AudioUnit_RenderCallback方法每隔32 ms调用一次。当扬声器被禁用时,接收到的帧数为256帧,这是准确的(采样率为8000)。当扬声器启用时,接收到的帧数为85。在这两种情况下,GetAudioFormat返回预期值: BitsPerChannel=16、BytesPerFrame=2、FramesPerPacket=1、ChannelsPerFrame=1、SampleRate=8000

更新:我最终使用了来自硬件的采样率,并执行下采样自我。必须理解的是,音频单元应该能够执行下行采样https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html#//apple_ref/doc/uid/TP40009492-CH3-SW11),但当扬声器启用时,我不可能使它工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-16 15:25:55

我希望你是在一个实际的设备上测试这个,而不是一个模拟器.

在代码中,您是否尝试使用以下方法:

代码语言:javascript
运行
复制
sampleRate = AudioSession.CurrentHardwareSampleRate;

与其强制采样率,不如从硬件中检查采样率。可能是在使用扬声器的过程中,它改变了采样率,从而产生了问题。

我建议根据以上的变化录制,看看音频是否有所改善,然后用其他标志进行实验。

标准记录模式:https://learn.microsoft.com/en-us/dotnet/api/audiotoolbox.audiostreambasicdescription?view=xamarin-ios-sdk-12#remarks

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66596727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档