现在坐车机系统,android系统通过hal层控制tbox端,可以控制tbox扫描频道,调频等功能,tbox将收到的FM音频数据通过rtp传给android,android这边解析rtp数据并解码播放,我这边负责hal控制和检测音频是否可被解码;
因为对音频解码原理并不熟悉,只知道rtp里的数据是pcm原始数据,知道tbox的pcm的基本情况
一开始,死活解码出来的都是啪啪的噪音,后来突然能解码了
receive_tcpdum_rtp.pcap 是我通过wireshark抓的数据包
2022-06-09-test_receive_fm 通过wireshark解析后的pcm数据流,也就是去头的负载
receive.rtp 是我自己在hal层写的一个接收流,并去掉rtp头之后保存的
一个文件
先写一下自己解流的方式,很简单:
就是绑定本地端口, 然后阻塞的收udp流,收到后将头部14个字节截掉,然后写到一个文件里,也就是上面receive.rtp文件,是我记录的一个,最后会再写下wireshark如何解码并保存文件
void ReceiveAnalysisRtp() {
TBOX_LOGD("ReceiveAnalysisRtp");
static int iSocketFD = 0;
struct sockaddr_in stLocalAddr = {0};
/* 创建socket */
iSocketFD = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (iSocketFD < 0) {
TBOX_LOGD("创建socket失败!");
return;
}
/* 填写地址 */
stLocalAddr.sin_family = AF_INET;
stLocalAddr.sin_port = htons(50080);
stLocalAddr.sin_addr.s_addr = INADDR_ANY;
/* 绑定地址 */
if (0 >
bind(iSocketFD, (struct sockaddr*)&stLocalAddr, sizeof(stLocalAddr))) {
TBOX_LOGD("绑定地址失败!");
close(iSocketFD);
return;
}
std::thread([]() {
TBOX_LOGD("ReceiveAnalysisRtp, thread create");
int iRecvLen = 0;
char acBuf[4096] = {0};
struct sockaddr_in stRemoteAddr = {0};
socklen_t iRemoteAddrLen = 0;
FILE* fp = NULL;
fp = fopen("/data/receive.rtp", "w+");
while (1) {
iRecvLen = recvfrom(iSocketFD, acBuf, sizeof(acBuf), 0,
(struct sockaddr*)&stRemoteAddr, &iRemoteAddrLen);
// TBOX_LOGD("iRecvLen: %d", iRecvLen);
fwrite(acBuf + 14, iRecvLen - 14, 1, fp);
}
fclose(fp);
}).detach();
}
接下来写一下,如何查看是否解码成功,也就是听声音:
用工具(Audacity)来解码raw原始数据
文件-->导入-->原始数据,选择receive.rtp 去头后的原始pcm流
然后就可以播放音频了,说明音频解码是正常,收取rtp流截掉14个字节保存为文件也是对的
下面说一下wireshark收网络包并解析音频流
将收到的udp流,先找一个包,右键点击,解码为rtp
下面是进入解码流程
选择 电话-->RTP-->RTP流
然后下面第二个图片,选中其中的一个流,点击右下角的分析
在弹出的rtp流分析界面中,保存为“文件同步前向音频流”,这个就是一个音频的raw裸数据文件
然后可以通过上面的(Audacity)来解析听下声音
后续出现的问题:
Wireshark导出rtp音频数据并使用Audacity分析_rtp语音流-CSDN博客
wireshark的版本为3.6.3后,按照上面的就不太好导出rtp流的裸数据了
需要
- 选择“电话”---“RTP流分析”
- 选择“Play Streams”弹出RTP播放器窗口,选择“Export”---"Payload"导出RAW文件
只有在这种情况下可以导出为Payload,其他情况都不行