Difference between revisions of "Telephone system:autopatch"
| m (added category) | |||
| (7 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
| {{Project | {{Project | ||
| + | |Featured=No | ||
| |State=Completed | |State=Completed | ||
| |Members=xopr | |Members=xopr | ||
| |Description=use a VoIP system to communicate over radio | |Description=use a VoIP system to communicate over radio | ||
| + | |Picture=autopatch.jpg | ||
| }} | }} | ||
| − | + | <onlyinclude>To connect the <abbr title="private automated branch exchange">PABX</abbr> to an external communications channel, one needs a tiny bit of hardware and some scripting to get it working. | |
| + | A proof of concept is made that used the <abbr title="private mobile radio">PMRs</abbr> in the space and a couple of components on a perf-board. | ||
| + | </onlyinclude> | ||
| == synopsis == | == synopsis == | ||
| − | Inspired by [ | + | Inspired by [https://freeswitch.org/confluence/display/FREESWITCH/Ham+Radio freeswitch.org's Examples Ham Radio], I wanted to be able to communicate over the air using FreeSWITCH. | 
| It's a simple script with the least amount of hardware you can think of. | It's a simple script with the least amount of hardware you can think of. | ||
| Line 13: | Line 17: | ||
| == implementation == | == implementation == | ||
| === hardware === | === hardware === | ||
| − | + | :Using Stabo freecomm 450 portable transceivers | |
| + | :[[File:autopatch_schematic.png|335px|FreeSWITCH autopatch schematic]] | ||
| === perl script === | === perl script === | ||
| − | + |  #!/usr/bin/perl | |
| + | |||
| + |  use strict; | ||
| + |  use Switch; | ||
| + |  use Data::Dumper; | ||
| + |  use POSIX qw(strftime); | ||
| + |  use Device::SerialPins; | ||
| + | |||
| + |  my $conference_name = 'radio'; | ||
| + |  my $roger_beep      = 'tone_stream://%(60,0,2000);%(60,0,1200);%(60,0,800);% (80,0,1500)'; | ||
| + |  my $serial_port     = '/dev/ttyUSB0'; | ||
| + | |||
| + |  our $session; | ||
| + | |||
| + |  my $ptt_port        = new Device::SerialPins( $serial_port ); | ||
| + |  my $api             = new freeswitch::API; | ||
| + |  my $con             = new freeswitch::EventConsumer( 'CUSTOM' ); #all | ||
| + |  my $nTalkers        = 0; | ||
| + | |||
| + |  resetTransmission(); | ||
| + | |||
| + |  freeswitch::consoleLog( 'INFO', "Registered on CUSTOM events\n" ); | ||
| + | |||
| + |  while( $session->ready ) | ||
| + |  { | ||
| + |    # Check every half a second to prevent a small cpu from clipping | ||
| + |    #sleep( 0.5 ); # eats cpu | ||
| + |    $session->sleep( 500 ); | ||
| + | |||
| + |    my $event = $con->pop; | ||
| + | |||
| + |    if ( $event | ||
| + |     && ($event->getHeader('Event-Name') eq 'CUSTOM' ) | ||
| + |     && ( $event->getHeader('Event-Subclass') eq 'conference::maintenance' )) | ||
| + |    { | ||
| + |      my $action = $event->getHeader('Action'); | ||
| + | |||
| + |      if ( $event->getHeader('Caller-Channel-Name') =~ m/^portaudio/ ) | ||
| + |      { | ||
| + |        # portaudio event, check DTMF | ||
| + |        if( $action eq 'dtmf' ) | ||
| + |        { | ||
| + |          my $dtmf_key = $event->getHeader('dtmf-key'); | ||
| + |          freeswitch::consoleLog('INFO', 'DTMF: ' . $dtmf_key ); | ||
| + |          switch( $dtmf_key ) | ||
| + |          { | ||
| + |          } | ||
| + |        } | ||
| + |      } | ||
| + |      else | ||
| + |      { | ||
| + |        # event from other member | ||
| + |        switch ( $action ) | ||
| + |        { | ||
| + |          case 'start-talking' | ||
| + |          { | ||
| + |            PTT( 1 ); | ||
| + |          } | ||
| + |          case 'stop-talking' | ||
| + |          { | ||
| + |            PTT( 0 ); | ||
| + |          } | ||
| + |          case m/^(del|mute|deaf)-member$/ | ||
| + |          { | ||
| + |            # recount the number of talkers since the person throwing the horn | ||
| + |            # onhook might trigger a talk event before leaving | ||
| + |            handleTalkerCount(); | ||
| + |          } | ||
| + |        } | ||
| + |      } | ||
| + |    } | ||
| + | |||
| + |    # if we have 2 members left (portaudio and this script), hup all members and stop the conference | ||
| + |  } | ||
| + | |||
| + |  sub PTT | ||
| + |  { | ||
| + |    if ( shift ) | ||
| + |    { | ||
| + |      # New talker | ||
| + |      $nTalkers++; | ||
| + |      if ( $nTalkers == 1 ) | ||
| + |      { | ||
| + |        freeswitch::consoleLog('INFO', "Start of transmission\n" ); | ||
| + |        $ptt_port->set_rts( 1 ); | ||
| + |      }  | ||
| + |    } else { | ||
| + |      # Talker done | ||
| + |      $nTalkers--; | ||
| + | |||
| + |      if ( $nTalkers == 0 ) | ||
| + |      { | ||
| + |        resetTransmission(); | ||
| + |      } | ||
| + |    } | ||
| + | |||
| + |    # resetTransmission could change the number of talkers | ||
| + |    if ( $nTalkers < 0 ) | ||
| + |    { | ||
| + |      freeswitch::consoleLog('WARNING', "Number of talkers was below zero, resetting..\n" ); | ||
| + |      $nTalkers = 0; | ||
| + |    } | ||
| + |  } | ||
| + | |||
| + |  sub resetTransmission | ||
| + |  { | ||
| + |    # reset the number of talkers | ||
| + |    $nTalkers = 0; | ||
| + | |||
| + |    # roger beep | ||
| + |    $api->execute( 'conference', $conference_name.' play '.$roger_beep ); | ||
| + |    $session->sleep( 500 ); | ||
| + |    #sleep( 0.7 ); # eats cpu | ||
| + | |||
| + |    # end of transmit | ||
| + |    $ptt_port->set_rts( 0 ); | ||
| + | |||
| + |    freeswitch::consoleLog('INFO', "End of transmission\n" ); | ||
| + |  } | ||
| + | |||
| + |  sub handleTalkerCount | ||
| + |  { | ||
| + |    freeswitch::consoleLog('INFO', "Member event, counting number of talkers..\n" ); | ||
| + | |||
| + |    my $conference_info = $api->execute( 'conference', $conference_name.' list' ); | ||
| + |    my $nRealTalkers =()= $conference_info =~ /[;\|]talking[;\|]/gi; | ||
| + |    my $nMembers = ($conference_info =~ tr/\n//); | ||
| + | |||
| + |    # adjust number of talkers | ||
| + |    if ( $nRealTalkers < $nTalkers ) | ||
| + |    { | ||
| + |      $nTalkers = $nRealTalkers + 1; | ||
| + |      PTT( 0 ); | ||
| + |    } | ||
| + | |||
| + |    if ( $nMembers <= 2 ) | ||
| + |    { | ||
| + |      freeswitch::consoleLog('INFO', "No humans in the conference anymore, terminating script..\n" ); | ||
| + |      $session->hangup(); | ||
| + |    } | ||
| + |  } | ||
| + | |||
| + |  1; # Return value | ||
| + | |||
| === dial plan === | === dial plan === | ||
| − | + | The dialplan consists of two extensions: a conference where phones can dial into (1310), and an extension which runs the perl script. | |
| + | The conference requires a minimum of two participants. When the first person calls, the conference will automatically call the script extension and portaudio device which will be bridged directly (auto answer). | ||
| + | |||
| + |  <extension name="test porto"> | ||
| + |    <condition field="destination_number" expression="^1310$"> | ||
| + |      <action application="answer"/> | ||
| + |      <action application="conference_set_auto_outcall" data="portaudio/auto_answer"/> | ||
| + |      <action application="conference_set_auto_outcall" data="loopback/1311"/> | ||
| + |      <action application="conference" data="radio@ultrawideband+flags{mintwo}"/> | ||
| + |    </condition> | ||
| + |  </extension> | ||
| + | |||
| + |  <extension name="test porto event"> | ||
| + |    <condition field="destination_number" expression="^1311$"> | ||
| + |      <action application="answer"/> | ||
| + |      <action application="perl" data="autopatch.pl"/> | ||
| + |    </condition> | ||
| + |  </extension> | ||
| + | |||
| + | [[Category:Telephony]][[Category:Telephone snippet]][[Category:FreeSWITCH]] | ||
Latest revision as of 09:20, 14 February 2018
| Project: Telephone system:autopatch | |
|---|---|
| Featured: | No | 
| State | Completed | 
| Members | xopr | 
| GitHub | No GitHub project defined. Add your project here. | 
| Description | use a VoIP system to communicate over radio | 
| Picture | |
|   | |
To connect the PABX to an external communications channel, one needs a tiny bit of hardware and some scripting to get it working. A proof of concept is made that used the PMRs in the space and a couple of components on a perf-board.
synopsis
Inspired by freeswitch.org's Examples Ham Radio, I wanted to be able to communicate over the air using FreeSWITCH.
It's a simple script with the least amount of hardware you can think of.
implementation
hardware
perl script
#!/usr/bin/perl
use strict;
use Switch;
use Data::Dumper;
use POSIX qw(strftime);
use Device::SerialPins;
my $conference_name = 'radio';
my $roger_beep      = 'tone_stream://%(60,0,2000);%(60,0,1200);%(60,0,800);% (80,0,1500)';
my $serial_port     = '/dev/ttyUSB0';
our $session;
my $ptt_port        = new Device::SerialPins( $serial_port );
my $api             = new freeswitch::API;
my $con             = new freeswitch::EventConsumer( 'CUSTOM' ); #all
my $nTalkers        = 0;
resetTransmission();
freeswitch::consoleLog( 'INFO', "Registered on CUSTOM events\n" );
while( $session->ready )
{
  # Check every half a second to prevent a small cpu from clipping
  #sleep( 0.5 ); # eats cpu
  $session->sleep( 500 );
  my $event = $con->pop;
  if ( $event
   && ($event->getHeader('Event-Name') eq 'CUSTOM' )
   && ( $event->getHeader('Event-Subclass') eq 'conference::maintenance' ))
  {
    my $action = $event->getHeader('Action');
    if ( $event->getHeader('Caller-Channel-Name') =~ m/^portaudio/ )
    {
      # portaudio event, check DTMF
      if( $action eq 'dtmf' )
      {
        my $dtmf_key = $event->getHeader('dtmf-key');
        freeswitch::consoleLog('INFO', 'DTMF: ' . $dtmf_key );
        switch( $dtmf_key )
        {
        }
      }
    }
    else
    {
      # event from other member
      switch ( $action )
      {
        case 'start-talking'
        {
          PTT( 1 );
        }
        case 'stop-talking'
        {
          PTT( 0 );
        }
        case m/^(del|mute|deaf)-member$/
        {
          # recount the number of talkers since the person throwing the horn
          # onhook might trigger a talk event before leaving
          handleTalkerCount();
        }
      }
    }
  }
  # if we have 2 members left (portaudio and this script), hup all members and stop the conference
}
sub PTT
{
  if ( shift )
  {
    # New talker
    $nTalkers++;
    if ( $nTalkers == 1 )
    {
      freeswitch::consoleLog('INFO', "Start of transmission\n" );
      $ptt_port->set_rts( 1 );
    } 
  } else {
    # Talker done
    $nTalkers--;
    if ( $nTalkers == 0 )
    {
      resetTransmission();
    }
  }
  # resetTransmission could change the number of talkers
  if ( $nTalkers < 0 )
  {
    freeswitch::consoleLog('WARNING', "Number of talkers was below zero, resetting..\n" );
    $nTalkers = 0;
  }
}
sub resetTransmission
{
  # reset the number of talkers
  $nTalkers = 0;
  # roger beep
  $api->execute( 'conference', $conference_name.' play '.$roger_beep );
  $session->sleep( 500 );
  #sleep( 0.7 ); # eats cpu
  # end of transmit
  $ptt_port->set_rts( 0 );
  freeswitch::consoleLog('INFO', "End of transmission\n" );
}
sub handleTalkerCount
{
  freeswitch::consoleLog('INFO', "Member event, counting number of talkers..\n" );
  my $conference_info = $api->execute( 'conference', $conference_name.' list' );
  my $nRealTalkers =()= $conference_info =~ /[;\|]talking[;\|]/gi;
  my $nMembers = ($conference_info =~ tr/\n//);
  # adjust number of talkers
  if ( $nRealTalkers < $nTalkers )
  {
    $nTalkers = $nRealTalkers + 1;
    PTT( 0 );
  }
  if ( $nMembers <= 2 )
  {
    freeswitch::consoleLog('INFO', "No humans in the conference anymore, terminating script..\n" );
    $session->hangup();
  }
}
1; # Return value
dial plan
The dialplan consists of two extensions: a conference where phones can dial into (1310), and an extension which runs the perl script. The conference requires a minimum of two participants. When the first person calls, the conference will automatically call the script extension and portaudio device which will be bridged directly (auto answer).
<extension name="test porto">
  <condition field="destination_number" expression="^1310$">
    <action application="answer"/>
    <action application="conference_set_auto_outcall" data="portaudio/auto_answer"/>
    <action application="conference_set_auto_outcall" data="loopback/1311"/>
    <action application="conference" data="radio@ultrawideband+flags{mintwo}"/>
  </condition>
</extension>
<extension name="test porto event">
  <condition field="destination_number" expression="^1311$">
    <action application="answer"/>
    <action application="perl" data="autopatch.pl"/>
  </condition>
</extension>

