paint-brush
Cómo transmito en vivo mi cerebro con Amazon IVS, una diadema Muse y Reactpor@amazonivs
4,671 lecturas
4,671 lecturas

Cómo transmito en vivo mi cerebro con Amazon IVS, una diadema Muse y React

Demasiado Largo; Para Leer

Esta es la primera vez que usamos React para transmitir en vivo nuestros datos cerebrales. Usamos el SDK de transmisión web de Amazon IVS para transmitir nuestros datos cerebrales en vivo a la nube. No vamos a ver cada paso para utilizar el SDK en esta publicación. En cambio, veremos los aspectos más destacados para tener una idea general de cómo funciona. El primer paso es instalar el módulo am-ivcast para ejecutar nuestra herramienta de transmisión: En el módulo de transmisión-transmisión, debemos importarlo a nuestro paquete favorito: En la herramienta de transmisión, tenemos otro paso para obtener otro paso en el proyecto.
featured image - Cómo transmito en vivo mi cerebro con Amazon IVS, una diadema Muse y React
Amazon Interactive Video Service (IVS)  HackerNoon profile picture
0-item

A principios de este año, creé un proyecto muy divertido que llamé "Brain
a la nube", donde guardé los datos de mi cerebro en la nube mientras jugaba
Call of Duty para poder analizar la relación entre mi
Función cognitiva y rendimiento en videojuegos. Escribí una de tres partes
serie de publicaciones de blog y creé algunos videos divertidos para resumir mis hallazgos sobre
ese proyecto Si desea comprobarlos, puede consultar el
enlaces en la parte inferior de esta publicación. Unos meses después de que publiqué eso
proyecto, comencé a trabajar en Twitch como desarrollador defensor principal para
Amazon Interactive Video Service (Amazon IVS): una solución completamente administrada
para crear soluciones de transmisión de video interactivas en vivo (consulte esta serie para obtener más información). El siguiente paso de mi proyecto "Brain to the Cloud" era obvio: necesitaba transmitir en vivo mi cerebro.

Transmitiendo mi cerebro

Antes de mirar el código, veamos el producto final. Hay 2
vistas para la aplicación: una vista de transmisión y una vista de reproducción. En
la vista de transmisión, podemos obtener una vista previa del video en vivo, iniciar el
transmitir y conectar la diadema Muse para transmitir los datos del cerebro
obtenido de la diadema. En la vista de reproducción, mostramos el vivo
corriente con un

 <video>
elemento, y trazar los datos del cerebro en tiempo real

Descripción del proyecto

Hay 5 pasos para este proyecto:

  1. Transmitir transmisión en vivo
  2. Captura datos cerebrales
  3. Publique datos cerebrales como metadatos cronometrados dentro de la transmisión en vivo
  4. Reproducción de transmisión en vivo
  5. Escuche metadatos cronometrados y represente datos cerebrales en un gráfico en tiempo real

Si prefiere representaciones gráficas de tales cosas, así es como se ve:

Construyendo el Proyecto

Usé React para este proyecto. ¿Por qué? Bueno, tengo mucha experiencia.
con Vue y Angular, pero probablemente sea uno de los últimos desarrolladores en
tierra para probar React. Supuse que ya era hora de descubrir qué era todo
el bombo estaba a punto, y yo sabía que esto no sería difícil
proyecto a construir con él. Debido a mi falta de experiencia previa, no estoy
lo que llamarías un usuario "avanzado" del marco, pero tengo que decir
que estoy bastante contento con lo que veo hasta ahora. encontré el proceso
agradable y no me encontré "luchando" con el marco. Pero
esta publicación de blog no se trata de mi opinión sobre los marcos de JavaScript, así que
guárdalo para una publicación futura. En su lugar, hablemos de cómo transmito
¡mi cerebro!

El hardware

En mi proyecto original "Brain to the Cloud", usé un EEG "antiguo"
auricular llamado MindFlex para capturar las lecturas de mi cerebro. funcionó bastante
bueno, pero me requirió "hackear" el dispositivo agregando un ESP-12
microcontrolador para extraer las lecturas del dispositivo y enviarlas
ellos a la nube. Esta vez busqué algo un poco más nuevo:
y algo que podría usar sin modificaciones. Después de un poco de
investigación, me decidí por la diadema Muse S. Afortunadamente, hay una biblioteca de código abierto realmente increíble llamada muse-js que me permite acceder a las lecturas cerebrales directamente en un navegador web con Web Bluetooth (en navegadores compatibles, por supuesto).

La transmisión en vivo

Hasta hace poco, la transmisión en vivo con Amazon IVS requería que usáramos un
cliente de terceros para transmitir nuestras transmisiones como RTMPS. Pero recientemente
lanzó un cambio de juego: el SDK de transmisión web de Amazon IVS .
Como su nombre lo indica, este SDK nos brinda la capacidad de transmitir nuestro
transmisión en vivo a través de WebRTC directamente desde un navegador web. Claramente, esto fue un
ajuste perfecto para la transmisión en vivo de mi cerebro, ya que significa que puedo crear
una solución "todo en uno" para transmitir los datos de mi cerebro junto con mi
transmisión en vivo sin depender de software de terceros o scripts externos.

Agregar transmisión web a la aplicación React

No vamos a ver cada uno de los pasos necesarios para utilizar el
Web Broadcast SDK en esta publicación. En su lugar, veremos los aspectos más destacados para
obtener una idea general de cómo funciona. No te preocupes, tengo otra publicación.
próximamente donde profundizaremos en el proceso "paso a paso" para usar
el SDK de Web Broadcast, así que estad atentos. Dicho esto, tomemos un
recorrido rápido para ver cómo utilicé el SDK en este proyecto. mi primer paso
fue usar una transmisión web para instalar el

 amazon-ivs-web-broadcast
módulo. Con su herramienta de administración de paquetes favorita, ejecute:

 $ npm install amazon-ivs-web-broadcast

A continuación, debemos importarlo a nuestro componente. En mi componente Broadcast.jsx, agregué:

 import IVSBroadcastClient, { STANDARD_LANDSCAPE } from 'amazon-ivs-web-broadcast' ;

Podemos crear una instancia de IVSBroadcastClient con la configuración de flujo deseada e ingerir el punto final de nuestro canal Amazon IVS y establecerlo en el estado de nuestro componente.

 this .setState({  broadcastClient : IVSBroadcastClient.create({    streamConfig : STANDARD_LANDSCAPE,    ingestEndpoint : this .state.ingestEndpoint, }) });

Ahora que tenemos una instancia del cliente, podemos agregar nuestra cámara al cliente. Para esto usamos

 navigator.mediaDevices.getUserMedia()
.

 const streamConfig = STANDARD_LANDSCAPE; const videoStream = await navigator.mediaDevices.getUserMedia({    video : {        deviceId : { exact : this .state.selectedVideoDeviceId },        width : {            ideal : streamConfig.maxResolution.width,            max : streamConfig.maxResolution.width, },        height : {            ideal : streamConfig.maxResolution.height,            max : streamConfig.maxResolution.height, }, }, }); this .state.broadcastClient.addVideoInputDevice(videoStream, 'camera1' , { index : 0 });

Agregar el micrófono del usuario al cliente sigue un patrón similar.

 const audioStream = await navigator.mediaDevices.getUserMedia({    audio : {        deviceId : this .state.selectedAudioDeviceId }, }); this .state.broadcastClient.addAudioInputDevice(audioStream, 'mic1' );
Nota: debido al modelo de seguridad del navegador, necesitamos obtener permisos para acceder a la cámara y al micrófono del usuario. Consulte la fuente del proyecto en GitHub para obtener más información sobre esto y para ver cómo capturé una lista de
dispositivos y los presentó en un cuadro de diálogo para permitir al usuario elegir el
dispositivo de transmisión si hay varias opciones disponibles.

Ahora podemos agregar una vista previa en vivo a la página para que podamos ver lo que nuestros espectadores finalmente verán en el lado del jugador.

 <canvas ref={ this .previewRef} id= 'broadcast-preview' ></canvas>

Y adjunte la vista previa a la

 broadcastClient
:

 this .state.broadcastClient.attachPreview( this .previewRef.current);

Para iniciar la transmisión, agregue un botón a la página, y en el

 onClick
controlador para la llamada de botón
 startBroadcast()
sobre el
 broadcastClient
(pasando lo necesario
 streamKey
).

 this .state.broadcastClient.startBroadcast( this .state.streamKey);

Obtención de datos de mi cerebro

Como mencioné anteriormente, usé el

 muse-js
biblioteca, que brinda la capacidad de conectarse a la banda para la cabeza y extraer los datos sin procesar. Sin embargo,
 muse-js
no calcula las potencias de banda absolutas para los datos de EEG. Para esto, necesitaba buscar otra biblioteca :
 eeg-pipes
.

El primer paso es agregar e importar las bibliotecas.

 $ npm install muse-js $ npm install @neurosity/pipes
 import { zipSamples, MuseClient } from 'muse-js' ; import { powerByBand, epoch, fft } from '@neurosity/pipes' ;

A continuación, agregué un botón con un controlador de clic. En el controlador, yo
conéctese a los auriculares, comience a escuchar datos y suscríbase al
corriente.

 const client = new MuseClient(); await client.connect(); await client.start(); zipSamples(client.eegReadings) .pipe( epoch({ duration : 1024 , interval : 250 , samplingRate : 256 }), fft({ bins : 256 }), powerByBand(), ) .subscribe(    ( data ) => {      const ch0 = [data.delta[ 0 ], data.theta[ 0 ], data.alpha[ 0 ], data.beta[ 0 ], data.gamma[ 0 ]];      const ch1 = [data.delta[ 1 ], data.theta[ 1 ], data.alpha[ 1 ], data.beta[ 1 ], data.gamma[ 1 ]];      const ch2 = [data.delta[ 2 ], data.theta[ 2 ], data.alpha[ 2 ], data.beta[ 2 ], data.gamma[ 2 ]];      const ch3 = [data.delta[ 3 ], data.theta[ 3 ], data.alpha[ 3 ], data.beta[ 3 ], data.gamma[ 3 ]];      const meta = [ch0, ch1, ch2, ch3];      //publish metadata
 } );

Publicación de mis datos cerebrales como metadatos cronometrados

Ahora que tengo un controlador que recopila datos de mi cerebro de Muse
banda para la cabeza, es hora de publicar esos datos como metadatos cronometrados en vivo
corriente.

Lo maravilloso de
 timed metadata
es que está directamente incrustado en la transmisión de video y sigue siendo una parte permanente de esa transmisión. Eso significa que existe incluso en versiones grabadas, lo que significa que incluso en la reproducción bajo demanda podemos escuchar y responder a los eventos.

El SDK de Web Broadcast no admite la publicación de metadatos cronometrados desde el lado del cliente, por lo que tendremos que usar

 putMetadata
( docs ) a través de AWS SDK para JavaScript . Para esto, creé una función AWS Lambda.

 const AWS = require ( 'aws-sdk' ); const ivs = new AWS.IVS({  apiVersion : '2020-07-14' ,  region : 'us-east-1'
}); exports .send = async (event, context, callback) => {  // response object
  const response = {      'statusCode' : 200 ,      'headers' : {          'Access-Control-Allow-Origin' : '*' ,          'Access-Control-Allow-Methods' : 'OPTIONS,GET,PUT,POST,DELETE' ,          'Content-Type' : 'application/json'
 },      'body' : '' ,      'isBase64Encoded' : false
 };  // parse payload
  let payload;  try { payload = JSON .parse(event.body); }  catch (err) { response.statusCode = 500 ; response.body = JSON .stringify(err); callback( null , response);    return ; }  // validate payload
  if (!payload || !payload.channelArn || !payload.metadata) { response.statusCode = 400 ; response.body = 'Must provide, channelArn and metadata' ; callback( null , response);    return ; }  // check payload size
  let byteLength = Buffer.byteLength(payload.metadata, 'utf8' );  if (byteLength > 1024 ) { response.statusCode = 400 ; response.body = 'Too big. Must be less than or equal to 1K' ; callback( null , response);    return ; }  // putmetadata input
  let params = {    channelArn : payload.channelArn,    metadata : payload.metadata };  try {    await ivs.putMetadata(params).promise(); response.statusCode = 200 ; response.body = JSON .stringify({ 'published' : true }, '' , 2 ); callback( null , response); }  catch (err) { response.statusCode = 500 ; response.body = err.stack; callback( null , response);    return ; } };

Para publicar mis datos cerebrales como metadatos cronometrados, creé un Amazon API Gateway para invocar la función y modificar el

 subscribe()
método anterior para llamar a la función AWS Lambda.

 zipSamples(client.eegReadings) .pipe( epoch({ duration : 1024 , interval : 250 , samplingRate : 256 }), fft({ bins : 256 }), powerByBand(), ) .subscribe(    ( data ) => {      const ch0 = [data.delta[ 0 ], data.theta[ 0 ], data.alpha[ 0 ], data.beta[ 0 ], data.gamma[ 0 ]];      const ch1 = [data.delta[ 1 ], data.theta[ 1 ], data.alpha[ 1 ], data.beta[ 1 ], data.gamma[ 1 ]];      const ch2 = [data.delta[ 2 ], data.theta[ 2 ], data.alpha[ 2 ], data.beta[ 2 ], data.gamma[ 2 ]];      const ch3 = [data.delta[ 3 ], data.theta[ 3 ], data.alpha[ 3 ], data.beta[ 3 ], data.gamma[ 3 ]];      const meta = [ch0, ch1, ch2, ch3];      // put metadata if broadcasting
      if ( this .state.isBroadcasting) { fetch(LAMBDA_URL, {          'method' : 'POST' ,          'mode' : 'no-cors' ,          'headers' : {            'Content-Type' : 'application/json' , },          'body' : JSON .stringify({            channelArn : this .state.channelArn,            metadata : JSON .stringify(meta) }) }); } } );

Construyendo la reproducción de transmisión en vivo y registrando los datos de mi cerebro

Una vez que se completó la transmisión en vivo con la vista de transmisión de datos cerebrales, se
tiempo para crear una experiencia de reproducción que muestre la transmisión en vivo
y registre los datos cerebrales en tiempo real tal como llegaron a través de metadatos cronometrados.

Crear el reproductor de transmisión en vivo

Podemos usar el IVS Web Player SDK a través de NPM, pero dado que usa WebAssembly, las cosas pueden complicarse . Para evitar ese engaño, me resulta más fácil usar el reproductor web a través de un

 <script>
etiqueta y lo agregué a mi
 index.html
en mi aplicación React.

 <script src= "https://player.live-video.net/1.12.0/amazon-ivs-player.min.js" ></script>

En mi

 Playback.jsx
componente, agarro una referencia al jugador y algunos elementos necesarios.

 const { IVSPlayer } = window ; const { create : createMediaPlayer, isPlayerSupported, PlayerEventType, PlayerState } = IVSPlayer; const { ENDED, PLAYING, READY, BUFFERING } = PlayerState; const { TEXT_METADATA_CUE, ERROR } = PlayerEventType;

Para la reproducción, usamos el nativo

 <video>
etiqueta.

 <video ref={ this .videoRef} controls playsInline></video>

Y para inicializar el reproductor y comenzar la reproducción:

 this .playerRef.current = createMediaPlayer(); this .playerRef.current.attachHTMLVideoElement( this .videoRef.current); this .playerRef.current.load(STREAM_URL); this .playerRef.current.play();

Escuchar y responder a metadatos cronometrados

Ahora que estamos reproduciendo la transmisión en vivo, podemos escuchar y responder a los datos cerebrales entrantes.

 this .playerRef.current.addEventListener(TEXT_METADATA_CUE, this .onPlayerMetadata);

Establezca los datos del cerebro en nuestro estado de componente:

 onPlayerMetadata = ( e ) => {  //console.log(e);
  const data = JSON .parse(e.text);  this .setState( state => { state.ch0.datasets[ 0 ].data = data[ 0 ]; state.ch1.datasets[ 0 ].data = data[ 1 ]; state.ch2.datasets[ 0 ].data = data[ 2 ]; state.ch3.datasets[ 0 ].data = data[ 3 ];    this .chartReferenceCh0.current.data.datasets[ 0 ].data = state.ch0.datasets[ 0 ].data;    this .chartReferenceCh1.current.data.datasets[ 0 ].data = state.ch1.datasets[ 0 ].data;    this .chartReferenceCh2.current.data.datasets[ 0 ].data = state.ch2.datasets[ 0 ].data;    this .chartReferenceCh3.current.data.datasets[ 0 ].data = state.ch3.datasets[ 0 ].data;    return ({      ch0 : state.ch0,      ch1 : state.ch1,      ch2 : state.ch2,      ch3 : state.ch3 }); }); };

Y renderícelo con un gráfico de barras (con Chart.js):

 <Bar data={ this .state.ch0} ref={ this .chartReferenceCh0} options={ {      aspectRatio : 1 ,      title : {        display : true ,        text : 'Channel: ' + channelNames[ 0 ] },        responsive : true ,        tooltips : {          enabled : false 
 },        legend : {          display : false 
 } } } />

La visualización es genial y ciertamente proporciona una forma divertida de ver mi
datos cerebrales mientras estoy transmitiendo en vivo un juego, pero no proporciona una tonelada de
contexto. Así que pensé que tendría sentido incluir algunos cálculos
para dar una idea de lo que los datos realmente significan. Por eso encontré
algunos cálculos en el

 muse-lsl
proyecto en GitHub
que incluía algunas fórmulas que se pueden usar para calcular factores como
relajación (alfa dividida por delta) y concentración (beta dividida por
theta). Otra excelente publicación de blog que encontré destacaba una forma de derivar la fatiga ((theta + alpha) / beta). Envolví estos cálculos en un componente útil y reutilizable.

 <Row className= 'mb-2' > { /* Delta: 0 Theta: 1 Alpha: 2 Beta: 3 Gamma: 4 */ } <Col xs={ 12 } xxl={ 4 } className= 'align-items-center mb-2 mb-xxl-0' >    < Badge className = 'fs-6 w-100' bg = 'info' >
 Relaxation:      < span className = 'fw-bold' >
        < NumberFormat 
          value = {this.props.dataset.data[0] ? ( this.props.dataset.data [ 2 ] / this.props.dataset.data [ 0 ]) : 0 }          decimalScale = {2} 
          displayType = { ' text '} />
      </ span >
    </ Badge > 
 </Col>  < Col xs = {12} xxl = {4} className = 'align-items-center mb-2 mb-xxl-0' >
    < Badge className = 'fs-6 w-100' bg = 'info' >
 Fatigue:      < span className = 'fw-bold' >
        < NumberFormat 
          value = { this.props.dataset.data [ 3 ] ? ( ( this.props.dataset.data [ 1 ] + this.props.dataset.data [ 2 ]) / this.props.dataset.data [ 3 ] ) : 0 }          decimalScale = {2} 
          displayType = { ' text '} />
      </ span >
    </ Badge > 
  </ Col >
  < Col xs = {12} xxl = {4} className = 'align-items-center mb-2 mb-xxl-0' >
    < Badge className = 'fs-6 w-100' bg = 'info' >
 Focus:      < span className = 'fw-bold' >
        < NumberFormat 
          value = {this.props.dataset.data[1] ? ( this.props.dataset.data [ 3 ] / this.props.dataset.data [ 1 ]) : 0 }          decimalScale = {2} 
          displayType = { ' text '} />
      </ span >
    </ Badge >
  </ Col >
</Row>

Resumen

En esta publicación, vimos cómo creé una aplicación React para vivir
transmitir mis datos cerebrales con Amazon IVS. Si desea obtener más información sobre
Amazon IVS, consulte la serie Getting Started with Amazon Interactive Video Service aquí en dev.to. Si está interesado en probar la aplicación o simplemente consultar el código fuente completo de la aplicación, compruébelo en GitHub . Sus comentarios, preguntas y comentarios siempre son bienvenidos, así que deje un comentario aquí o conéctese conmigo en Twitter

Enlaces