Llamadas voice over IP
- Esta función sólo está disponible en el framework Android.
- La versión del sistema operativo debe ser Android 2.3.X (Gingerbread) o superior.
- A la hora de desarrollar, es conveniente estar atento a los mensajes del logcat que vienen bajo el tag “xonevoip” y “sipmanager”, para solucionar errores.
Implementación
Para empezar, descargamos e instalamos el módulo de llamadas xonevoip desde xonesupport.
Como las llamadas telefónicas son algo que se puede recibir en cualquier momento, usamos un objeto global como pueden ser las variables user(“”). Para ello, usamos createobject(“xonevoip”) y se lo asignamos a algo como MAP_VOIP.
Si las funciones voip no están soportadas en este terminal, al crear el objeto saltará una excepción y mostrará un mensaje de aviso por pantalla.
Necesitamos también definir en el nodo <app> de la aplicación el atributo phone-coll=“coleccionllamadaentrante”, que se llamará automáticamente cuando se reciba una llamada desde ese perfil y que debe contener, como mínimo, los botones de colgar y descolgar la llamada. La idea bajo esta implementación, es que el desarrollador cree los botones para hacer llamadas, recibirlas o registrarse con el servidor, y que diseñe una pantalla de llamadas a su gusto.
Por ejemplo, se puede hacer que se registre al loguearse en la aplicación con los datos que se saquen de la base de datos y que haya una opción en algún menú para hacer las llamadas.
Para las pruebas, se puede montar un servidor Asterisk® o usar algún proveedor gratuito como IPTel.
A continuación se describen las funciones y más abajo se muestra un ejemplo de uso completo.
Funciones de registro
CreateProfile
Nombre | createprofile(usuario, servidor) |
---|---|
Parámetro | Descripción |
usuario | Nombre de usuario de la cuenta SIP. |
servidor | Dominio del servidor SIP. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").CreateProfile "usuario", "servidor.org"
SetPassword
Nombre | setpassword(password) |
---|---|
Parámetro | Descripción |
password | Define la contraseña de la cuenta SIP. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetPassword "pass"
SetProtocol
Nombre | setprotocol(protocolo) |
---|---|
Parámetro | Descripción |
protocolo | Protocolo para conectarse al servidor. Casi siempre es UDP. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetProtocol "UDP"
SetPort
Nombre | setport(puerto) |
---|---|
Parámetro | Descripción |
puerto | Puerto al que conectarse del servidor. Casi siempre es 5060. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetPort 5060
SetSendKeepAlive
Nombre | setsendkeepalive(keepalive) |
---|---|
Parámetro | Descripción |
keepalive | Define si se debe enviar un paquete de keepalive al servidor. Puede ser true o false. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetSendKeepAlive "true"
SetOutboundProxy
Nombre | setoutboundproxy(direccion) |
---|---|
Parámetro | Descripción |
direccion | IP o dominio del servidor proxy para las llamadas salientes, si fuera necesario. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetOutboundProxy "212.212.212.212"
SetDisplayName
Nombre que se ve al hacer una llamada. Lo proporciona el proveedor voip
Nombre | setdisplayname(nombre) |
---|---|
Parámetro | Descripción |
nombre | Nombre que se mostrará. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetProfileName "Test VoIP 01"
SetProfileName
Define el nombre del perfil que se puede ver en los ajustes de cuentas voipde Android.
Nombre | setprofilename(nombre) |
---|---|
Parámetro | Descripción |
nombre | Nombre interno del perfil. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetProfileName "Test VoIP 01"
AddProfile
Da por válidos el resto de ajustes y crea el perfil.
Nombre | addprofile() |
---|---|
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").AddProfile
RegisterProfile
Una vez creado el perfil, lo registra para poder recibir llamadas.
Nombre | registerprofile() |
---|---|
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").RegisterProfile
UnRegisterProfile
Esta llamada desactiva el perfil y no deja pasar ni recibir llamadas. Según la versión de Android, esta llamada puede ser ignorada. [TODO]
Nombre | unregisterprofile() |
---|---|
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").UnRegisterProfile
SetRingtone
Nombre | setringtone(fichero) |
---|---|
Parámetro | Descripción |
fichero | Nombre del fichero de sonido que se reproducirá al recibir una llamada desde este perfil. Puede ser .WAV, .MP3 o lo que sea capaz de reproducir el terminal. Se recomienda usar un .WAV no demasiado pesado. |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SetRingtone "ringtone.mp3"
Funciones de llamada saliente
MakeVoIPCall
Nombre | makevoipcall(direccionsip) |
---|---|
Parámetro | Descripción |
direccionsip | Dirección a la cual hacer la llamada |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").MakeVoIPCall "test@servidorsip.com"
Funciones de llamada entrante
AnswerVoIPCall
Responde a la llamada entrante.
Nombre | answervoipcall() |
---|---|
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").MakeVoIPCall "test@servidorsip.com"
Funciones de llamada
HangVoIPCall
Cuelga la llamada, se haya establecido o no.
Nombre | answervoipcall() |
---|---|
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").HangVoIPCall
SendDTMF
Envía tonos DTMF en la llamada activa. No suele funcionar, pues sólo existe un codec voip capaz de transportar esta clase de tonos en modo “in-band” (G711) y no es habitual en proveedores voip.
Nombre | senddtmf(numero) |
---|---|
Parámetro | Descripción |
numero | Cadena con el número a enviar. Valores posibles: 0123456789ABCD |
Valor devuelto | 0 si OK, -1 si error. |
Ejemplo de uso:
user("MAP_VOIP").SendDTMF "1234"
EJEMPLO
Este es un ejemplo en plan “Walkie-Talkie”. Para usarlo cojemos dos teléfonos, en uno cargamos el primer mappings y en el otro el segundo.
Perfil #1:
<?xml version="1.0" encoding="iso-8859-1"?> <xml> <app prefix="gen" version="0.0.0.164" entry-point="TEST" autologon="true" phone-coll="LlamadaEntrante"> <!-- <style url="default.css"> <style url="default_hor.css" conditions="phone:horizontal"/> <style url="default_tablet.css" conditions="tablet:vertical"/> <style url="default_hor.css" conditions="tablet:horizontal"/> --> </app> <collprops type="general"> <coll name="Empresas" title="la empresa" sql="SELECT t1.ID,t1.CODIGO FROM ##PREF##Empresa t1" shadow="false" objname="Empresa" updateobj="Empresa" progid="ASGestion.CASEmpresa" fontsize="9" nomenmask="8" editwidth="101" editheight="97" filter="" sort=""> <group name="General" id="1" /> <prop name="CODIGO" visible="3" group="1" type="N" fieldsize="4" autosearch="true" /> </coll> <coll name="Usuarios" title="el usuario" sql="SELECT t1.ID,t1.IDEMPRESA,t1.LOGIN,t1.PWD,t1.NOMBRE FROM ##PREF##Usuarios t1" shadow="false" objname="Usuarios" updateobj="Usuarios" progid="ASGestion.CASUser" dropdown="true" editwidth="101" editheight="97" fontsize="9" filter="" sort=""> <group name="General" id="1" /> <prop name="IDEMPRESA" group="1" visible="0" type="N" mapcol="Empresas" mapfld="ID" /> <prop name="LOGIN" visible="3" group="1" type="T" fieldsize="10" fixed-text="true" size="10" /> <prop name="PWD" group="1" type="T" fieldsize="10" fixed-text="true" size="10" visible="" /> <prop name="NOMBRE" visible="3" group="1" type="T" fieldsize="30" fixed-text="true" size="30" /> <prop name="USERTYPE" visible="1" group="1" type="T" fieldsize="30" fixed-text="true" size="50" /> <create> <action name="setval" field="IDEMPRESA" value="##ENTID##" /> </create> </coll> <coll name="Empresas" title="la empresa" sql="SELECT t1.ID,t1.CODIGO FROM ##PREF##Empresa t1" shadow="false" objname="Empresa" updateobj="Empresa" progid="ASGestion.CASEmpresa" fontsize="9" nomenmask="8" editwidth="101" editheight="97" filter="" sort=""> <group name="General" id="1" /> <prop name="CODIGO" visible="3" group="1" type="N" fieldsize="4" autosearch="true" /> </coll> <coll name="Usuarios" title="el usuario" sql="SELECT t1.ID,t1.IDEMPRESA,t1.LOGIN,t1.PWD,t1.NOMBRE FROM ##PREF##Usuarios t1" shadow="false" objname="Usuarios" updateobj="Usuarios" progid="ASGestion.CASUser" dropdown="true" editwidth="101" editheight="97" fontsize="9" filter="" sort=""> <group name="General" id="1" /> <prop name="IDEMPRESA" group="1" visible="0" type="N" mapcol="Empresas" mapfld="ID" /> <prop name="LOGIN" visible="3" group="1" type="T" fieldsize="10" fixed-text="true" size="10" /> <prop name="PWD" group="1" type="T" fieldsize="10" fixed-text="true" size="10" visible="" /> <prop name="NOMBRE" visible="3" group="1" type="T" fieldsize="30" fixed-text="true" size="30" /> <prop name="USERTYPE" visible="1" group="1" type="T" fieldsize="30" fixed-text="true" size="50" /> <create> <action name="setval" field="IDEMPRESA" value="##ENTID##" /> </create> </coll> <coll name="LlamadaEntrante" fontsize="8" title="TEST" objname="TEST" updateobj="TEST" progid="ASData.CASBasicDataObj" sql="SELECT t1.ID FROM ##PREF##TEST t1" filter="" sort="" notab="true"> <group name="General" id="1" /> <frame id="aaa" name="aaa" width="100%" height="100%" /> <prop frame="aaa" name="MAP_TITULO02" type="TL" group="1" title="Llamada entrante!" width="100%" height="15%" labelwidth="10" /> <prop frame="aaa" name="MAP_HANG02" type="B" group="1" title="Colgar" method="ExecuteNode(hang)" width="100%" height="20%" labelwidth="10" /> <prop frame="aaa" name="MAP_RECIBIR02" type="B" group="1" title="Recibir" method="ExecuteNode(recibir)" width="100%" height="20%" labelwidth="10" /> <prop frame="aaa" name="MAP_DTMF02" type="B" group="1" title="Enviar DTMF prueba" method="ExecuteNode(dtmf)" width="100%" height="20%" labelwidth="10" /> <prop frame="aaa" name="MAP_SALIR02" type="B" group="1" title="Salir" method="ExecuteNode(salir)" width="100%" height="20%" labelwidth="10" /> <salir> <action name="runscript" type="runscript"> <script language="VBScript"> appdata.FailWithMessage -11888, "##EXITAPP##" </script> </action> </salir> <recibir> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").AnswerVoIPCall </script> </action> </recibir> <dtmf> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").SendDTMF "123456789" </script> </action> </dtmf> <hang> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").HangVoIPCall appdata.FailWithMessage -11888, "##EXITAPP##" </script> </action> </hang> </coll> <coll name="TEST" fontsize="8" title="TEST" objname="TEST" updateobj="TEST" progid="ASData.CASBasicDataObj" sql="SELECT t1.ID FROM ##PREF##TEST t1" filter="" sort="" notab="true"> <group name="General" id="1" /> <frame id="aaa" name="aaa" width="100%" height="100%" /> <prop frame="aaa" name="MAP_REGISTRARPERFIL01" type="B" group="1" title="Registrar con perfil #1" method="ExecuteNode(registrarperfil01)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_LLAMARPERFIL02" type="B" group="1" title="Llamar a perfil #2" method="ExecuteNode(llamarperfil02)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_HANG" type="B" group="1" title="Colgar" method="ExecuteNode(hang)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_UNREGISTER" type="B" group="1" title="Unregister" method="ExecuteNode(unregister)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_SALIR" type="B" group="1" title="Salir" method="ExecuteNode(salir)" width="100%" height="14%" labelwidth="10" /> <salir> <action name="runscript" type="runscript"> <script language="VBScript"> appdata.FailWithMessage -11888, "##EXITAPP##" </script> </action> </salir> <registrarperfil01> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP") = CreateObject("XOneVoIP") user("MAP_VOIP").CreateProfile "usuario", "iptel.org" user("MAP_VOIP").SetRingtone "testring.mp3" user("MAP_VOIP").SetPassword "contraseña" user("MAP_VOIP").SetProtocol "UDP" user("MAP_VOIP").SetPort 5060 user("MAP_VOIP").SetProfileName "Test VoIP 01" user("MAP_VOIP").AddProfile user("MAP_VOIP").RegisterProfile </script> </action> </registrarperfil01> <recibir> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").AnswerVoIPCall </script> </action> </recibir> <dtmf> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").SendDTMF "123456789" </script> </action> </dtmf> <llamarperfil02> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").MakeVoIPCall "direccionperfil2@iptel.org" </script> </action> </llamarperfil02> <hang> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").HangVoIPCall </script> </action> </hang> <unregister> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").UnRegisterProfile </script> </action> </unregister> </coll> </collprops> </xml>
Perfil #2:
<?xml version="1.0" encoding="iso-8859-1"?> <xml> <app prefix="gen" version="0.0.0.164" entry-point="TEST" autologon="true" phone-coll="LlamadaEntrante"> <!-- <style url="default.css"> <style url="default_hor.css" conditions="phone:horizontal"/> <style url="default_tablet.css" conditions="tablet:vertical"/> <style url="default_hor.css" conditions="tablet:horizontal"/> --> </app> <collprops type="general"> <coll name="Empresas" title="la empresa" sql="SELECT t1.ID,t1.CODIGO FROM ##PREF##Empresa t1" shadow="false" objname="Empresa" updateobj="Empresa" progid="ASGestion.CASEmpresa" fontsize="9" nomenmask="8" editwidth="101" editheight="97" filter="" sort=""> <group name="General" id="1" /> <prop name="CODIGO" visible="3" group="1" type="N" fieldsize="4" autosearch="true" /> </coll> <coll name="Usuarios" title="el usuario" sql="SELECT t1.ID,t1.IDEMPRESA,t1.LOGIN,t1.PWD,t1.NOMBRE FROM ##PREF##Usuarios t1" shadow="false" objname="Usuarios" updateobj="Usuarios" progid="ASGestion.CASUser" dropdown="true" editwidth="101" editheight="97" fontsize="9" filter="" sort=""> <group name="General" id="1" /> <prop name="IDEMPRESA" group="1" visible="0" type="N" mapcol="Empresas" mapfld="ID" /> <prop name="LOGIN" visible="3" group="1" type="T" fieldsize="10" fixed-text="true" size="10" /> <prop name="PWD" group="1" type="T" fieldsize="10" fixed-text="true" size="10" visible="" /> <prop name="NOMBRE" visible="3" group="1" type="T" fieldsize="30" fixed-text="true" size="30" /> <prop name="USERTYPE" visible="1" group="1" type="T" fieldsize="30" fixed-text="true" size="50" /> <create> <action name="setval" field="IDEMPRESA" value="##ENTID##" /> </create> </coll> <coll name="Empresas" title="la empresa" sql="SELECT t1.ID,t1.CODIGO FROM ##PREF##Empresa t1" shadow="false" objname="Empresa" updateobj="Empresa" progid="ASGestion.CASEmpresa" fontsize="9" nomenmask="8" editwidth="101" editheight="97" filter="" sort=""> <group name="General" id="1" /> <prop name="CODIGO" visible="3" group="1" type="N" fieldsize="4" autosearch="true" /> </coll> <coll name="Usuarios" title="el usuario" sql="SELECT t1.ID,t1.IDEMPRESA,t1.LOGIN,t1.PWD,t1.NOMBRE FROM ##PREF##Usuarios t1" shadow="false" objname="Usuarios" updateobj="Usuarios" progid="ASGestion.CASUser" dropdown="true" editwidth="101" editheight="97" fontsize="9" filter="" sort=""> <group name="General" id="1" /> <prop name="IDEMPRESA" group="1" visible="0" type="N" mapcol="Empresas" mapfld="ID" /> <prop name="LOGIN" visible="3" group="1" type="T" fieldsize="10" fixed-text="true" size="10" /> <prop name="PWD" group="1" type="T" fieldsize="10" fixed-text="true" size="10" visible="" /> <prop name="NOMBRE" visible="3" group="1" type="T" fieldsize="30" fixed-text="true" size="30" /> <prop name="USERTYPE" visible="1" group="1" type="T" fieldsize="30" fixed-text="true" size="50" /> <create> <action name="setval" field="IDEMPRESA" value="##ENTID##" /> </create> </coll> <coll name="LlamadaEntrante" fontsize="8" title="TEST" objname="TEST" updateobj="TEST" progid="ASData.CASBasicDataObj" sql="SELECT t1.ID FROM ##PREF##TEST t1" filter="" sort="" notab="true"> <group name="General" id="1" /> <frame id="aaa" name="aaa" width="100%" height="100%" /> <prop frame="aaa" name="MAP_TITULO02" type="TL" group="1" title="Llamada entrante!" width="100%" height="15%" labelwidth="10" /> <prop frame="aaa" name="MAP_HANG02" type="B" group="1" title="Colgar" method="ExecuteNode(hang)" width="100%" height="20%" labelwidth="10" /> <prop frame="aaa" name="MAP_RECIBIR02" type="B" group="1" title="Recibir" method="ExecuteNode(recibir)" width="100%" height="20%" labelwidth="10" /> <prop frame="aaa" name="MAP_DTMF02" type="B" group="1" title="Enviar DTMF prueba" method="ExecuteNode(dtmf)" width="100%" height="20%" labelwidth="10" /> <prop frame="aaa" name="MAP_SALIR02" type="B" group="1" title="Salir" method="ExecuteNode(salir)" width="100%" height="20%" labelwidth="10" /> <salir> <action name="runscript" type="runscript"> <script language="VBScript"> appdata.FailWithMessage -11888, "##EXITAPP##" </script> </action> </salir> <recibir> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").AnswerVoIPCall </script> </action> </recibir> <dtmf> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").SendDTMF "123456789" </script> </action> </dtmf> <hang> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").HangVoIPCall appdata.FailWithMessage -11888, "##EXITAPP##" </script> </action> </hang> </coll> <coll name="TEST" fontsize="8" title="TEST" objname="TEST" updateobj="TEST" progid="ASData.CASBasicDataObj" sql="SELECT t1.ID FROM ##PREF##TEST t1" filter="" sort="" notab="true"> <group name="General" id="1" /> <frame id="aaa" name="aaa" width="100%" height="100%" /> <prop frame="aaa" name="MAP_REGISTRARPERFIL02" type="B" group="1" title="Registrar con perfil #2" method="ExecuteNode(registrarperfil02)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_LLAMARPERFIL01" type="B" group="1" title="Llamar a perfil #1" method="ExecuteNode(llamarperfil01)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_HANG" type="B" group="1" title="Colgar" method="ExecuteNode(hang)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_UNREGISTER" type="B" group="1" title="Unregister" method="ExecuteNode(unregister)" width="100%" height="14%" labelwidth="10" /> <prop frame="aaa" name="MAP_SALIR" type="B" group="1" title="Salir" method="ExecuteNode(salir)" width="100%" height="14%" labelwidth="10" /> <salir> <action name="runscript" type="runscript"> <script language="VBScript"> appdata.FailWithMessage -11888, "##EXITAPP##" </script> </action> </salir> <registrarperfil02> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP") = CreateObject("XOneVoIP") user("MAP_VOIP").CreateProfile "contraseña", "iptel.org" user("MAP_VOIP").SetRingtone "testring.mp3" user("MAP_VOIP").SetPassword "contraseña" user("MAP_VOIP").SetProtocol "UDP" user("MAP_VOIP").SetPort 5060 user("MAP_VOIP").SetProfileName "Test VoIP 02" user("MAP_VOIP").AddProfile user("MAP_VOIP").RegisterProfile </script> </action> </registrarperfil02> <recibir> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").AnswerVoIPCall </script> </action> </recibir> <dtmf> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").SendDTMF "123456789" </script> </action> </dtmf> <llamarperfil01> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").MakeVoIPCall "direccionperfil1@iptel.org" </script> </action> </llamarperfil01> <hang> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").HangVoIPCall </script> </action> </hang> <unregister> <action name="runscript" type="runscript"> <script language="VBScript"> user("MAP_VOIP").UnRegisterProfile </script> </action> </unregister> </coll> </collprops> </xml>