【问题标题】:How to convert PCM S16LE audio to MU-LAW/8000 using .NET (Windows/Mac/Linux)如何使用 .NET (Windows/Mac/Linux) 将 PCM S16LE 音频转换为 MU-LAW/8000
【发布时间】:2022-01-05 20:21:59
【问题描述】:

我正在尝试在 Twilio 语音呼叫和 Discord 语音通道之间接收和传输音频。 我正在努力弄清楚如何将从DSharpPlus(.NET 的 Discord 库)接收的音频数据转换为 Twilio Voice 所需的格式。

如果我正在阅读DSharpPlus' docs correctly,则来自 DSharpPlus 的 PCM 数据是 PCM S16LE 格式。 Twilio 希望数据采用 MU-LAW/8000 格式(我相信不包括标题)。

我正在尝试使用NAudio 转换数据,但我通过电话听到的只是尖锐的痛苦噪音。我不能使用完整的 NAudio 库,因为该项目应该在 Windows/Mac/Linux 上运行,并且一些 NAudio API 仅适用于 Windows。
这是我目前拥有的相关代码:

private async Task VoiceReceiveHandler(VoiceNextConnection connection, VoiceReceiveEventArgs args)
{
    
    if (twilioSocketConnectionManager.TryGetSocketById(socketId, out var twilioSocket) && twilioSocket.Socket.State == WebSocketState.Open)
    {
        var media = ConvertPcmToMulawBase64Encoded(args.AudioFormat, args.PcmData.ToArray());
        var json = JsonSerializer.Serialize<MediaMessage>
        (
            new MediaMessage("media", twilioSocket.StreamSid, new MediaPayload(media)), 
            jsonSerializerOptions
        );
        logger.LogInformation(json);
        var bytes = Encoding.Default.GetBytes(json);
        var arraySegment = new ArraySegment<byte>(bytes, 0, bytes.Length);
        await twilioSocket.Socket.SendAsync(arraySegment, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
    }
}

private static string ConvertPcmToMulawBase64Encoded(AudioFormat audioFormat, byte[] pcmData)
{
        
    var sourceFormat = new WaveFormat(audioFormat.SampleRate, 16, audioFormat.ChannelCount);
    return Convert.ToBase64String(EncodeMuLaw(pcmData, 0, pcmData.Length));
}

public static byte[] EncodeMuLaw(byte[] data, int offset, int length)
{
    var encoded = new byte[length / 2];
    int outIndex = 0;
    for(int n = 0; n < length; n+=2)
    {
        encoded[outIndex++] = MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(data, offset + n));
    }
    return encoded;
}

我还需要再次从 MU-LAW 转换为 PCM S16LE,但首先要做的是。
在音频处理方面我完全忘记了,所以请放轻松。

这里是其余的源代码:https://github.com/Swimburger/DiscordTwilioVoiceBot

基本上我的问题是,如何在支持 Windows/Linux/Mac 的同时使用 .NET 将 PCM S16LE 音频转换为 MU-LAW/8000


更新 1:

人们建议使用 ffmpeg 代替 NAudio,我认为我在这里做得正确,但我仍然听到尖锐的噪音而不是实际的音频。

private async Task VoiceReceiveHandler(VoiceNextConnection connection, VoiceReceiveEventArgs args)
{
    var ffmpeg = Process.Start(new ProcessStartInfo
    {
        FileName = "ffmpeg",
        Arguments = $@"-hide_banner -ac 2 -f s16le -ar 48000 -i pipe:0 -c:a pcm_mulaw -f mulaw -ar 8000 -ac 1 pipe:1",
        RedirectStandardInput = true,
        RedirectStandardOutput = true
    });

    //byte[] trimmedData = new byte[args.PcmData.Length - 44];
    //Buffer.BlockCopy(args.PcmData.ToArray(), 44, trimmedData, 0, trimmedData.Length);

    await ffmpeg.StandardInput.BaseStream.WriteAsync(args.PcmData);
    ffmpeg.StandardInput.Close();
    byte[] data;
    using(var memoryStream = new MemoryStream())
    {
        ffmpeg.StandardOutput.BaseStream.CopyTo(memoryStream);
        data = memoryStream.ToArray();
    }
    ffmpeg.Dispose();

    //byte[] trimmedData = new byte[data.Length - 44];
    //Buffer.BlockCopy(data, 44, trimmedData, 0, trimmedData.Length);

    //return;

    if (twilioSocketConnectionManager.TryGetSocketById(socketId, out var twilioSocket) && twilioSocket.Socket.State == WebSocketState.Open)
    {
        var json = JsonSerializer.Serialize<MediaMessage>
        (
            new MediaMessage("media", twilioSocket.StreamSid, new MediaPayload(Convert.ToBase64String(data))), 
            jsonSerializerOptions
        );
        logger.LogInformation(json);
        var bytes = Encoding.Default.GetBytes(json);
        var arraySegment = new ArraySegment<byte>(bytes, 0, bytes.Length);
        await twilioSocket.Socket.SendAsync(arraySegment, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
    }
}

这是separate branch

【问题讨论】:

    标签: c# .net audio twilio naudio


    【解决方案1】:

    我有一个类似的问题,将 Twilio 的 MU-LAW 转换为 PCM 16LE 以流式传输到 Azure 认知服务转录服务。我是用 Java 而不是 dotnet 编写的,但我没有找到好的库解决方案。

    但是,可以使用查找表一次一个字节地完成转换(请注意,一个字节的 mulaw 由 2 个字节的 pcm 表示)。有一个rather abstract description of the algorithm on wikipedia,我发现this dotnet repo 的代码很容易翻译成Java,而且运行良好。对于您的情况,您需要查看 MulawDecoder.cs。

    我为 mulaw->pcm 生成的 Java 代码是 here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-06
      • 2023-03-08
      相关资源
      最近更新 更多