Search code examples
perlperl-modulefreeswitch

How do I do a Push to Talk, Walkie Talkie (PTT) using freeswitch with mod_conference


I try a push to talk with it. a android sip client and server sip (freeswitch) my mod_conference has it:

file 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>

my script 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: $0 [-p pass] [-P port] [-H host] [-d device] [-b    baud]\n";
     print "example: $0 -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();
       }
      }

now I don't Know use this file radio.pl in this a moment I try a sip client with android sip and all successfully in a conference but now I want configure that one talk and everyone listen, in this moment all talk and all listen, please I need help

Thank's


Solution

  • I am currently trying to accomplish the same task. One thing I did do was use a conference member flag to enter all members into the conference as muted. When the ptt button is pressed it will send a dtmf "unmute" event to the conference.

    The only problem with this is there is no stopping of other members who are currently in the conference to also press the ptt button at the same time as another member thus having 2 members on the conference talking at the same time, which is what you dont want