如何在 Perl 中使用 HTTP POST 接收 wav 音频文件并在 Asterisk AGI 中播放

How to receive a wav audio file using HTTP POST in Perl and play it in Asterisk AGI

我正在使用 IBM Watson TTS 进行文本转语音功能。 我可以使用 Postman 的 Send and Download 功能获取音频文件。但是,我应该如何在 Perl 中做到这一点。 我对 Perl 完全陌生。 我使用 Perl 的原因是我需要在 Asterisk AGI 中实现 TTS。

编辑: 我可以保存文件。但是,无法在 Asterisk 中播放。

我正在为 POST 请求和播放音频使用以下代码片段:

....
my $uaresponse = $ua->post(
    "$url",
    Content_Type => "application/json",
    Accept => "audio/wav",
    Authorization => "Basic OWFmMjhhYmItMWFmMi00ZjU0LWE1YTAtNTJhNGUxNjRjNGQ1OnlkYWgwN3BRdEJMVA==",
    Content => $json_text,
);

if(!$uaresponse->is_success){
    print "Failed request to IBM \n";
} else{
    print "Successful with IBM \n";

    ($fh, $tmpname) = tempfile("ggl_XXXXXXXX", DIR => $tmpdir, UNLINK => 1);

    $tmpname = $uaresponse->content;

# my approach is wrong somewhere here...??

    #print "$tmpname\n";


#           open(my $out, '>:wav', "$tmpname.wav") or die "unable to open $!";
#           print $out pack('a*', $ua_response2->content);

   # Playback and save file in cache #
    $res = playback($tmpname, $intkey);
    die if ($res < 0);
    last if ($res > 0);

}

 sub checkresponse {
my $input = <STDIN>;
my @values;

chomp $input;
if ($input =~ /^200 result=(-?\d+)\s?(.*)$/) {
    @values = ("", "");
} else {
    $input .= <STDIN> if ($input =~ /^520-Invalid/);
    warn "$name Unexpected result: $input\n";
    @values = (-1, -1);
}
return @values;
}

sub playback {
my ($file, $keys) = @_;
my @response;

print "STREAM FILE $file \"$keys\"\n";
@response = checkresponse();
if ($response[0] >= 32 && chr($response[0]) =~ /[\w*#]/) {
    console_log("Got digit chr($response[0])") if ($debug);
    print "SET EXTENSION ", chr($response[0]), "\n";
    checkresponse();
    print "SET PRIORITY 1\n";
    checkresponse();
} elsif ($response[0] == -1) {
    console_log("Failed to play $file.");
}
return $response[0];
}

我假设您正在使用 LWP::UserAgent for your $ua and File::Temp 作为 tempfile 函数。

tempfile returns a filehandle and a filename. $uaresponse is an HTTP::Response object, and its method content returns HTTP 响应的未解码原始主体。

您正在将该正文(可能是完整的 wave 文件)分配给保存临时文件文件名的变量。您永远不会将内容写入文件。您正在尝试在注释掉的代码中执行此操作,但由于您已经覆盖了文件名,因此它不会起作用。

你可以直接使用tempfile给你的$fh。由于 wave 是二进制数据,因此在 $fh 上设置 binmode 是有意义的。然后就可以直接写入了。

if(!$uaresponse->is_success){
    print "Failed request to IBM \n";
} else{
    print "Successful with IBM \n";

    my ($fh, $tmpname) = tempfile("ggl_XXXXXXXX.wav", DIR => $tmpdir, UNLINK => 1);
    binmode $fh;
    print $fh $uaresponse->content; # or with pack if you want
}

应该是这样。 Perl 中没有 :wav 编码,因此您尝试的那部分代码无论如何都不会起作用。

请注意,在您对 tempfile 的调用中,您设置了 UNLINK => 1 选项,这意味着临时文件将在您的程序结束后自动删除。看起来这不是你想要的。看起来您想保留该文件。在那种情况下,也许 File::Temp 不是正确的方法。

这里是按最喜欢的顺序排列的问题。

1) 文件必须具有 EXACT 格式:wav、pcm 8khz、16 位、单声道。任何其他格式都将被忽略。如果您有其他格式,您首先使用 sox 或其他工具更改格式。如果您不确定格式,您应该使用 sox 或其他工具来确保格式受支持。

2) 您发送给asterisk 的文件名末尾应该没有.wav 扩展名。用户Asterisk::AGI模块,无需从头重写agi交互。

3) 文件必须有 asterisk 用户的读取权限

4) 文件所在的目录必须有星号用户

对open/read的权限

@arheops 和@simbabque 提供的答案肯定有帮助。

阻碍我的程序正常运行的恶作剧错误是打印语句:

print "Successful with IBM \n";

我通过在 Asterisk CLI 上执行打印语句的艰难方式了解到,上面的一个给出了一个我忽略的错误(510 无效或未知命令)。一旦我注释掉打印响应,它就可以正常工作了。

但是,如果你想使用打印,正确的方法应该是:

print "VERBOSE \" Successful with IBM \" \n";