if you’ve been following the opensim-commits mailing lists recently, you will have noticed that among the flurry of bug fixes and new features were a couple of commits mentioning the magic terms voice support. based on the the voice technology entry on wiki.secondlife.com, and also jhurliman’s libsl VoiceManager and VoiceTest code we have been working on adding voice capabilities required to interact with Linden Lab’s SecondLife® client to OpenSim.
i’ll try and explain what we’ve achieved so far in the following sections. if you are impatient and want to skip the pretty pictures and high-level explanations you can use the following mini-table of contents:
- asterisk-opensim integration
- automatic SIP account creation
- automatic conference call setup
- setting it all up
- setting it all up: AsteriskVoiceModule
- setting it all up: asterisk-opensim.py
- setting it all up: MySQL database
- setting it all up: asterisk
with the first iteration we refactored OpenSim’s capability system so that region module’s could contribute their capabilities to the seed capability and added a very simple, plain
the second iteration (subversion r4236) now has a new voice module,
AsteriskVoiceModule. also, in
share/python/asterisk you should find a python XmlRpc server called
asterisk-opensim.py. together with the open-source asterisk VoIP server both bring us quite a bit closer to our goal of voice support for OpenSim.
to understand how
asterisk-opensim.py and your SecondLife client play together, let’s take a look at the following figure:
automatic SIP account creation
when the SecondLife client logs in to the Linden Lab grid or to an OpenSim grid, among the first things it does (once it got its seed capabilties from the grid) is to ask the grid server for the voice acount details (#1,
ProvisionAccountRequest in the figure above). these voice account details basically are your avatar’s SIP account details which your SecondLife client is going to pass on to
SLVoice(.exe).1 in our case,
AsteriskVoiceModule deals with the incoming caps request from the SecondLife client: it
- retrieves the avatar’s UUID and base64-encodes it, and
- generates a one-time password (otp), and then
- it then issues an
account_updateXmlRpc call to our
asterisk-opensim.pyXmlRpc server running on the same box as our asterisk server (#2,
asterisk-opensim.py checks that the XmlRpc call is correct and then updates the MySQL database that we use to configure asterisk in realtime by adding a dialplan for the UUID of our avatar (which basically creates a SIP account for our avatar)(#3,
update extensions_table) — the MySQL database becomes effective (#4) the next time asterisk queries the database for its dialplan.
asterisk-opensim.py has done its job, it tells
AsteriskVoiceModule that it was successful (#5).
AsteriskVoiceModule then returns the newly created (or updated) voice account information to your SecondLife client (#6).
Your SecondLife client then passes that information on to
SLVoice which has nothing better to do than go and register with our asterisk server…
…well, it would, except,
SLVoice as packaged with the normal SecondLife client does not know about our asterisk server. we’ll need to supply a replacement
SLVoice client before we can claim success!2 you might want to check out the voipforvw project for one example of such a replacement.
ok, so, we now have a SIP account, and our potential
SLVoice replacement has registered with the asterisk server (well, once we’ve got it, that is ;-)) — how do we actually get voice and get to talk to other avatars? that’s what the next section is all about…
automatic conference call setup
lacking a proper spatial sound module for asterisk, we are just going to assign a conference call number to each and every region in our grid. sure, the idea being that whenever you avatar enters a new region, your SecondLife client will dial into the conference call for that region and leave the conference call of the old region.
how does your SecondLife client get the conference call number then? well, it turns out that the SecondLife client issues a
ParcelVoiceInfo request to the grid each time it enters a new region3. again, the figure below illustrates what happens.
AsteriskVoiceModule will receive the
ParcelVoiceInfo call (#1) and will in turn issue a
region_update XmlRpc call to
asterisk-opensim (#2) containing the region’s UUID4.
asterisk-opensim verifies the XmlRpc call from
AsteriskVoiceModule and will then add records to asterisk’s MySQL database (#3) to
- create (or update) a conference call with the region UUID as the dial-in “number”
- create appropriate dial plan entries for that conference call
asterisk will pick up the changes the next time it goes through its dial plan (#4)
and, once done,
success: true to
AsteriskVoiceModule (#5), which then returns the region voice details to your SecondLife client (#6):
region_name— the name of the region your avatar is currently in
parcel_id— i assume this contains the local ID of the piece of land your avatar is on
channel_uri— basically, the UUID of the region plus the value of the
conf_domainparameter from the
[AsteriskVoiceModule]section from OpenSim.ini
your SecondLife client passes the received information on to the
SLVoice application which will then dial into to the conference call (#7) for the new region (and leave the old conf call for the old region).5
setting it all up
to make this all work we need to
- setup asterisk’s MySQL database
- configure asterisk to query the MySQL database for its dial plan
the following sections explain each step in more detail.
setting it all up: AsteriskVoiceModule
to enable the
AsteriskVoiceModule you need to add the following lines to
[AsteriskVoice] enabled = true ; SIP account server domain sip_domain = testserver.com ; SIP conf server domain conf_domain = testserver.com ; URL of the asterisk opensim frontend asterisk_frontend = http://testserver.com:49153/ ; password for the asterisk frontend XmlRpc calls asterisk_password = bah-humbug ; timeout for XmlRpc calls to asterisk front end (in ms) asterisk_timeout = 3000 ; salt for asterisk nonces asterisk_salt = some_secret_here
what do the individual parameter mean:
- if true enable the module. make sure you have the plain vanilla
- the SIP domain to append to UUIDs for user accounts (can be empty)
- the SIP domain to append to UUIDs for region conference call IDs
- the URL of the
- the password required for the
AsteriskVoiceModulewill wait this long for XmlRpc calls to
asterisk-opensim.pyto succeed (in ms)
- salt to use for generating random one-time password for user SIP accounts
setting it all up: asterisk-opensim.py
asterisk-opensim.py is configured through it’s own config file. you supply the path to the config file via the
--config option (just invoke
--help to get usage instructions). the config file looks like this:
[xmlrpc] baseurl = http://127.0.0.1:53263/ debug = true [mysql] server = localhost database = asterisk user = asterisk password = asterisk debug = true [mysql-templates] tables = /path/to/create-table.sql user = /path/to/create-user.sql region = /path/to/create-region.sql debug = true
we have three sections:
- here you configure the base URL for the
region_updateXmlRpc calls (currently you cannot supply a path name, we only take hostname and port)
- here you configure which server to use, the name of the asterisk database, the user name and password of the MySQL user and whether you want debugging output or not.
- these are the path names to the templates that we use to create the required MySQL tables and also to update user account and update region conference calls. also, you can switch on debugging here.
setting it all up: MySQL database
setting up MySQL is pretty easy: you only need to create the asterisk database and the asterisk user:
# mysql -u root -p mysql> create database asterisk; Query OK, 1 row affected (0.02 sec) mysql> use asterisk; Database changed mysql> grant all on asterisk.* to 'asterisk'@'localhost' identified by 'asterisk'; Query OK, 0 rows affected (0.09 sec) mysql> quit; Bye
asterisk-opensim.py will take care of creating the necessary tables for you.
you might want to change the user name (the
'asterisk part of
'asterisk'@'localhost') and password (again, the
'asterisk' part in
identified by 'asterisk') — but make sure you adapt your
[asterisk-opensim.cfg](#setup-asterisk-opensim) and your asterisk configuration accordingly.
setting it all up: asterisk
we need to configure asterisk to use the ODBC database interconnect (also called asterisk realtime).
in your asterisk configuration directory — on ubuntu that’s
/etc/asterisk — you need to make sure that you have
sipusers => odbc,asterisk,ast_sipfriends sippeers => odbc,asterisk,ast_sipfriends extensions => odbc,asterisk,extensions_table
res_odbc.conf you need to have the following section:
[asterisk] enabled => yes dsn => asterisk-connector username => asterisk password => asterisk ;pooling => no ;limit => 5 pre-connect => yes
this assumes that your asterisk database is “asterisk”. likewise, that the MySQL username and password is ‘asterisk’ — if you used different values in your MySQL setup , you, of course, need to reflect that here.
then, you need to have the following
[general] static=yes writeprotect=no clearglobalvars=no [globals] CONSOLE=Console/dsp [avatare] switch => Realtime/@
finally, you need to have an empty
# mv sip.conf sip.conf.backup # touch sip.conf
that’s about it, really.
on windows it’s
SLVoice.exe, on linux it’s just
emphasizing this so as not to get lots of emails telling me that your voice setup does not work. no, kids, we are not there yet. but we can see the city lights approaching… ↩
it might actually do so, everytime you move into a new parcel (or land in OpenSim terminology), i haven’t checked that yet… “left as an exercise to the reader” ;-) ↩
actually the region UUID plus the
conf_domainparameter from the
[AsteriskVoiceModule]config section in
again, this requires a replacement
SLVoiceapplication, the standard one won’t do this. ↩