如何使用带 mod_conference 的 freeswitch 进行一键通、对讲机 (PTT)
How do I do a Push to Talk, Walkie Talkie (PTT) using freeswitch with mod_conference
我试着用 push 跟它说话。
一个 android sip 客户端和服务器 sip (freeswitch)
我的 mod_conference 有:
文件conference.conf.xml
<group name="radio">
<control action="mute" digits="0"/>
<control action="deaf mute" digits="*"/>
<control action="energy up" digits="9"/>
<control action="energy equ" digits="8"/>
<control action="energy dn" digits="7"/>
<control action="vol talk up" digits="3"/>
<control action="vol talk zero" digits="2"/>
<control action="vol talk dn" digits="1"/>
<control action="vol listen up" digits="6"/>
<control action="vol listen zero" digits="5"/>
<control action="vol listen dn" digits="4"/>
<control action="hangup" digits="#"/>
</group>
profile
<profile name="radio">
<param name="caller-controls" value="radio"/>
</profile>
my dialplan
<include>
<extension name="radio_conference">
<condition field="destination_number" expression="^1337$"/>
<condition field="source" expression="mod_portaudio" break="never">
<action application="perl" data="$${script_dir}/radio.pl"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="start_dtmf"/>
</condition>
<condition>
<action application="conference" data="radio@radio"/>
</condition>
</extension>
</include>
我的脚本radio.pl
use Device::SerialPins;
use Getopt::Std;
use strict;
use FreeSWITCH::Client;
use POSIX ':signal_h'; # used for alarm to ensure we get heartbeats
use Switch;
use Data::Dumper; # used to print out myhash debug info
use File::stat;
my $password = "1234"; # event socket password
my $host = "192.168.100.228"; # event socket host
my $port = 8021; # event socket port
my $device = undef; # radio control device (/dev/ttyS0, COM1, etc)
my $baud = 9600; # radio control device baud rate
my $timeout = 30; # seconds to expect a heartbeat or reconnect
my $courtesy_tone = "tone_stream://%(150,150,500);%(150,0,400)"; # tone played before releasing PTT
my $confname = "radio"; # the name of the conference
my $extension = "1337"; # this is the extension that portaudio will call to join
my $callsign = undef; # disable callsign autoID - set to your callsign
my $callsign_interval = 600; # 10 minute intervals
# for TTS anouncements played after CWID - undef to disable
my $voice = "Allison";
my $swift = "/opt/swift/bin/swift";
my $filetime = 0;
# normal users do not need to edit anything below here
my %options;
my $fs;
my $lastheartbeat;
my $lastcallsign;
my $lasttx;
my $releasePTT=0;
my $ptt_port;
sub pressPTT()
{
$ptt_port->set_rts(1);
}
sub releasePTT()
{
$ptt_port->set_rts(0);
}
# this connects to the event socket
sub es_connect()
{
print "Connecting to $host:$port\n";
eval {
$fs = init FreeSWITCH::Client {-password => $password, -host => $host, -port => $port};
if(defined $fs) {
$fs->sendmsg({'command' => 'event plain heartbeat CUSTOM conference::maintenance'});
$lastheartbeat = time;
}
} or do {
print "Error connecting - waiting for retry\n";
sleep(10);
}
}
sigaction SIGALRM, new POSIX::SigAction sub {
if ($lastheartbeat < (time - $timeout)) {
print "Did not receive a heartbeat in the specified timeout\n";
if (defined $fs) {
$fs->disconnect();
undef $fs;
}
es_connect();
}
if(defined $callsign && $lastcallsign < (time - $callsign_interval) && $lasttx > $lastcallsign) {
pressPTT();
$fs->command("jsapi morse.js conference radio ".$callsign);
$lastcallsign = time;
$releasePTT++;
if (-f "announcement.txt") {
if(stat("announcement.txt")->mtime > $filetime && defined $voice $$ defined $swift) {
system("$swift -p audio/deadair=2000,audio/sampling- rate=8000,audio/channels=1,audio/encoding=pcm16,audio/output-format=raw -o /tmp/announcement.raw -f announcement.txt -n $voice");
$fs->command("conference ".$confname." play /tmp/announcement.raw");
}
}
}
# reset the alarm
alarm $timeout;
} or die "Error setting SIGALRM handler: $!\n";
sub usage()
{
print "Usage: [=12=] [-p pass] [-P port] [-H host] [-d device] [-b baud]\n";
print "example: [=12=] -p password -P 8021 -H localhost -d /dev/ttyS0 -b 38400\n";
exit;
}
sub checkArgs()
{
getopts("p:P:H:d:b:h",\%options);
usage() if defined $options{h};
$password = $options{p} if defined $options{p};
$host = $options{H} if defined $options{H};
$port = $options{P} if defined $options{P};
$device = $options{d} if defined $options{d};
$baud = $options{b} if defined $options{b};
if(! defined $device || ! defined $password ||
! defined $host || ! defined $port) {
usage();
exit;
}
}
checkArgs();
$ptt_port = Device::SerialPins->new($device);
releasePTT();
es_connect();
alarm $timeout;
$SIG{INT} = "byebye"; # traps keyboard interrupt (^C)
sub byebye {
if(defined $fs) {
$fs->command("pa hangup");
}
exit();
}
if(defined $fs) {
$fs->command("pa call ".$extension);
} else {
print "Unable to start portaudio channel\n";
}
$lastcallsign = time;
while (1) {
if(defined $fs) {
my $reply = $fs->readhash(undef);
if ($reply->{socketerror}) {
es_connect();
}
if($reply->{body}) {
my $myhash = $reply->{event};
if ($myhash->{'event-name'} eq "HEARTBEAT") {
$lastheartbeat = time;
} elsif ($myhash->{'event-subclass'} eq "conference::maintenance") {
if($myhash->{'conference-name'} eq $confname) {
if($myhash->{'caller-channel-name'} =~ m/^portaudio/) {
# this is from the radio
if($myhash->{'action'} eq 'dtmf') {
switch($myhash->{'dtmf-key'}) {
# I will be adding some "dial" instructions for autopatch
# and maybe some other settings here
}
}
} else {
# this is from everyone else
if ($myhash->{'action'} eq 'start-talking') {
print "The port is talking! keying mic\n";
$lasttx = time;
pressPTT();
} elsif ($myhash->{'action'} eq 'stop-talking') {
print "The port stopped talking! releasing mic\n";
if(defined $courtesy_tone) {
$fs->command("conference ".$confname." play ".$courtesy_tone);
$releasePTT++;
}
}
}
if($myhash->{'action'} eq 'dtmf') {
print "conf: $myhash->{'conference-name'}\tmember: $myhash->{'member-id'}\tDTMF: $myhash->{'dtmf-key'}\n";
} elsif ($myhash->{'action'} eq 'play-file') {
print "conf: $myhash->{'conference-name'}\taction: $myhash->{'action'}\tfile: $myhash->{'file'}\n";
} elsif ($myhash->{'action'} eq 'play-file-done') {
print "conf: $myhash->{'conference-name'}\taction: $myhash->{'action'}\tfile: $myhash->{'file'}\n";
if($releasePTT>0) {
$releasePTT--;
}
print "release PTT: $releasePTT\n";
if($releasePTT==0) {
releasePTT();
}
} else {
print "conf: $myhash->{'conference-name'}\tmemid: $myhash->{'member-id'}\taction: $myhash->{'action'}\tCLID: $myhash-> {'caller-caller-id-number'}\n";
}
} else {
print "conf: $myhash->{'conference-name'}\tmemid: $myhash->{'member-id'}\taction: $myhash->{'action'}\tCLID: $myhash-> {'caller-caller-id-number'}\n";
}
} else {
print Dumper $myhash;
}
}
} else {
es_connect();
}
}
现在我不知道在这一刻使用这个文件 radio.pl 我尝试使用 android sip 的 sip 客户端并且在会议中都成功了,但现在我想配置一个谈话和大家听着,在这一刻所有的谈话和所有的倾听,拜托我需要帮助
谢谢
我目前正在尝试完成相同的任务。我做的一件事是使用会议成员标志将所有成员静音。当按下 ptt 按钮时,它将向会议发送 dtmf "unmute" 事件。
唯一的问题是没有阻止当前在会议中的其他成员也与另一个成员同时按下 ptt 按钮,因此会议中有 2 个成员同时发言,这是你不想要的
我试着用 push 跟它说话。 一个 android sip 客户端和服务器 sip (freeswitch) 我的 mod_conference 有:
文件conference.conf.xml
<group name="radio">
<control action="mute" digits="0"/>
<control action="deaf mute" digits="*"/>
<control action="energy up" digits="9"/>
<control action="energy equ" digits="8"/>
<control action="energy dn" digits="7"/>
<control action="vol talk up" digits="3"/>
<control action="vol talk zero" digits="2"/>
<control action="vol talk dn" digits="1"/>
<control action="vol listen up" digits="6"/>
<control action="vol listen zero" digits="5"/>
<control action="vol listen dn" digits="4"/>
<control action="hangup" digits="#"/>
</group>
profile
<profile name="radio">
<param name="caller-controls" value="radio"/>
</profile>
my dialplan
<include>
<extension name="radio_conference">
<condition field="destination_number" expression="^1337$"/>
<condition field="source" expression="mod_portaudio" break="never">
<action application="perl" data="$${script_dir}/radio.pl"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="start_dtmf"/>
</condition>
<condition>
<action application="conference" data="radio@radio"/>
</condition>
</extension>
</include>
我的脚本radio.pl
use Device::SerialPins;
use Getopt::Std;
use strict;
use FreeSWITCH::Client;
use POSIX ':signal_h'; # used for alarm to ensure we get heartbeats
use Switch;
use Data::Dumper; # used to print out myhash debug info
use File::stat;
my $password = "1234"; # event socket password
my $host = "192.168.100.228"; # event socket host
my $port = 8021; # event socket port
my $device = undef; # radio control device (/dev/ttyS0, COM1, etc)
my $baud = 9600; # radio control device baud rate
my $timeout = 30; # seconds to expect a heartbeat or reconnect
my $courtesy_tone = "tone_stream://%(150,150,500);%(150,0,400)"; # tone played before releasing PTT
my $confname = "radio"; # the name of the conference
my $extension = "1337"; # this is the extension that portaudio will call to join
my $callsign = undef; # disable callsign autoID - set to your callsign
my $callsign_interval = 600; # 10 minute intervals
# for TTS anouncements played after CWID - undef to disable
my $voice = "Allison";
my $swift = "/opt/swift/bin/swift";
my $filetime = 0;
# normal users do not need to edit anything below here
my %options;
my $fs;
my $lastheartbeat;
my $lastcallsign;
my $lasttx;
my $releasePTT=0;
my $ptt_port;
sub pressPTT()
{
$ptt_port->set_rts(1);
}
sub releasePTT()
{
$ptt_port->set_rts(0);
}
# this connects to the event socket
sub es_connect()
{
print "Connecting to $host:$port\n";
eval {
$fs = init FreeSWITCH::Client {-password => $password, -host => $host, -port => $port};
if(defined $fs) {
$fs->sendmsg({'command' => 'event plain heartbeat CUSTOM conference::maintenance'});
$lastheartbeat = time;
}
} or do {
print "Error connecting - waiting for retry\n";
sleep(10);
}
}
sigaction SIGALRM, new POSIX::SigAction sub {
if ($lastheartbeat < (time - $timeout)) {
print "Did not receive a heartbeat in the specified timeout\n";
if (defined $fs) {
$fs->disconnect();
undef $fs;
}
es_connect();
}
if(defined $callsign && $lastcallsign < (time - $callsign_interval) && $lasttx > $lastcallsign) {
pressPTT();
$fs->command("jsapi morse.js conference radio ".$callsign);
$lastcallsign = time;
$releasePTT++;
if (-f "announcement.txt") {
if(stat("announcement.txt")->mtime > $filetime && defined $voice $$ defined $swift) {
system("$swift -p audio/deadair=2000,audio/sampling- rate=8000,audio/channels=1,audio/encoding=pcm16,audio/output-format=raw -o /tmp/announcement.raw -f announcement.txt -n $voice");
$fs->command("conference ".$confname." play /tmp/announcement.raw");
}
}
}
# reset the alarm
alarm $timeout;
} or die "Error setting SIGALRM handler: $!\n";
sub usage()
{
print "Usage: [=12=] [-p pass] [-P port] [-H host] [-d device] [-b baud]\n";
print "example: [=12=] -p password -P 8021 -H localhost -d /dev/ttyS0 -b 38400\n";
exit;
}
sub checkArgs()
{
getopts("p:P:H:d:b:h",\%options);
usage() if defined $options{h};
$password = $options{p} if defined $options{p};
$host = $options{H} if defined $options{H};
$port = $options{P} if defined $options{P};
$device = $options{d} if defined $options{d};
$baud = $options{b} if defined $options{b};
if(! defined $device || ! defined $password ||
! defined $host || ! defined $port) {
usage();
exit;
}
}
checkArgs();
$ptt_port = Device::SerialPins->new($device);
releasePTT();
es_connect();
alarm $timeout;
$SIG{INT} = "byebye"; # traps keyboard interrupt (^C)
sub byebye {
if(defined $fs) {
$fs->command("pa hangup");
}
exit();
}
if(defined $fs) {
$fs->command("pa call ".$extension);
} else {
print "Unable to start portaudio channel\n";
}
$lastcallsign = time;
while (1) {
if(defined $fs) {
my $reply = $fs->readhash(undef);
if ($reply->{socketerror}) {
es_connect();
}
if($reply->{body}) {
my $myhash = $reply->{event};
if ($myhash->{'event-name'} eq "HEARTBEAT") {
$lastheartbeat = time;
} elsif ($myhash->{'event-subclass'} eq "conference::maintenance") {
if($myhash->{'conference-name'} eq $confname) {
if($myhash->{'caller-channel-name'} =~ m/^portaudio/) {
# this is from the radio
if($myhash->{'action'} eq 'dtmf') {
switch($myhash->{'dtmf-key'}) {
# I will be adding some "dial" instructions for autopatch
# and maybe some other settings here
}
}
} else {
# this is from everyone else
if ($myhash->{'action'} eq 'start-talking') {
print "The port is talking! keying mic\n";
$lasttx = time;
pressPTT();
} elsif ($myhash->{'action'} eq 'stop-talking') {
print "The port stopped talking! releasing mic\n";
if(defined $courtesy_tone) {
$fs->command("conference ".$confname." play ".$courtesy_tone);
$releasePTT++;
}
}
}
if($myhash->{'action'} eq 'dtmf') {
print "conf: $myhash->{'conference-name'}\tmember: $myhash->{'member-id'}\tDTMF: $myhash->{'dtmf-key'}\n";
} elsif ($myhash->{'action'} eq 'play-file') {
print "conf: $myhash->{'conference-name'}\taction: $myhash->{'action'}\tfile: $myhash->{'file'}\n";
} elsif ($myhash->{'action'} eq 'play-file-done') {
print "conf: $myhash->{'conference-name'}\taction: $myhash->{'action'}\tfile: $myhash->{'file'}\n";
if($releasePTT>0) {
$releasePTT--;
}
print "release PTT: $releasePTT\n";
if($releasePTT==0) {
releasePTT();
}
} else {
print "conf: $myhash->{'conference-name'}\tmemid: $myhash->{'member-id'}\taction: $myhash->{'action'}\tCLID: $myhash-> {'caller-caller-id-number'}\n";
}
} else {
print "conf: $myhash->{'conference-name'}\tmemid: $myhash->{'member-id'}\taction: $myhash->{'action'}\tCLID: $myhash-> {'caller-caller-id-number'}\n";
}
} else {
print Dumper $myhash;
}
}
} else {
es_connect();
}
}
现在我不知道在这一刻使用这个文件 radio.pl 我尝试使用 android sip 的 sip 客户端并且在会议中都成功了,但现在我想配置一个谈话和大家听着,在这一刻所有的谈话和所有的倾听,拜托我需要帮助
谢谢
我目前正在尝试完成相同的任务。我做的一件事是使用会议成员标志将所有成员静音。当按下 ptt 按钮时,它将向会议发送 dtmf "unmute" 事件。
唯一的问题是没有阻止当前在会议中的其他成员也与另一个成员同时按下 ptt 按钮,因此会议中有 2 个成员同时发言,这是你不想要的