Sistema de Atención al Cliente con WebRTC y Elastix-CallCenter.

26 Jul

Hola, en este artículo vamos a crear un sistema de atención a cliente usando las herramientas WebRTC-SIPML5 y Elastix junto con su addon de Call Center. La idea general es generar 0 costos entre el usuario y nuestro centro de atención. Es por esto que vamos a usar WebRTC y Elastix dos herramientas open source las cuales van a interactuar usando nuestra conexión de internet.

Paso 1.

Instalar el soporte de WebRTC para el módulo de Call Center de Elastix que publiqué anteriormente.

Paso 2.

Crear una cola de atención:

  • Crear al menos 2 dispositivos SIP. Menú PBX—>Extensions.
  • Crear una cola de atención. Menú PBX—>Queue.
  • Asignar a la nueva cola de atención uno de los dispositivos SIP como miembro dinámico y usando el prefijo S, por ejemplo, para el dispositivo 1500 quedará de la siguiente manera: S1500,0
  • Seleccionar el ‘ring strategy'(estrategia de timbrado) con ‘fewestcalls'(menos llamadas recibidas).
  • Añadir los Anuncios necesarios.
  • Aplicar los cambios.

Paso 3.

Configurar el Módulo de Call Center de Elastix, para recibir llamadas:

  • Ir al menú ‘Agent Options'(Opciones de agente).
  • Crear al menos una ‘callback extension'(Extension callback). Tiene que coincidir con el dispositivo que se añadió como miembro a la cola de atención.
  • Ir a ‘Ingoing calls'(llamadas entrantes)—> Queues(Colas).
  • Seleccionar la Cola de atención previamente creada.

Paso 4.

Crear nuestra página web que será desde donde nuestros usuarios van a contactarnos(el diseño de la página web queda al gusto y capacidades de cada quien).

Para usar la API de SIPML5 pueden checar el ejemplo online con el que ellos cuentan o su documentación. Les dejo el código con el que llevo trabajando en algunos proyectos y el cual estoy usando en este artículo:

 

<head>
       <title>Navaismo's ElastixCC-WebRTC</title>
    <!-- SIPMl5 API for WEBRTC calls -->
        <script src="js/SIPml-api.js"></script>
        <link href="css/bootstrap.min.css" media="screen" rel="stylesheet"></link>
</head>

<script>

 //Variables
 var mySipStack;
        var mycallSession;
 var myregisterSession;

 // readycallback for INIT
 var readyCallback = function(e){
  console.log("engine is ready");

  //CHeck if the SIPml start
  if(SIPml.isInitialized() == 1){
   console.log("Done to initialize the engine");
   //If the stack is started, create the sip stack
   startSipStack();
  }else{
   //If not started display console msg
   console.log("Failed to initialize the engine");
  }          
 }

 // error callback for INIT
 var errorCallback = function(e){
  console.error('Failed to initialize the engine: ' + e.message);
 }

 //INIT SIPML5 API
 SIPml.init(readyCallback, errorCallback);

 //Here we listen stack messages
 function listenerFunc(e){
  //Log incoming messages
  tsk_utils_log_info('==stack event = ' + e.type);

  switch(e.type){

   //If failed msg or error Log in console & Web Page
   case 'failed_to_start': case 'failed_to_stop':  case 'stopping': case 'stopped': {

    console.log("Failed to connect to SIP SERVER")
    mycallSession = null;
    mySipStack = null;
    myregisterSession = null;

    $("#mysipstatus").html('');
    $("#mysipstatus").html('<i>Disconnected: </i>'+e.description);

    break;
   }

   //If the msg is 'started' now try to Login to Sip server           
          case 'started': {
                  console.log("Trying to Login");

    login();//function to login in sip server

    //Display msg in the web page
    $("#mysipstatus").html('');
    $("#mysipstatus").html('<i>Trying to Connect</i>');

    break;
   }

   //If the msg 'connected' display the register OK in the web page 
   case 'connected':{
    $("#mysipstatus").html('');
    $("#mysipstatus").html('<i>Registered with Sip Server</i>');

    break;
   }

   //If the msg 'Sent request' display that in the web page---Pattience
   case 'sent_request':{

    $("#mysipstatus").html('');
    $("#mysipstatus").html('<i>'+e.description+'</i>');

    break;
   }

   //If the msg 'terminated' display that on the web---error maybe?
   case 'terminated': {
    $("#mysipstatus").html('');
    $("#mysipstatus").html('<i>'+e.description+'</i>');

    break;
   }

   //If the msg 'i_new_call' the browser has an incoming call
   case 'i_new_call': {
     if (mycallSession) {
                          // do not accept the incoming call if we're already 'in call'
                          e.newSession.hangup(); // comment this line for multi-line support
                  }else{

     mycallSession = e.newSession;

     //Change buttons values
                   btnCall.value = 'Answer';
                  btnHangUp.value = 'Reject';
                          btnCall.disabled = false;
                          btnHangUp.disabled = false;

     //Start ringing in the browser
                          startRingTone();

     //Display in the web page who is calling
                   var sRemoteNumber = (mycallSession.getRemoteFriendlyName() || 'unknown');
                   $("#mycallstatus").html("<i>Incoming call from [<b>" + sRemoteNumber + "</b>]</i>");
                   showNotifICall(sRemoteNumber);
    }
    break;
   }

   case 'm_permission_requested':{
                         break;
                 }
              case 'm_permission_accepted':
          case 'm_permission_refused': {
    if(e.type == 'm_permission_refused'){

            btnCall.value = 'Call';
            btnHangUp.value = 'HangUp';
            btnCall.disabled = false;
            btnHangUp.disabled = true;

            mycallSession = null;

            stopRingbackTone();
            stopRingTone();

             $("#mysipstatus").html("<i>" + s_description + "</i>");

                      }
                      break;
                 }
   case 'starting': default: break;
         }            
 }

 //Function to Listen the call session events
 function calllistener(e){
  //Log all events
  tsk_utils_log_info('****call event**** = ' + e.type);

  switch(e.type){

   //Display in the web page that the call is connecting
   case 'connected': case 'connecting': {

        var bConnected = (e.type == 'connected');
                      if (e.session == myregisterSession) {                          
                           $("#mycallstatus").html("<i>" + e.description + "</i>");

                      }else if (e.type == 'connecting') {                          
                           $("#mycallstatus").html("<i>" + e.description + "</i>");

    }else if (e.session == mycallSession) {
                          btnHangUp.value = 'HangUp';

                         if (bConnected) {
                           stopRingbackTone();
                           stopRingTone();
     }
                             }
    break;
                        }

   //Display in the browser teh call is finished
   case 'terminated': case 'terminating': {

    if (e.session == mycallSession) {
                          mycallSession = null;
                         myregisterSession = null;

                          $("#mycallstatus").html("<i>" + e.description + "</i>");
            stopRingbackTone();
            stopRingTone();

                 }else if (e.session == mycallSession) {

            btnCall.value = 'Call';
            btnHangUp.value = 'HangUp';
            btnCall.disabled = false;
            btnHangUp.disabled = true;

            mycallSession = null;

            stopRingbackTone();
            stopRingTone();
                        }
    break;

   }  

   // future use with video
           case 'm_stream_video_local_added': {
                      if (e.session == mycallSession) {

                          }
                      break;
                 }

   //future use with video
                case 'm_stream_video_local_removed': {
                      if (e.session == mycallSession) {

                          }
                      break;
                 }

   //future use with video
         case 'm_stream_video_remote_added':  {
                      if (e.session == mycallSession) {

                          }
                         break;
              }

   //future use with video
          case 'm_stream_video_remote_removed': {
                      if (e.session == mycallSession) {

                          }
                      break;
                 }

   //added media audio todo messaging
                 case 'm_stream_audio_local_added':
   case 'm_stream_audio_local_removed':
          case 'm_stream_audio_remote_added':
          case 'm_stream_audio_remote_removed': {

                  stopRingTone();                   
                         stopRingbackTone();

                      break;
                 }

   //If the remote end send us a request with SIPresponse 18X start to ringing
   case 'i_ao_request':{
                         var iSipResponseCode = e.getSipResponseCode();
                         if (iSipResponseCode == 180 || iSipResponseCode == 183) {
                   startRingbackTone(); //function to start the ring tone
     $("#mycallstatus").html('');
                              $("#mycallstatus").html('<i>Remote ringing...</i>');
     $("#btnHangUp").show();
                         }
    break;
   }

   // If the remote send early media stop the sounds
   case 'm_early_media': {
                  if (e.session == mycallSession){ 
           stopRingTone();                   
                          stopRingbackTone();
     $("#mycallstatus").html('');
     $("#mycallstatus").html('<i>Call Answered</i>');
    }
    break;
   }
                }

 }

 //function to send the SIP Register
 function login(){
  //Show in the console that the browser is trying to register
  console.log("Registering");

  //create the session
         myregisterSession = mySipStack.newSession('register', {
                 events_listener: { events: '*', listener: listenerFunc } // optional: '*' means all events
                });

  //send the register
        myregisterSession.register();
 }

 // function to create the sip stack
 function startSipStack(){
  //show in the console that th browser is trying to create the sip stack
  console.info("attempting to start the SIP STACK");

  //stack options
  mySipStack  = new SIPml.Stack({
          realm: 'asterisk',
          impi: 'usuario',
          impu: 'sip:usuario@myip',
          password: 'mipassword', // optional
          display_name: 'TS', // optional
          websocket_proxy_url: 'ws://miip:10060', // optional
          outbound_proxy_url: 'udp://miip:5060', // optional
          //ice_servers: [{ url: 'stun:stun.l.google.com:19302'}, { url:'turn:user@numb.viagenie.ca', credential:'myPassword'}], // optional
          enable_rtcweb_breaker: true, // optional
          enable_click2call: false, // optional
          events_listener: { events: '*', listener: listenerFunc }, //optional
          sip_headers: [ //optional
              {name: 'User-Agent', value: 'DM_SIPWEB-UA'}, 
              {name: 'Organization', value: 'Digital-Merge'}
          ]
      });
  //If the stack failed show errors in console
  if (mySipStack.start() != 0) {
                 console.info("Failed to start Sip Stack");
             }else{
                 console.info("Started the Sip Stack");
  }

 }

 //Fucntion to call/answer
 function call(){
  var calltype;

  if(mySipStack){
   //create the session to call
          mycallSession = mySipStack.newSession('call-audio', {
                  audio_remote: document.getElementById('audio_remote'),
                  audio_local: document.getElementById('audio_local'),
                  video_remote: document.getElementById('video_remote'),
                  video_local: document.getElementById('video_local'),
                      events_listener: { events: '*', listener: calllistener } // optional: '*' means all events
                 });
   $("#mycallstatus").show();
   //call using the number 80000
          mycallSession.call("80000");
  }else if(!mySipStack){
   alert('Stack not ready!');

  //If the textbox is empty and the button call is ANSWER, then is a incoming call
  }else if(flag =='Answer' && mySipStack && mycallSession){

                        stopRingbackTone();
                        stopRingTone();                   

   //Accept the session call
   mycallSession.accept({
                                audio_remote: document.getElementById('audio_remote'),
                                audio_local: document.getElementById('audio_local'),
                                events_listener: { events: '*', listener: calllistener } // optional: '*' means all events
                        });
  }
 }

 //function to hangup the call
 function hangup(){
  //If exist a call session, hangup and reset button values
  if(mycallSession){
          mycallSession.hangup({events_listener: { events: '*', listener: calllistener }});
                        stopRingbackTone();
                        stopRingTone();                   
                        btnCall.value = 'Call';
                        btnHangUp.value = 'HangUp';
   $("#callnumber").attr('value','');
   $("#mycallstatus").html("Call Terminated")
   $("#btnHangUp").hide();
   //destroy the call session
   mycallSession = null;

  }else{
   $("#callnumber").attr('value','');
  }   

 }

 //Fucntion to send DTMF frames
 function sipSendDTMF(c){
         if(mycallSession && c){
              if(mycallSession.dtmf(c) == 0){
                  try { dtmfTone.play(); } catch(e){ }
              }
         }else{
   var lastn = $("#callnumber").val();

   $("#callnumber").val( lastn + c );
          try { dtmfTone.play(); } catch(e){ }

  }

     }

/**************** fucntion to play sounds *******************/
    function startRingTone() {
        try { ringtone.play(); }
        catch (e) { }
    }

    function stopRingTone() {
        try { ringtone.pause(); }
        catch (e) { }
    }

    function startRingbackTone() {
        try { ringbacktone.play(); }
        catch (e) { }
    }

    function stopRingbackTone() {
        try { ringbacktone.pause(); }
        catch (e) { }
    }

   function showNotifICall(s_number) {
        // permission already asked when we registered
        if (window.webkitNotifications && window.webkitNotifications.checkPermission() == 0) {
            if (oNotifICall) {
                oNotifICall.cancel();
            }
            oNotifICall = window.webkitNotifications.createNotification('images/sipml-34x39.png', 'Incaming call', 'Incoming call from ' + s_number);
            oNotifICall.onclose = function () { oNotifICall = null; };
            oNotifICall.show();
        }
    }

</script>

<div class="col">
            <h2>Llamenos Usando WebRTC</h2>
ll <audio id='audio_remote'></audio>
                        &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
   <button class="btn btn-primary" id="btnCall" onclick="call()" >Click Aquí Para Llamarnos!</button>

 &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
   <button class="btn btn-danger hide" id="btnHangUp" onclick="hangup()" >Colgar Llamada</button>

                        &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;
   <span class="label hide" id="mycallstatus"></span>

 &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 
   <span class="label label-inverse" id="mysipstatus">Si ve esta etiquete usted necesita usar Chrome para llamar</span>

                        <p style="font-size: 10px;">WebRTC es una nueva tecnología que usa el Navegador Web para establecer una llamada, en este caso la llamada es de Audio y Usted necesita contar con una diadema(o bien micrófono y bocinas) para llamarnos sin costo alguno.
Esta tecnología por ahora solo es compatible con el navegador Chrome para descargarlo <a href="">de click aqui.</a>
                </div>
                <div class="col"> ll

Si van a usar el ejemplo anterior sólo tienen que editar el siguiente código con los datos de su dispositivo SIP.

//stack options
mySipStack = new SIPml.Stack({
realm: 'asterisk',
impi: 'usuario',
impu: 'sip:usuario@myip',
password: 'mipassword', // optional
display_name: 'TS', // optional
websocket_proxy_url: 'ws://miip:10060', // optional
outbound_proxy_url: 'udp://miip:5060', // optionalk

Y lo más importante es apuntar el número de la llamada hacia nuestra cola de atención previamente creada, eso se logra editando el código(en éste ejemplo la cola creada tiene el número 80000):

//call using the number 80000
mycallSession.call("80000");

Al finalizar tendrán algo como esto:

Paso 5.

Probar el sistema. Video Demo(sin audio por problemas técnicos):

 

Notas.

Es claro que este ejemplo sólo usa un peer SIP, sin embargo estos son algunos hints para crear múltiples usuarios.

  • Crear una página web de atención donde primero verifique los peers registrados.
  • Basados en el punto anterior elegir qué peer registrar.
  • Crear un formulario para que el usuario registre algunos datos básicos como su nombre y pasar estos datos con el peer de registro.
  • Adaptar realtime o bien escribir directamente en la base de datos de asterisk para crear peers ‘dinámicos’.
  • Crear una página web para clientes/usuarios registrados y crear extensiones/peers basados en estos datos, así mismo se pueden crear campañas entrantes con estos datos.

El registro no es necesario realmente, pero de esta forma demuestro que es posible interactuar con asterisk y WebRTC.

WebRTC no necesita de Asterisk para lograr esto, de hecho lo puede hacer Peer to Peer(punto a punto) como lo haría la fantástica aplicación llamada Twelephone, sin embargo este artículo esta diseñado para integrar un sistema de atención online con Elastix y su módulo de call center.

Se puede añadir video a las llamadas ;).

Asterisk Plano también es capaz de esto(y más) usando extensiones directamente o bien una cola de atención. Es solo que estoy de buenas con Elastix. 😀

Para aquellos que no sólo quieran tener soporte en Chrome existe una extensión que permite a los navegadores como Internet Explorer y Opera funcionar con WebRTC se llama webrtc4all.

Recuerden su feedback es bienvenido.

  • Francisco J Loza López

    Excelente artículo, empezando a probar !!
    Para hacerlo con asterisk puro cambia mucho ??

    • navaismo

      Hola, del lado web no cambia más que el número a donde vas a apuntar la llamada. Yo te recomiendo que separes del contexto de tus extensiones este peer webrtc(algo que olvidé comentar en el artículo) y por ejemplo con un GOTO redirecciones la llamada a tu contexto donde tienes la Cola de atención.

      Si ya tienes asterisk PURO puedes implementar una solución multipeer con ARA 😉

      • Francisco J Loza López

        Sobre que version de Asterisk se podria implementar, actualmente tengo la 1.8.X
        Pero del lado de asterisk que configuración hay que hacer ??

        • navaismo

          Como vas a instalar el gateway webrtc2sip es compatible con cualquier versión de asterisk. Elastix por ejemplo usa la 1.8.20, la función del gateway es esa, interconectar el websocket con cualquier sip server(no necesariamente asterisk).

          De tu lado de asterisk solo debes crear el peer como cualquier otro. Códecs válidos, contexto válido, etc.

          • Francisco J Loza López

            Que tal navisimo, estoy compilando webrtc2sip y me manda este error:

            root@webRTC2SIP:/usr/local/src/webrtc2sip# make -j `getconf _NPROCESSORS_ONLN`

            make all-am

            make[1]: Entering directory `/usr/local/src/webrtc2sip’

            g++ -DHAVE_CONFIG_H -I. -I/usr/local/include/tinysak -I/usr/local/include/tinynet -I/usr/local/include/tinyhttp -I/usr/local/include/tinysip -I/usr/local/include/tinydav -I/usr/local/include/tinysdp -I/usr/local/include/tinysigcomp -I/usr/local/include/tinymedia -I/usr/local/include/tinyxcap -I/usr/local/include/tinysms -I/usr/local/include/tinymsrp -I/usr/local/include/tinyrtp -I/usr/local/include/tinyipsec -I/usr/include/libxml2 -I/usr/include -Itinywrap -g -O2 -MT webrtc2sip-mp_c2c.o -MD -MP -MF .deps/webrtc2sip-mp_c2c.Tpo -c -o webrtc2sip-mp_c2c.o `test -f ‘mp_c2c.cc’ || echo ‘./’`mp_c2c.cc

            In file included from mp_net_transport.h:23:0,

            from mp_c2c.h:23,

            from mp_c2c.cc:19:

            mp_object.h:23:23: fatal error: tsk_debug.h: No such file or directory

            compilation terminated.

            make[1]: *** [webrtc2sip-mp_c2c.o] Error 1

            make[1]: Leaving directory `/usr/local/src/webrtc2sip’

            make: *** [all] Error 2

            root@webRTC2SIP:/usr/local/src/webrtc2sip#

            Busque en google a cerca de esto pero no hay nada

            Me estoy basando en esta guia para la instalacion de webRTC2SIP:

            http://linux.autostatic.com/installing-webrtc2sip-on-ubuntu-1204#install_packages

            Salu2

          • navaismo

            Que SO estás usando? Supongo que usas el script del artículo anterior, si es así el script solo es para CentOS 5.X si usas un CentOS 6.X debes usar uno de mis otros scripts por ejemplo para las distros de FreePBX que están en mi blog. Lamentablemente si cambia la forma de instalar entre versiones de CentOS.

          • Francisco J Loza López

            Segun el blog de donde lo estoy revisando es en un ubuntu server 12.04. Y es donde yo lo estoy corriendo.
            Cual es tu blog ? ?
            Ahorita me pongo a instalar la maquina virtual con centos.

          • navaismo

            Mi blog de asterisk es asterisktools.blogspot.com.

            Pero en tu caso es más sencillo instalar el gateway ya que existe un PPA para eso, revisa este enlace: https://groups.google.com/forum/#!topic/doubango/2lGEXzdzMwQ

            El primer mensaje de toda la conversación tiene las instrucciones para instalarlo.

          • Francisco J Loza López

            Los comandos del blog que comente me dan varios errorres, ahora estoy instalando todo tal y como lo dice el documento “technical-guide-1.0.pdf”
            Espero asi no tener problemas.
            Salu2.

          • navaismo

            El PPA de Ubuntu te da problemas? Es raro toda la gente de Ubuntu prefiere usar el ppa a compilar. Si usas las instrucciones de mi blog solo aplica para centos 5 en el caso del script de elastix y centos 6 para freepbx. En todo caso son las mismas instrucciones que la guía técnica.

            Saludos.

          • Francisco J Loza López

            Ok, estoy utilizando el script para freepbx en un centos 6.4.

            El unico error que me marco fue al reiniciar el demonio httpd ya que no tengo instalado ningun servidor http.

            Como se si ya tengo corriendo WebRTC2SIP busque en los procesos y no esta.

          • navaismo

            Los scripts crean una sessión screen, ejecuta el comando: screen -ls si en la salida ves algo que diga ‘wrtc’ esta corriendo algo así:

            There is a screen on:
            12361.wrtc (Detached)
            1 Socket in /var/run/screen/S-root.

            Puedes entrar a ver el estado del gateway con el comando: screen -r wrtc
            Para salir de la sesión script sin detener el gateway usa la combinación de teclas: CTRL+A+D.

          • Francisco J Loza López

            Después de instalar todo corriendo el script me marca esto:
            [root@localhost wrtc4FreePBX]# screen -ls

            No Sockets found in /var/run/screen/S-root.

            [root@localhost wrtc4FreePBX]#

            Entonces corro el ultimo comando del script que según comprendo es para iniciar webrtc2sip:

            [root@localhost wrtc4FreePBX]# screen -dmS wrtc /usr/local/sbin/webrtc2sip –config=/usr/local/sbin/config.xml

            [root@localhost wrtc4FreePBX]# screen -ls

            No Sockets found in /var/run/screen/S-root.

            [root@localhost wrtc4FreePBX]#

            Todo esto en una instalación limpia de Centos 6.4 32 bits.

          • navaismo

            Eso quiere decir que hay un problema con el arranque del gateway.

            Cámbiate al directorio /usr/local/sbin y da ejecuta el comando: ls
            Si existe el binario webrtc2sip, ejecútalo sin la sesión screen.

            Si ves una carpeta llamada sbin y ahi esta el binario webrtc2sip copialo un nivel arriba y ejecutalo sin la sesión screen.

            En ambos casos verifica si hay error al arrancar el binario sin la sesión.

          • Francisco J Loza López

            Solamente hay un config.xml !! 🙁

            [root@localhost wrtc4FreePBX]# cd /usr/local/sbin/

            [root@localhost sbin]# ls

            config.xml

            [root@localhost sbin]#

          • navaismo

            Entonces algo falló en la compilación del gateway. ¿Viste algún error?

            Cámbiate al directorio de los archivos fuente del gateway webrtc2sip y ejecuta los comandos uno por uno. Pega la salida de cada uno de los comandos(no sé si sea una mejor idea usar el foro para eso) es muy importante la salida completa del script configure.

            make distclean
            ./autogen.sh
            ./configure –prefix=/usr/local/sbin
            make clean
            make
            make install

          • Francisco J Loza López

            Ok. voy a abrir un nuevo tema y pego la salida de cada comando.

          • navaismo

            Este script esta probado para un CentOS 6 y compila FFMPEG desde las fuentes: https://dl.dropboxusercontent.com/u/1277237/install_wrtcgw_CentOS6.sh

          • Francisco J Loza López

            Excelente, lo probaré en la tarde !!!

          • Francisco J Loza López

            Es necesario tener instalado apache ?? o algun otro servidor web ??

          • navaismo

            Para ejecutar el gateway webrtc2sip y asterisk no es necesario.
            Si tu vas a hostear la página en el mismo server, si; de lo contrario no es necesario instalar APACHE.

          • Francisco J Loza López

            Listo, ahora si ya esta corrieno el webrtc2sip!!
            Excelente, gracias.
            Ahora a hacer pruebas..

          • Francisco J Loza López

            Estoy preparando los archivos, al ejecutar ./configure –with-ssl –with-srtp –with-speex –with-speexdsp –enable-speexresampler –enable-speexjb –enable-speexdenoiser –with-gsm –with-ffmpeg –with-h264 –prefix=/usr/local

            en lla carpeta de doubango me sale este error:

            configure: error: You requested FFmpeg (h264, h263, theora, mp4v-es) but not found…die

          • navaismo

            Vas a tener que instalar el FFMPEG desde las fuentes, al parecer la librería que usa el CentOS ya no es compatible con la última revisión.

  • navaismo

    ERRATA:

    Me falto añadir este pedazo de código en el ejemplo:

    [quote]

    [/quote]

    Obviamente los sonidos los tienen que descargar junto con al API SIPML5 y cambiar las rutas.

  • redes

    hola navaismo

    lo instale puedo llamar pero no puedo recibir llamadas no
    repica en Cola de atención.

    • navaismo

      Cambiaste el número a llamar para que esté dirigido al de las colas?

    • redes

      ya listo

  • InfoServi ツ

    Se puede hacer esto, pero en lugar de llamar a una cola del callcenter sea hacia una extension? O sea tengo elastix instalado en mi empresa, pero no quiero instalar el modulo de callcenter para esto, y me interesa que desde nuestra pagina web los clientes nos puedan llamar.
    Muy buenos los articulos de la pagina!!

    • navaismo

      Si, debes instalar todo menos el paquete de sipml5toElasix(si usas los rpms), si estas usando los scripts no ejecutes el script install_webfiles.sh

      Solamente tienes que cambiar la parte del código donde se apunta la llamada a la cola 80000 por la extensión que deseas marcar.

  • Manuel

    Podrias dejar el path completo al archivo CSS para descargarlo ?