VoipRadioPanel

From RevSpace
Revision as of 19:23, 26 November 2012 by Maxell (Talk | contribs)

Jump to: navigation, search

%NOTOC%Goal

Have max. 6 participants dial on to an asterisk pbx, make each of their voices individually available as a mono output. Each participant should hear the other participants plus an external input from the mixing desk (studio mics / music), but not hear themselves back.

Documentation should be provider for common platforms (linux, macosx, ms windows). Pick one voip client on each platform, and document every step from installation, configuration to connecting to the conference pbx and joining.


Todo

Needs a lot of testing in the field:

  • get a bunch of typical users to give up a few hours of their time, explain they will need to be patient and do exactly as we say
  • set up a conference bridge with different types of connections: pots, voip, skype to sip gateway
  • documentation
  • create sample set to guide users in joining the conf

Setup

  • ESI u46xl sound card (6 out, 4 in, sponsored by Hxx)
  • Mixing desk with at least 6 line-ins, one aux or sub out
  • linphone instances to connect to the pbx
  • asterisk with custom extensions and scripts
  • siptosis skype gateway

ESI u46xl

Linux has crappy support for this device. To initialize the device properly, send the following to the usb mixer with 'amixer -c 1 -s':

cset numid=1 on,on
cset numid=2 on
cset numid=3 0,0,0,0
cset numid=4 on,on
cset numid=1 off,off
cset numid=5 off
cset numid=1 on,on
cset numid=7 on,on,on,on
cset numid=8 on
cset numid=6 0,0,0,0
cset numid=9 31,31,31,31,31,31

(yes, we turn 1 on, of and on again, needed to properly load 5, which disables monitor)

This .asoundrc makes the channels individually adressable and creates some fake input/output for linphone:

// Copyright (c) Koen Martens, gmc@sonologic.nl
// licensed under GPLv3

pcm.u46xl_play {
        type dmix
        ipc_key 2048
        slave {
                pcm "hw:1,0"
                rate 44100
                period_time 0
                period_size 1024
                buffer_size 8192
                channels 6
        }
        bindings {
                0 0
                1 1
                2 2
                3 3
                4 4
                5 5
        }
}

pcm.out1 {
        type plug
        slave {
                pcm "u46xl_play"
                channels 6
                rate 44100
        }
        ttable.0.0 1
}
pcm.out2 {
        type plug
        slave {
                pcm "u46xl_play"
                channels 6
        }
        ttable.0.1 1
}
pcm.out3 {
        type plug
        slave {
                pcm "u46xl_play"
                channels 6
        }
        ttable.0.2 1
}
pcm.out4 {
        type plug
        slave {
                pcm "u46xl_play"
                channels 6
        }
        ttable.0.3 1
}
pcm.out5 {
        type plug
        slave {
                pcm "u46xl_play"
                channels 6
        }
        ttable.0.4 1
}
pcm.out6 {
        type plug
        slave {
                pcm "u46xl_play"
                channels 6
        }
        ttable.0.5 1
}

pcm.u46xl_record {
        type dsnoop
        ipc_key 1647
        slave {
                pcm "hw:1,0"
                period_size 0
                buffer_size 65536
                rate 44100
                channels 4
        }
        bindings {
                0 0
                1 1
        }
}

pcm.in1 {
        type plug
        ttable.0.0 1.0
        slave.pcm pcm.u46xl_record
}

pcm.in2 {
        type plug
        ttable.0.1 1.0
        slave.pcm pcm.u46xl_record
}

pcm.in3 {
        type plug
        ttable.0.2 1.0
        slave.pcm pcm.u46xl_record
}

pcm.in4 {
        type plug
        ttable.0.3 1.0
        slave.pcm pcm.u46xl_record
}
pcm.dummy {
        type plug
        slave {
                pcm default
                channels 1
                rate 44100
        }
        ttable.0.0 0
}

pcm.mynull {
  type null
}

pcm.channel1 {
        type asym
        playback.pcm "out1"
        capture.pcm "dummy"
}

pcm.channel2 {
        type asym
        playback.pcm "out2"
        capture.pcm "dummy"
}

pcm.channel3 {
        type asym
        playback.pcm "out3"
        capture.pcm "dummy"
}

pcm.channel4 {
        type asym
        playback.pcm "out4"
        capture.pcm "dummy"
}
pcm.channel5 {
        type asym
        playback.pcm "out5"
        capture.pcm "dummy"
}

pcm.channel6 {
        type asym
        playback.pcm "out6"
        capture.pcm "dummy"
}

pcm.feedback {
        type asym
        playback.pcm "null"
        capture.pcm "in1"
}

linphone

Use linphonec -c configfile -s 'spyext@voip.host', eg:

linphonec -c linphone1.cfg -s '1@pbx.sonologic.net'

Here is linphone1.cfg:

[sound]
alsadev=channel1
playback_dev_id=ALSA: channel1
ringer_dev_id=ALSA: channel1
capture_dev_id=ALSA: channel1
remote_ring=/usr/share/sounds/linphone/ringback.wav

[GtkUi]
advanced_ui=1

[video]
device=V4L2: /dev/video0
size=cif
enabled=0
display=0
capture=0
show_local=0
self_view=0

[net]
download_bw=0
upload_bw=0
firewall_policy=2
mtu=0
stun_server=pbx.sonologic.net

[sip]
sip_port=5071
guess_hostname=1
inc_timeout=15
use_info=0
use_rfc2833=0
use_ipv6=0
register_only_when_network_is_up=1
default_proxy=-1
contact=<sip:spy@localhost:5071>

[rtp]
audio_rtp_port=7081
video_rtp_port=9078
audio_jitt_comp=60
video_jitt_comp=0
nortp_timeout=30

[audio_codec_0]
mime=speex
rate=32000
enabled=1

[audio_codec_1]
mime=speex
rate=16000
enabled=1

[audio_codec_2]
mime=speex
rate=8000
enabled=1

[audio_codec_3]
mime=GSM
rate=8000
enabled=1

[audio_codec_4]
mime=PCMU
rate=8000
enabled=1

[audio_codec_5]
mime=PCMA
rate=8000
enabled=1

[video_codec_0]
mime=MP4V-ES
rate=90000
enabled=1
recv_fmtp=profile-level-id=3

[video_codec_1]
mime=theora
rate=90000
enabled=1

[video_codec_2]
mime=H263-1998
rate=90000
enabled=1
recv_fmtp=CIF=1;QCIF=1

[video_codec_3]
mime=H263
rate=90000
enabled=1

[video_codec_4]
mime=x-snow
rate=90000
enabled=1

[auth_info_0]
username=spyuser
userid=spyuser
passwd=secret
realm="asterisk"

Be sure to use different alsa devices and different sip/rtp ports for additional spying clients.

For feedback (audio from the mixing desk sub out to the conference):

linphonec -c feedback.cfg -s 'feedback@pbx.sonologic.net'

Here is the config:

[sound]
alsadev=feedback
playback_dev_id=ALSA: feedback
ringer_dev_id=ALSA: feedback
capture_dev_id=ALSA: feedback
remote_ring=/usr/share/sounds/linphone/ringback.wav

[GtkUi]
advanced_ui=1

[video]
device=V4L2: /dev/video0
size=cif
enabled=0
display=0
capture=0
show_local=0
self_view=0

[net]
download_bw=0
upload_bw=0
firewall_policy=2
mtu=0
stun_server=p��

[sip]
sip_port=5080
guess_hostname=1
inc_timeout=15
use_info=0
use_rfc2833=0
use_ipv6=0
register_only_when_network_is_up=1
default_proxy=-1
contact=<sip:spy@localhost:5070>

[rtp]
audio_rtp_port=7090
video_rtp_port=9078
audio_jitt_comp=60
video_jitt_comp=0
nortp_timeout=30

[audio_codec_0]
mime=speex
rate=32000
enabled=1

[audio_codec_1]
mime=speex
rate=16000
enabled=1

[audio_codec_2]
mime=speex
rate=8000
enabled=1

[audio_codec_3]
mime=GSM
rate=8000
enabled=1

[audio_codec_4]
mime=PCMU
rate=8000
enabled=1

[audio_codec_5]
mime=PCMA
rate=8000
enabled=1

[video_codec_0]
mime=MP4V-ES
rate=90000
enabled=1
recv_fmtp=profile-level-id=3

[video_codec_1]
mime=theora
rate=90000
enabled=1

[video_codec_2]
mime=H263-1998
rate=90000
enabled=1
recv_fmtp=CIF=1;QCIF=1

[video_codec_3]
mime=H263
rate=90000
enabled=1

[video_codec_4]
mime=x-snow
rate=90000
enabled=1

[auth_info_0]
username=spy
passwd=secret
realm="asterisk"

extensions.ael

You need a sip.conf with a spy user and a feedback user, which both are in context spy.

You may want to create sip accounts for the panel members. Dump them in context panel.

You might want to make an extension 'panel' in your public sip context, which goes to panel|s|1.

// Copyright (c) 2011, Koen Martens <gmc@sonologic.nl>
// licensed under GPLv3

context panel {
        s => {
                Answer(500);
                BackGround(auth-incorrect);
                WaitExten;
        };
        t => {
                Hangup();
        };
        _XXXX => {
                if (${DB_EXISTS(PANEL_ACCOUNT/${EXTEN})}) {
                        Set(participantno=${DB(PANEL_ACCOUNT/${EXTEN})});
                        jump s@panel_join;
                } else {
                        Playback(auth-incorrect);
                        jump s;
                }
        };
        h => {
                NoOp(${DB_DELETE(PANEL_CHANNELS/${participantno})});
        };
};

context panel_join {
        s => {
                // expects participantno to be set
                if (${DB_EXISTS(PANEL_CHANNELS/${participantno})}) {
                        // Warn about participant already existing
                }
                Set(DB(PANEL_CHANNELS/${participantno})=${CHANNEL});
//              ConfBridge(0,1q);
                MeetMe(0,1q);
        }
}

context spy {
        _X => {
                Answer(500);
                while (1) {
                        if (${DB_EXISTS(PANEL_CHANNELS/${EXTEN})}) {
                                Set(channeltospy=${DB(PANEL_CHANNELS/${EXTEN})});
                                //ChanSpy(${channeltospy},oqXS);
                                ChanSpy(${channeltospy},oXSv(4));
                        }
                        Wait(5);
                }
        };
        _feedback => {
                Answer(500);
//              ConfBridge(0,1qs);
                MeetMe(0,1q);
        }
        echo => {
                Answer(500);
                Echo();
                Hangup();
        }
};

context moderator {
        // Moderator for conference
        1337 => {
                Answer(2000);
                // Warn about being joined as a moderator
//              ConfBridge(0,1qsa);
                MeetMe(0,1qsa);
        };
        // Dial out
        _0X. => {
                Set(outboundno=${EXTEN:1});
                jump s@outboundtie;
        }
};

context outboundtie {
        s => {
                Dial(SIP/moderator,60,T);
                NoOp();
        };
        _X => {
                Set(participantno=${EXTEN});
                jump s@panel_join;
        }
}

siptosis

Get the gateway software here.

Some useful documents:

I am not pretending I know exactly what is going on here, but something like this should do the trick (supposing there is a sip account panel2 on your pbx):

# siptosis.cfg
debug_level=3

#        SipToSis configuration file

# ___________________________________________

#



#how opften in minutes to check for configuration changes (0=disable)

configWatchInterval=0



#Set to log_debug.properties for full debugging

logConfigFile=log.properties



#Files containing Authorization rules

siptoskypeauthfile=SipToSkypeAuth.props

skypetosipauthfile=SkypeToSipAuth.props



#Files containing dialing transforms

SkypeOutDialingRulesFile=SkypeOutDialingRules.props

SipOutDialingRulesFile=SipOutDialingRules.props



#location of ua.jar file

ua_jar=ua.jar



#increase audio threads processing priority (0-2) 0=normal

audioPriorityIncrease=0



#jitter enable and size (0=disable,1=small,2=medium,3=large,4=extra large)

jitterLevel=2



#Set to skype_connect=no to disable connection to skype client - for testing purposes

skype_connect=yes



#Following ports are used by skype to transfer audio to/from siptosis 

#  - use any unused ports - uses 2 ports per connection

skype_audioportbase=64432





#Set to yes to enable skype DTMF support - uses more cpu

enableSkypeDtmfDetector=no

SkypeDtmfDetectorHitThreshold=90

SkypeDtmfDetectorSilenceThreshold=6



#Set to yes to regenerate SIP DTMF to Skype

sendSipDtmfToSkype=yes



#Set to yes to regenerate Skype DTMF to Sip

sendSkypeDtmfToSip=yes



#If using inband detectors, no to detect dtmf only during authentication (saves cpu)

inbandFullTimeDtmfDetection=no





#special mode if using skype client manually and an outbound skype call is made, it will attempt a sip call and link the two

JoinManualSkypeOutboundCallToSip=no



#refuse,voicemail,ignore,transferto:skypeid  

#  If you are using a PBX with multiple clients/ids you probably want to use ignore

#  or possibly transferto:nextskypeid to the next skypeclient in the chain

#  then refuse on the last one

SkypeInboundAllChannelsBusyAction=refuse



#If an incoming skype call and sip destination is not available for any reason, what to do with skype call. 

#Allowed options: ring or refuse - ring allows the skype client to continue ringing and be answered manually.

SkypeInboundSipDestUnavailableAction=refuse





#busy,transferto:sipurl  

#  If you want multiple outbound channels (AsteriskWin32 does not like this)

#  use transferto:sipurl to the next SipToSis channel in the chain then busy on the last one

SipInboundAllChannelsBusyAction=busy





#enable if skype client can support multiple active calls at same time - trying to lie here won't work

#I have yet to find a client that can do this

skypeclientsupportsmulticalls=no



#For an ATA/SIP Phone set to 2 - this allows two total calls - one will be on hold.

#For a PBX - depending on if the skype client supports multi calls - if not set it to 1

#  otherwise set based on your hardware/bandwidth limitations

concurrentcalllimit=2



#specify in 5 minute increments, 0=disable auto shutdown - siptosis will auto shutdown in x minutes when idle

autoShutdownMinutes=0



#Seconds caller has to enter the pin number

pintimeout=8

#Number of pin entry attempts before auto hangup

pinretrylimit=3



#Seconds caller has to enter the destination number

destinationtimeout=12

#Number of destination entry attempts before auto hangup

destinationretrylimit=3



#SIP authorization system recordings - make your own if you like (wav 16k 16bit mono).

pinFile=clips/enterPin.wav

destinationFile=clips/enterDest.wav

dialingFile=clips/dialing.wav

invalidPinFile=clips/invalidPin.wav

invalidDestFile=clips/invalidDest.wav



#Skype authorization system recordings - make your own if you like (wav 16k 16bit mono).

skypePinFile=clips/enterPin.wav

skypeDestinationFile=clips/enterDest.wav

skypeDialingFile=clips/dialing.wav

skypeInvalidPinFile=clips/invalidPin.wav

skypeInvalidDestFile=clips/invalidDest.wav



#Used for Skypeout only - transmit skype feedback sound during PSTN call attempt

handleEarlyMedia=yes



#Send Skype IM when calling skype users - not used for skypeout

sendSkypeIM=no

skypeimmessage=You are about to receive a Skype Voice call from [callerid].

#delay between the IM and the actual skype call in seconds.

sendSkypeImDelay=2



#transport_protocols=udp tcp

transport_protocols=udp

via_addr=10.1.3.20

host_ifaddr=ALL-INTERFACES

enableNatTranslate=yes 

#outbound_proxy=127.0.0.2:5060



#Sample AUTO config with NO registration

#  username and password not important in this mode

#Set to available port to transport SIP messages on siptosis computer

#host_port=5070

#username=skypests

#passwd=unimportantpassword

# --- end of NO registration example ---



#Sample config with NO registration - use if above auto config doesn't work - change 127.0.0.1 to ip address of computer running siptosis

#  username and password not important in this mode

#Set to available port to transport SIP messages on siptosis computer

#host_port=5070

#contact_url=sip:skypests@127.0.0.1:5070

#from_url="skypests" <sip:5611111111@127.0.0.1:5070>

#username=skypests

#passwd=unimportantpassword

#realm=127.0.0.1

# --- end of NO registration example ---



#Sample config WITH registration to GizmoProject - comment out NO registration info above first and uncomment the following

#contact_url=sip:studiorevspace@127.0.0.1:5070

#from_url="panel2" <sip:panel2@pbx.sonologic.net:5060>

#username=panel2

#passwd=secret
#realm=asterisk

#expires=120

#minregrenewtime=60

#regfailretrytime=15

#do_register=yes

#outbound_proxy=pbx.sonologic.net:5060

# --- end of WITH registration example ---





#sample FWD reg example - note the outbound proxy

#host_port=5070

#contact_url=sip:8?????@SipToSisIpAddress:SipToSisHostPort

#from_url="8?????" <sip:8?????@fwd.pulver.com:5060>

#username=8?????

#realm=fwd.pulver.com

#passwd=????

#expires=240

#do_register=yes

#minregrenewtime=120

#regfailretrytime=15

#outbound_proxy=fwdnat2.pulver.com:5060

# --- end of FWD registration example ---





#sample pennytel reg example

#host_port=5070

#contact_url=sip:8?????@SipToSisIpAddress:SipToSisHostPort

#from_url="8?????" <sip:8?????@sip.pennytel.com:5060>

#username=8?????

#realm=sip.pennytel.com

#passwd=123456

#expires=320

#do_register=yes

#minregrenewtime=120

#regfailretrytime=15

# --- end of pennytel registration example ---





#Sample Asterisk registration example - comment out NO registration info above first and uncomment the following.

#host_port=5070

#contact_url=sip:skypetestuser@SipToSisIpAddress:SipToSisHostPort

#from_url="skypetestuser" <sip:skypetestuser@asteriSkipAddress:asteriskHostPort>

#username=skypetestuser

#realm=asterisk

#passwd=skypetest

#expires=3600

#do_register=yes

#minregrenewtime=120

#regfailretrytime=15

# --- end of Asterisk Reg example ---



#Sample Asterisk registration example - comment out NO registration info above first and uncomment the following.

host_port=5070

contact_url=sip:studiorevspace@10.1.3.20:5070

from_url="panel2" <sip:panel2@pbx.sonologic.net:5060>

username=panel2

realm=asterisk

passwd=geheim
expires=3600

do_register=yes

minregrenewtime=120

regfailretrytime=15

# --- end of Asterisk Reg example ---



#Sample FreeSwitch regisration - can't use 5070 like others

#host_port=5077

#contact_url=sip:skypetestuser@SipToSisIpAddress:SipToSisHostPort

#from_url="skypetestuser" <sip:skypetestuser@freeswitchIPAddress:freeswitchHostPort>

#username=skypetestuser

#realm=freeswitchDeterminedRealm

#passwd=skypetest

#expires=3600

#do_register=yes

#minregrenewtime=160

#regfailretrytime=15

# --- end of FreeSwitch Reg example ---







#do_unregister=yes

#do_unregister_all=yes



#keepalive_time - set to zero to disable keep alives

keepalive_time=45000



audio=yes

#following is the SIP RTP port base - use an even port number

audio_port=63200

#auto hangup after no rtp packets received for ? seconds

noRtpReceivedAutoHangupSeconds=30



#only PCMU,PCMA,GSM (jmf lib),GSMTRI (tritonus libs) codecs currently supported - first one is the preferred codec

#You can append RW to the codec name to disable sample averaging - use need to use filter with those.

#Speex doesn't not work well at all - mass cpu usage

audio_codec=PCMU,PCMA,GSMTRI,ILBC,SPEEX

#PCMU/PCMA allow 160,240,320 - GSM allows 160 - ILBC allows 240, Speex allows 160, Speex16k allows 320  - need one size for each codec specified 

audio_frame_size=240,240,160,240,160

#if using dynamic payload types (speex and ilbc) you must specify the payload number (asterisk uses 98,97), if not you can remove this parameter

audio_avp=-1,-1,-1,98,97



#Audio volume gains - 1 for each codec - (decimal number) 1=flat no gain, higher=louder, too high will clip or distort

#volume sip->skype

skype_audiooutgain=1,1,1,1,1

#volume skype->sip

skype_audioingain=1.5,1.5,1.5,1.5,1.5



#Filter skype audio before being downsampled and sent to SIP device. 

#No Filtering

FilterParams=NONE

#RC lowpass filter

#RC,delay time (lower lowers cutoff),RC constant (higher lowers cutoff) - 50,40 is a good starting point 

#FilterParams=RC,50,40

#FIR filter

#FIR,Order (higher sharper cutoff and more cpu),window type (RECTANGULAR,HANNING,HAMMING,BLACKMAN),filter type (LP,HP,BP),minFreq,maxFreq

#FilterParams=FIR,100,HANNING,LP,0,3200

#FilterParams=FIR,100,HANNING,HP,300,3200

#FilterParams=FIR,100,HANNING,BP,300,3200



#If yes, will send RTP packets to address received from the otherside

#  instead of what was received in the session descriptor. 

#  This may help with one way audio problems. 

enableSendRTPtoReceivedAddress=yes

#works with above setting - sending of rtpPackets can be redirected until receiving this number of packets. After that the address is locked.

lockRtpSendAddressAfterPackets=1



#Set to -1 to disable rfc2833 some providers use 96 most use 101

dtmf2833payloadtype=101 



#Use these for SIP INFO msg support - first is the most common type

#dtmfinfotype=application/dtmf-relay

#dtmfinfotype=application/dtmf



#Use only if rfc2833 and INFO are not supported - uses more cpu

enableSIPInbandDtmfDetector=no

SipDtmfDetectorHitThreshold=30

SipDtmfDetectorSilenceThreshold=6





#params to control sip response address handling

useViaRport=yes

useViaReceived=yes

#send all responses using outbound proxy - outbound proxy must be set up

sendResponseUsingOutboundProxy=no



#sip response for any uncovered reason

baseFailureResponse=403

#sip response if remote skype user refused call

skypeRefusedResponse=603

#sip response if skype call failed, invalid skype user, or no skype credit

skypeFailedResponse=404

#sip response if skype returned unplaced status

skypeUnPlacedResponse=408

#sip response if called party is busy

skypeBusyResponse=600



#network buffers for skype api audio transport (0=leave at OS default)

TcpRxBufferSize=8192

TcpTxBufferSize=8192

#network buffers for RTP audio transport (0=leave at OS default)

RtpRxBufferSize=8192

RtpTxBufferSize=8192



#*** register server settings below *** not required if registration is not needed for phone

#set to yes to turn on server registrar or no to disable

is_registrar=yes

#set to yes to allow register of users not already in registar database (users.db)

register_new_users=yes

#set to domains of server - see mjsip doc

#domain_names=192.168.0.4 somedomain.com

allowMultiContactsPerUser=no

And you will need something like this in your SkypeToSipAuth.props:

*,sip:panel@pbx.sonologic.net:5060

Somehow it seems to dial the sip uri without registering, so panel must be in the public incoming SIP context.

Known issues

  • siptosis - spy output is very choppy, is this for all sip channels?? needs testing, spy works perfect when spying on iax channels
  • killing siptoskype without hanging up the incoming skype call will result in odd lingering channels in asterisk, messing with your head