提示为:
用 perl 写 rtpengine 测试程序,尽量简单,支持 ping/offer/answer/delete
Gemini 2.5 Pro 产生的代码如下:
perl
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use Convert::Bencode qw(bencode bdecode);
use Data::Dumper;
# ================= 配置区域 =================
my $RTPENGINE_HOST = '127.0.0.1'; # rtpengine 地址
my $RTPENGINE_PORT = 2223; # rtpengine ng 监听端口
my $TIMEOUT = 2; # 超时时间 (秒)
# ===========================================
# 创建 UDP Socket
my $socket = IO::Socket::INET->new(
Proto => 'udp',
PeerAddr => $RTPENGINE_HOST,
PeerPort => $RTPENGINE_PORT
) or die "无法连接到 $RTPENGINE_HOST:$RTPENGINE_PORT : $!\n";
print "连接到 rtpengine ($RTPENGINE_HOST:$RTPENGINE_PORT)...\n\n";
# 生成一个用于测试的 Call-ID
my $test_call_id = "perl-bencode-test-" . int(rand(99999)) . "@" . $RTPENGINE_HOST;
my $from_tag = "tag-" . int(rand(99999));
my $to_tag = "tag-" . int(rand(99999));
# 模拟 SDP (用于 Offer)
my $sdp_offer = <<'END';
v=0
o=- 123456 123456 IN IP4 1.1.1.1
s=-
c=IN IP4 1.1.1.1
t=0 0
m=audio 10000 RTP/AVP 0
a=rtpmap:0 PCMU/8000
END
# 模拟 SDP (用于 Answer)
my $sdp_answer = <<'END';
v=0
o=- 654321 654321 IN IP4 2.2.2.2
s=-
c=IN IP4 2.2.2.2
t=0 0
m=audio 20000 RTP/AVP 0
a=rtpmap:0 PCMU/8000
END
# ================= 执行测试流程 =================
# 1. 测试 Ping
print "=== [1] 测试 PING ===\n";
send_request("ping", {});
# 2. 测试 Offer
print "\n=== [2] 测试 OFFER ===\n";
my $offer_params = {
'call-id' => $test_call_id,
'from-tag' => $from_tag,
'sdp' => $sdp_offer,
'replace' => ['origin', 'session-connection'], # 示例参数
};
send_request("offer", $offer_params);
# 3. 测试 Answer
print "\n=== [3] 测试 ANSWER ===\n";
my $answer_params = {
'call-id' => $test_call_id,
'from-tag' => $from_tag,
'to-tag' => $to_tag,
'sdp' => $sdp_answer,
'replace' => ['origin', 'session-connection'],
};
send_request("answer", $answer_params);
# 4. 测试 Delete
print "\n=== [4] 测试 DELETE ===\n";
my $delete_params = {
'call-id' => $test_call_id,
'from-tag' => $from_tag,
};
send_request("delete", $delete_params);
# 关闭 Socket
$socket->close();
print "\n测试结束。\n";
# ================= 核心函数 =================
sub send_request {
my ($command, $params_href) = @_;
# 1. 将命令本身也放入参数哈希中
$params_href->{command} = $command;
# 2. 生成 Cookie (用于匹配响应)
my $cookie = int(rand(1000000)) . "_cookie";
# 3. 编码数据为 bencode 格式
my $bencoded_data = bencode($params_href);
# 4. 构造 ng 协议数据包: "Cookie BencodedData"
my $packet = "$cookie $bencoded_data";
# 5. 发送
$socket->send($packet) or die "发送失败: $!\n";
# 6. 接收响应 (带超时处理)
my $response_data;
eval {
local $SIG{ALRM} = sub { die "timeout" };
alarm $TIMEOUT;
$socket->recv($response_data, 65535); # 最大 UDP 包大小
alarm 0;
};
if ($@) {
if ($@ =~ /timeout/) {
print "错误: 接收超时 (rtpengine 未运行或端口错误?)\n";
} else {
print "错误: $@\n";
}
return;
}
# 7. 解析响应
# 响应格式: "Cookie BencodedBody"
my ($resp_cookie, $resp_body) = split(/\s+/, $response_data, 2);
if ($resp_cookie ne $cookie) {
print "警告: Cookie 不匹配! 发送: $cookie, 接收: $resp_cookie\n";
}
print "Command: $command\n";
print "Status: ";
if ($resp_body) {
my $resp_decoded = eval { bdecode($resp_body) };
if ($@) {
print "Bencode 解析失败: $@\n";
} else {
if ($resp_decoded->{result} && ($resp_decoded->{result} eq 'ok' || $resp_decoded->{result} eq 'pong')) {
print "OK\n";
if ($resp_decoded->{sdp}) {
print " - Rtpengine 返回了新的 SDP\n";
}
} else {
print "ERROR\n";
# 使用 Data::Dumper 打印详细的错误信息
print Dumper($resp_decoded);
}
}
} else {
print "Empty response\n";
}
}
cpan Convert::Bencode
perl test.pl
输出如下:
连接到 rtpengine (127.0.0.1:2223)...
=== [1] 测试 PING ===
Command: ping
Status: OK
=== [2] 测试 OFFER ===
Command: offer
Status: OK
- Rtpengine 返回了新的 SDP
=== [3] 测试 ANSWER ===
Command: answer
Status: OK
- Rtpengine 返回了新的 SDP
=== [4] 测试 DELETE ===
Command: delete
Status: OK
测试结束。
现在的 AI 确实强