Alexa skills de audio con la interfaz AudioPlayer: directivas (II)
En el primer post de la serie sobre AudioPlayer hacía una introducción a esa interfaz de Alexa que nos permite crear skills que reproducen audio. Te recomiendo leerlo primero, si aún no lo hiciste, para tener claros los conceptos básicos antes de entrar en algunos detalles más avanzados aquí.
En este post vamos a ver las directivas básicas del AudioPlayer que nos permitirán o bien reproducir un audio o parar una reproducción en curso. Las directivas son información especial que se añade a una respuesta desde el back para que el dispositivo Alexa que se está usando haga algo.
Siempre aviso al inicio de este tipo de artículos que voy a usar el SDK de Java, programando en Kotlin, para el backend. Esto hace diferente la experiencia del desarrollador para esta parte pero los conceptos y la información que cuento aplica igualmente. Al final lo que cambian son detalles derivados por un SDK concreto o la "syntactic sugar" de un lenguaje determinado.
Y otro friendly reminder: para probar este tipo de skills no podemos usar el simulador de la Alexa Developer Console ya que no permite reproducir audio. Vamos a necesitar disponer de un dispositivo con Alexa para ir probando cualquier cosa que hagamos con el AudioPlayer.
Audio Skill de chistes
Antes de entrar en detalles voy a plantear una skill que pone a disposición del usuario varios audios. Por ejemplo, podríamos hacer una skill que reproduzca chistes ya grabados en mp3, sin usar la voz de Alexa.
Alojamiento de los audios
Supongamos que esos audios están alojados en S3 de forma pública con nombres como "chiste-1", "chiste-2", etc. Además hemos decidido que sean archivos MP3. De esa forma estamos cubriendo los requisitos que pone Alexa para que no tengamos problemas al intentar reproducirlos.
La URL de acceso a un chiste podría ser: https://skill-chistes.s3.[region].amazonaws.com/chiste-[n].mp3
. Así podemos fácilmente movernos entre audios (anterior > chiste-[n-1] o siguiente > chiste-[n+1]) e identificar de forma inequívoca para los intents de pausar/continuar, comenzar desde el principio, repetir, etc.
Directivas de AudioPlayer
Para indicar al dispositivo Alexa que está utilizando el usuario que tiene que realizar algún tipo de operación especial, como reproducir como audio el contenido de una URL, hay que usar una directiva.
Estas directivas tienen un formato concreto y forman parte de una respuesta normal que se envía desde el back. Para el AudioPlayer tenemos tres directivas posibles:
AudioPlayer.Play
> Le dice a Alexa que reproduzca el audio indicado por la URL, campoaudioItem
, que va en la respuesta.AudioPlayer.Stop
> Indica parar la reproducción del actual audio, sea cual sea.AudioPlayer.ClearQueue
> Se usa para limpiar la cola de audios que estuvieran programados para sonar.
Yo aún no tengo experiencia gestionando colas de reproducción con lo que no voy a contar cómo usar la directiva de AudioPlayer.ClearQueue
pero dejo el link a la documentación oficial.
Directiva AudioPlayer.Play
A la hora de hacer una skill de audio lo primero que nos interesará será que Alexa reproduzca el fichero MP3 que tenemos alojado, en este caso, en un supuesto S3. Esta directiva la podemos añadir a la respuesta de cualquier petición, ya sea un LaunchRequest
o IntentRequest
.
Cosas a tener en cuenta a la hora de añadir la directiva de play a una respuesta:
- El formato de esta directiva es bastante extenso ya que permite, por ejemplo, indicar metadatos si estamos en un dispositivo con pantalla pero no estamos usando APL. De esta forma a la salida de audio se le podría acompañar con una salida visual mínima.
- Podemos incluir también una salida de texto que Alexa dirá justo antes de reproducir el audio.
- Normalmente querremos que Alexa finalice la sesión y reproduzca el audio simplemente. En caso contrario, Alexa comenzará a reproducir el audio y de forma inmediata lo pausará para quedarse a la escucha del usuario. Ese no sería el comportamiento esperado para este tipo de skills.
Antes de ver el código de la directiva es necesario comentar un campo obligatorio de la misma: el PlayBehavior
. El valor de este campo va a indicar el comportamiento que tiene que tener el playback de Alexa con el audio que se le envía. Hay tres posibles valores:
REPLACE_ALL
> que comienza la reproducción del audio que se le está pasando remplazando el actual y la cola pendiente que hubiera. Será el usado en nuestro ejemplo.ENQUEUE
> que encola el audio indicado al final de la actual cola sin afectar a la reproducción en curso.REPLACE_ENQUEUED
> remplaza la cola actual sin afectar a la reproducción en curso.
Para añadir la directiva a la respuesta, usando el SDK de Java y Kotlin, tenemos un builder
que nos facilitará la vida bastante:
- En el
builder
añadimos la directiva de AudioPlayer. Esto equivaldría a poner eltype: AudioPlayer.Play
si estuviéramos usando Javascript/Typescript. - Indicar el comportamiento del playback a
REPLACE_ALL
como ya dijimos anteriormente, ya que no vamos a usar una cola de reproducción. - Indicar desde qué punto tiene Alexa que reproducir el audio que se le pasa. Para comenzar desde el principio usamos el valor de 0 (
0L
en Kotlin ya que es unLong
). Cuando lleguemos a la parte de reanudar un audio pausado indicaremos aquí otro valor. - El valor de un "token previo", obligatorio si estamos usando colas, para identificar cualquier reproducción previa. En este caso no lo necesitamos y lo ponemos a
null
. - Un token para la reproducción que estamos enviando. Es obligatorio siempre. Para nuestro ejemplo vale cualquier valor como:
audioSkill
. - La URL que identifica el audio.
Directiva AudioPlayer.Stop
Esta directiva para parar la reproducción del audio en curso es mucho más sencilla que la de play
al no tener parámetros ni nada de configuración. Basta con añadirla a la respuesta que nos interese:
El uso de estas directivas va a provocar que se generen los eventos del playback y tengamos que manejarlos correctamente en nuestro back. Esto va íntimamente relacionado con los built-in que se pueden generar por peticiones del usuario.
Veremos todos los detalles en siguientes entregas de esta serie de artículos :)