【发布时间】: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);
}
}
【问题讨论】:
标签: c# .net audio twilio naudio