-
Notifications
You must be signed in to change notification settings - Fork 1
irec 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');
}
}
}
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();
});
},
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);
},
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.
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;
},
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');
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.
- Repaso y conceptos basicos
- Ejercicios para repasar
- Problematica de desarrollo mobile
- Phonegap
- Requerimientos e instalacion
- Phonegap CLI
- [Primeros ejercicios con Phonegap](Ejercicio Phonegap)
- Plugins
- Hello world
- Estructura de un proyecto Phonegap
- Plugin Device
- Debugging
- Incorporando un framework CSS
- Plugin Vibration
- Sumando partes
- Plugin Battery Status
- Un poco de jQuery
- jQuery Mobile
- Navegacion
- Plugin Dashboard
- Revision de Plugin Dashboard
- Paginas extra
- ToDo
- Persistencia
- ToDo Persistente
- Plugin Camera
- Opciones de camara
- App Mi Galeria
- Revision de Galeria
- Plugin File
- Escribir y leer texto
- Escribir archivos binarios
- Guardando fotos
- Debugger: weinre
- Inspeccionar con weinre
- Phonegap Developer App
- Refactor de apps
- Plugin Media
- Pruebas con audio
- Control y monitoreo de audio
- Encapsular play/pausa
- Hacks
- Formato de tiempos
- Grabar y reproducir
- Proyecto Integrador
- Revision de interfaz
- Interfaz basica
- Entrevista: modelo
- Funcionalidad: revision
- Seleccion de framework
- iRec: navegacion
- iRec: fileApi
- iRec: guias
- iRec: entrevistas
- iRec: recordApi
- iRec: helpers
- iRec: mediaApi
- iRec: inicializar paginas
- iRec: refactor
- iRec: mediaApi refactor
- iRec: recordApi refactor
- iRec: helpers
- iRec: guias.js
- iRec: entrevistas.js
- iRec: crear guias
- iRec: re-inicializando
- iRec: re-ordenando
- iRec: pendientes
- iRec: reporte ux
- iRec:revision: volver
- iRec:entrevista: volver
- iRec:revision: cambios
- iRec:revision: stop
- iRec:revision: Rew 10"
- iRec:revision: tag Go
- iRec: limpieza
- Firma de apps
- Android
- Generacion de key
- Firma de apk
- Alineacion de zip
- Firmar con Phonegap
- iOS
- Detalles finales
- Config.xml
- Iconos
- Splash