聚会可能有点晚了,但我最近遇到了同样的问题,我想如果其他人有这个问题,我应该在这里分享我的解决方案。我还使用 RTP-proxy 来捕获保存为两个 .rtp 文件的音频流,每个通道一个,其中 .o。是发起呼叫者(呼叫者)和.a 的输出。是接听电话的人(被叫者)。
解决方案 1。
RTP-proxy 有一个内置模块,可以为您进行 wav 转换,称为“extractaudio”。该文档至少可以说,但您可以从命令行使用它,如下所示:
extractaudio -F wav -B /path/to/rtp /path/of/outfile.wav
这将一次将一个 RTP 文件转换为 WAV 文件。该模块使用 GSM 编码对创建的 WAV 文件进行编码。如果不希望这样做,您可以将-D pcm_16 作为额外参数传递给它,以将编码切换为线性 PCM 16,这是一种更好的保持音频质量的格式。我使用子进程的方式通过python以编程方式提取WAV文件,以便进行命令行调用。
解决方案 2。
您可以直接提取原始 RTP 数据并使用第三部分软件(如 SoX 或 FFmpeg)将其转换为 WAV 文件。此解决方案需要 SoX、FFmpeg 和 tshark 作为依赖项。如果您自己打开 RTP 文件并提取 UDP 数据,则可以不使用 tshark,但使用 tshark 可以轻松完成。
这是我的代码(Python 2.7.9):
import os
import subprocess
import shlex
import binascii
FILENAME = "my_file"
WORKING_DIR = os.path.dirname(os.path.realpath(__file__))
IN_FILE_O = "%s/%s.o.rtp" % (WORKING_DIR, FILENAME)
IN_FILE_A = "%s/%s.a.rtp" % (WORKING_DIR, FILENAME)
conversion_list = {"PCMU" : "sox -t ul -r 8000 -c 1 %s %s",
"GSM" : "sox -t gsm -r 8000 -c 1 %s %s" ,
"PCMA" : "sox -t al -r 8000 -c 1 %s %s",
"G722" : "ffmpeg -f g722 -i %s -acodec pcm_s16le -ar 16000 -ac 1 %s",
"G729": "ffmpeg -f g729 -i %s -acodec pcm_s16le -ar 8000 -ac 1 %s"
}
if __name__ == "__main__":
args_o = "tshark -n -r " + IN_FILE_O + " -T fields -e data"
args_a = "tshark -n -r " + IN_FILE_A + " -T fields -e data"
f_o = WORKING_DIR + "/" + "payload_o.g722"
f_a = WORKING_DIR + "/" + "payload_a.g722"
payload_o = subprocess.Popen(shlex.split(args_o), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).communicate()[0]
payload_a = subprocess.Popen(shlex.split(args_a), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).communicate()[0]
if os.path.exists(f_o):
os.remove(f_o)
if os.path.exists(f_a):
os.remove(f_a)
with open(f_o, "ab") as new_codec:
payload = payload_o.split("\n")
for line in payload:
line = line.rstrip()
tmp = "%s.o: " % FILENAME
for index, (op, code) in enumerate(zip(line[0::2], line[1::2])):
if index > 11:
new_codec.write(binascii.unhexlify(op + code))
with open(f_a, "ab") as new_codec:
payload = payload_a.split("\n")
for line in payload:
line = line.rstrip()
tmp = "%s.a: " % FILENAME
for index, (op, code) in enumerate(zip(line[0::2], line[1::2])):
if index > 11:
new_codec.write(binascii.unhexlify(op + code))
owav = WORKING_DIR + "/" + "%s.o.wav" % FILENAME
awav = WORKING_DIR + "/" + "%s.a.wav" % FILENAME
if os.path.exists(owav):
os.remove(owav)
if os.path.exists(awav):
os.remove(awav)
print("Creating %s with %s" % (owav, f_o))
print("Creating %s with %s" % (awav, f_a))
subprocess.Popen(shlex.split(conversion_list["G722"] % (f_o, owav)), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).communicate()[0]
subprocess.Popen(shlex.split(conversion_list["G722"] % (f_a, awav)), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).communicate()[0]
我在我的解决方案中将 G722 硬编码为输入数据,但如果您有正确的 SoX/FFmpeg 命令,它应该适用于任何类型的输入编码。我在预定义的字典中添加了一些不同的编码。此解决方案的缺点是您必须知道 RTP 文件中记录的呼叫的编码。我试图在 RTP 文件中找到与 PCAP 文件中的rtp.p_type 等效的参数,这需要使用的编解码器但没有任何运气。我对 RTP 文件不够熟悉,所以它可能存在于数据中的某个地方。这样做的另一个缺点是生成的音频文件有时可能比原始音频短。我假设这是由于 Silence Suppression 造成的,在这种情况下,可以通过在时间戳指示静音已被删除(未传输)的地方自己插入静音来修复它。
查看有关 RTP 文件信息的好方法是通过 tshark-command:
tshark -n -r /path/to/file.rtp
希望对某人有所帮助!
编辑:
我发现了另一个关于 detecting the encoding within a RTP file 的问题。