Skip to content
Christian Gastrell edited this page Jun 23, 2015 · 2 revisions

recordApi

Si bien ya vimos como crear un objeto que nos ayude con la funcion de grabar audio, este es un poco mas complejo en algunos aspectos y mas simple en otros.

En este caso dependemos de una estructura de datos (la guia que usaremos para entrevistar) y al mismo tiempo estaremos creando otra estructura de datos (la entrevista que estamos realizando). Esto afecta como inicializamos recordApi y empezamos a depender de la interfaz, que deberiamos inicializar con antelacion (no deberiamos inicializar los botones cada vez, sino que deberian estar previamente inicializados).

var recordApi = {
  initialize: function(callback){
    //referencia al boton
    recordApi.button = $('#record');

    //referencia al reloj
    recordApi.clock = $('#record-time');

    //inicializar estado
    recordApi.isRecording = false;

    //inicializar variable para el timer
    recordApi.timer = null;

    //referencia al directorio "audio"
    fileApi.getDir('audio', function(err, dir){
      if(err) {
        console.log(err);
        return;
      }
      recordApi.audioDir = dir;
      callback && callback();
    });
  },
  nuevaGrabacion: function(guiaId, callback){
    var fileName = guid();
    var onError = function(err) {
      callback && callback(err, null);
    }
    var onFile = function(fileEntry) {
      recordApi.entrevista = {
        id: fileName,
        audioPath: fileEntry.nativeURL,
        interview: guiaId,
        start: null,
        stop: null,
        tags: []
      };
      recordApi.recordFile = fileEntry.nativeURL;
      callback && callback(null, fileEntry);
    }
    recordApi.audioDir.getFile(fileName, {create:true}, onFile, onError);
  },
  createTagButton: function(ref) {
    var button = $('<button />')
      .addClass("ui-btn ui-btn-inline ui-mini")
      .text('+')
      .click(function(e){
        if(!recordApi.isRecording) {
          return;
        }
        console.log('tag ' + ref + ' @ ' + new Date());
        recordApi.entrevista.tags.push({ref: ref, time: new Date()});
      });
    return button;
  },
  updateClock: function(){
    var recordTime = ((new Date() - recordApi.entrevista.start) / 1000) << 0;
    recordApi.clock.text(clockFormat(recordTime));
  },
  record: function(){
    recordApi.media = new Media(recordApi.recordFile, recordApi.onStop, recordApi.onError, recordApi.onStatus);
    recordApi.media.startRecord();
  },
  stop: function(){
    recordApi.media.stopRecord();
  },
  onStop: function(){
    console.log('recordApi.onStop');
    recordApi.media.release();
    recordApi.media = null;
    recordApi.entrevista.stop = new Date();
    entrevistas.agregar(recordApi.entrevista, function(entrevista){
      $('#revision').data('entrevistaIdx',entrevistas.lista.length - 1);
      $(':mobile-pagecontainer').pagecontainer('change','#revision');
    });
    // mediaApi.load(recordApi.recordFile);
  },
  onError: function(err){
    console.log('Recording error');
    console.log(err);
  },
  onStatus: function(status){
    switch(status) {
      case Media.MEDIA_NONE: console.log('Status change: idle');
      break;
      case Media.MEDIA_STARTING:
        console.log('Status change: starting');
      break;
      case Media.MEDIA_RUNNING:
        console.log('Status change: running');
        recordApi.timer = setInterval(recordApi.updateClock,500);
        recordApi.isRecording = true;
        recordApi.entrevista.start = new Date();
        recordApi.button.css('background-color','red');
        recordApi.button.text('Detener');
        $.mobile.loading('hide');
      break;
      case Media.MEDIA_PAUSED: console.log('Status change: paused');
      break;
      case Media.MEDIA_STOPPED:
        console.log('Status change: stopped');
        clearInterval(recordApi.timer);
        recordApi.timer = null;
        recordApi.isRecording = false;
        recordApi.button.css('background-color', '#333');
        recordApi.button.text('Grabar');
      break;
      default: console.log('unknown status');
    }
  }
}

initialize

Durante la inicializacion guardamos referencias a elementos HTML que existen en la pagina #interview (que es la que se mostrara mientras estemos grabando): #record y #record-time

Tambien llamamos a fileApi.getDir y guardamos el resultado en la variable recordApi.audioDir. Esta referencia nos permite luego crear los archivos de audio sin tanto ajetreo contra el fileApi

  initialize: function(callback){
    //referencia al boton
    recordApi.button = $('#record');

    //referencia al reloj
    recordApi.clock = $('#record-time');

    //inicializar estado
    recordApi.isRecording = false;

    //inicializar variable para el timer
    recordApi.timer = null;

    //referencia al directorio "audio"
    fileApi.getDir('audio', function(err, dir){
      if(err) {
        console.log(err);
        return;
      }
      recordApi.audioDir = dir;
      callback && callback();
    });
  },

nuevaGrabacion

Con este metodo inicializamos una nueva grabacion: creamos una entrevista vacia en recordApi.entrevista haciendo referencia a un id de guia. Tambien generamos un UUID para identificar la entrevista y el archivo de audio.

Luego usamos la referencia al directorio que creamos en la inicializacion recordApi.audioDir para crear el nuevo archivo de grabacion y con el resultado guardamos la URL del archivo en el objeto recordApi.entrevista.audioPath

  nuevaGrabacion: function(guiaId, callback){
    var fileName = guid();
    var onError = function(err) {
      callback && callback(err, null);
    }
    var onFile = function(fileEntry) {
      recordApi.entrevista = {
        id: fileName,
        audioPath: fileEntry.nativeURL,
        interview: guiaId,
        start: null,
        stop: null,
        tags: []
      };
      recordApi.recordFile = fileEntry.nativeURL;
      callback && callback(null, fileEntry);
    }
    recordApi.audioDir.getFile(fileName, {create:true}, onFile, onError);
  },

updateClock

Esta funcion es la que va a ejecutar el interval de recordApi y se encarga de mantener el reloj corriendo mientras estamos grabando.

  updateClock: function(){
    var recordTime = ((new Date() - recordApi.entrevista.start) / 1000) << 0;
    recordApi.clock.text(clockFormat(recordTime));
  },

Notar la operacion entre fechas (date) que devuelve la diferencia entre las 2 fechas en milisegundos y las funciones de ayuda clockFormat() y guid() que explicaremos luego.

createTagButton

Teniamos esta funcion pero ahora la incluimos en el objeto ya que necesitaremos distinta funcionalidad cuando estamos grabando y cuando estamos revisando una entrevista

  createTagButton: function(ref) {
    var button = $('<button />')
      .addClass("ui-btn ui-btn-inline ui-mini")
      .text('+')
      .click(function(e){
        if(!recordApi.isRecording) {
          return;
        }
        recordApi.entrevista.tags.push({ref: ref, time: new Date()});
      });
    return button;
  },

onStop

La funcion que se ejecuta cuando detenemos la grabacion se encarga principalmente de limpiar un poco y llevarnos a la vista de revision con la entrevista recien grabada

  onStop: function(){
    console.log('recordApi.onStop');
    recordApi.media.release();
    recordApi.media = null;
    recordApi.entrevista.stop = new Date();
    entrevistas.agregar(recordApi.entrevista, function(entrevista){
      $('#revision').data('entrevistaIdx',entrevistas.lista.length - 1);
      $(':mobile-pagecontainer').pagecontainer('change','#revision');
    });
  },

A su vez tambien marca el Date en entrevista.stop y usa el metodo entrevistas.agregar para guardar los datos de la entrevista. Al finalizar esta llamada hacemos 2 cosas:

  • configurar la propiedad data de la vista de revision con el ultimo indice del array de entrevistas (entrevistas.length - 1)
  • nos dirige, por codigo, a la pagina #revision (si, en jQueryMobile es un asco esta llamada, pero es lo que hay) $(':mobile-pagecontainer').pagecontainer('change','#revision');

onStatus

Cuando detectamos el cambio de estado del archivo (recordApi.media) a RUNNING (o sea, grabando) nos encargamos de configurar ultimos detalles (entrevista.start = new Date()) e inicializamos el setInterval para mantener el reloj, cambiamos el texto y color del boton. Luego cuando cambie a STOPPED volveremos todo atras para que quede listo para otra grabacion.

  onStatus: function(status){
    switch(status) {
      case Media.MEDIA_RUNNING:
        console.log('Status change: running');
        recordApi.timer = setInterval(recordApi.updateClock,500);
        recordApi.isRecording = true;
        recordApi.entrevista.start = new Date();
        recordApi.button.css('background-color','red');
        recordApi.button.text('Detener');
        $.mobile.loading('hide');
      break;
      case Media.MEDIA_STOPPED:
        console.log('Status change: stopped');
        clearInterval(recordApi.timer);
        recordApi.timer = null;
        recordApi.isRecording = false;
        recordApi.button.css('background-color', '#333');
        recordApi.button.text('Grabar');
      break;
    }
  }

Ahora vemos un par de funciones de ayuda que estamos utilizando antes de probar.

  1. Repaso y conceptos basicos
  2. Ejercicios para repasar
  3. Problematica de desarrollo mobile
  4. Phonegap
  5. Requerimientos e instalacion
  6. Phonegap CLI
  7. [Primeros ejercicios con Phonegap](Ejercicio Phonegap)
  8. Plugins
  9. Hello world
  10. Estructura de un proyecto Phonegap
  11. Plugin Device
  12. Debugging
  13. Incorporando un framework CSS
  14. Plugin Vibration
  15. Sumando partes
  16. Plugin Battery Status
  17. Un poco de jQuery
  18. jQuery Mobile
  19. Navegacion
  20. Plugin Dashboard
  21. Revision de Plugin Dashboard
  22. Paginas extra
  23. ToDo
  24. Persistencia
  25. ToDo Persistente
  26. Plugin Camera
  27. Opciones de camara
  28. App Mi Galeria
  29. Revision de Galeria
  30. Plugin File
  31. Escribir y leer texto
  32. Escribir archivos binarios
  33. Guardando fotos
  34. Debugger: weinre
  35. Inspeccionar con weinre
  36. Phonegap Developer App
  37. Refactor de apps
  38. Plugin Media
  39. Pruebas con audio
  40. Control y monitoreo de audio
  41. Encapsular play/pausa
  42. Hacks
  43. Formato de tiempos
  44. Grabar y reproducir
  45. Proyecto Integrador
  46. Revision de interfaz
  47. Interfaz basica
  48. Entrevista: modelo
  49. Funcionalidad: revision
  50. Seleccion de framework
  51. iRec: navegacion
  52. iRec: fileApi
  53. iRec: guias
  54. iRec: entrevistas
  55. iRec: recordApi
  56. iRec: helpers
  57. iRec: mediaApi
  58. iRec: inicializar paginas
  59. iRec: refactor
  60. iRec: mediaApi refactor
  61. iRec: recordApi refactor
  62. iRec: helpers
  63. iRec: guias.js
  64. iRec: entrevistas.js
  65. iRec: crear guias
  66. iRec: re-inicializando
  67. iRec: re-ordenando
  68. iRec: pendientes
  69. iRec: reporte ux
  70. iRec:revision: volver
  71. iRec:entrevista: volver
  72. iRec:revision: cambios
  73. iRec:revision: stop
  74. iRec:revision: Rew 10"
  75. iRec:revision: tag Go
  76. iRec: limpieza
  77. Firma de apps
  78. Android
  79. Generacion de key
  80. Firma de apk
  81. Alineacion de zip
  82. Firmar con Phonegap
  83. iOS
  84. Detalles finales
  85. Config.xml
  86. Iconos
  87. Splash
Clone this wiki locally