No início deste ano, criei um projeto muito divertido que chamei de "Brain to the Cloud" onde salvei meus dados cerebrais na nuvem enquanto jogava Call of Duty para que eu pudesse analisar a relação entre meu função cognitiva e desempenho de videogame. Eu escrevi um em três partes série de postagens no blog e criei alguns vídeos divertidos para resumir minhas descobertas sobre aquele projeto. Se você gostaria de verificá-los, você pode consultar o links no final deste post. Alguns meses depois de publicar aquele projeto, comecei a trabalhar no Twitch como o principal Developer Advocate para Amazon Interactive Video Service (Amazon IVS) - uma solução totalmente gerenciada para criar soluções de transmissão de vídeo ao vivo e interativas (confira para saber mais). A próxima etapa do meu projeto "Brain to the Cloud" era óbvia - eu precisava . esta série transmitir meu cérebro ao vivo Transmitindo meu cérebro Antes de olharmos para o código, vamos ver o produto final. Há 2 visualizações para o aplicativo: uma visualização de transmissão e uma visualização de reprodução. Dentro a exibição de transmissão, podemos visualizar o vídeo ao vivo, iniciar o transmissão e conecte a faixa de cabeça Muse para transmitir os dados do cérebro obtido da faixa de cabeça. Na exibição de reprodução, exibimos o ao vivo transmitir com um elemento e mapear os dados do cérebro em tempo real <video> Visão Geral do Projeto Existem 5 passos para este projeto: Transmitir transmissão ao vivo Capturar dados cerebrais Publique dados cerebrais como metadados cronometrados na transmissão ao vivo Reproduzir transmissão ao vivo Ouça metadados cronometrados e renderize dados cerebrais em um gráfico em tempo real Se você preferir representações gráficas de tais coisas, veja como fica: Construindo o Projeto Eu usei o React para este projeto. Por quê? Bem, eu tenho muita experiência com Vue e Angular, mas provavelmente sou um dos últimos desenvolvedores earth para tentar React. Achei que era hora de descobrir o que tudo o hype era sobre, e eu sabia que isso não seria uma tarefa difícil projeto para construir com ele. Devido à minha falta de experiência anterior, não estou o que você chamaria de usuário "avançado" da estrutura, mas devo dizer que estou muito feliz com o que vejo até agora. achei o processo agradável e não me vi "brigando" com o framework. Mas esta postagem do blog não é sobre minha opinião sobre frameworks JavaScript, então vou guarde isso para um post futuro. Em vez disso, vamos falar sobre como eu transmito meu cérebro! O hardware No meu projeto original "Brain to the Cloud", usei um EEG "vintage" um fone de ouvido chamado MindFlex para capturar minhas leituras cerebrais. Funcionou bastante bem, mas exigiu que eu "hackeasse" o dispositivo adicionando um ESP-12 microcontrolador para extrair as leituras do dispositivo e enviar eles para a nuvem. Desta vez, procurei algo um pouco mais novo - e algo que eu poderia usar sem modificações. Depois de um pouco de pesquisa, optei pela Felizmente, existe uma biblioteca de código aberto realmente incrível chamada que me permite acessar as leituras do cérebro diretamente em um navegador da Web com Web Bluetooth (em navegadores compatíveis, é claro). bandana Muse S. muse-js A transmissão ao vivo Até recentemente, a transmissão ao vivo com IVS exigia que usássemos um cliente de terceiros para transmitir nossos fluxos como RTMPS. Mas nós recentemente lançou um divisor de águas: o . Como o nome indica, este SDK nos dá a capacidade de transmitir nosso transmissão ao vivo via WebRTC diretamente de um navegador da web. Claramente, este foi um ajuste perfeito para transmitir ao vivo meu cérebro, pois significa que posso criar uma solução "tudo-em-um" para transmitir meus dados cerebrais junto com meu transmissão ao vivo sem depender de software de terceiros ou scripts externos. o Amazon Amazon IVS Web Broadcast SDK Adicionando transmissão da Web ao aplicativo React Não vamos examinar cada etapa necessária para utilizar o Web Broadcast SDK nesta postagem. Em vez disso, veremos os destaques para ter uma ideia geral de como funciona. Não se preocupe - tenho outro post em breve, onde vamos nos aprofundar no processo "passo a passo" para usar o Web Broadcast SDK, portanto, fique atento a isso. Dito isso, vamos dar uma jornada rápida para ver como usei o SDK neste projeto. meu primeiro passo era usar uma transmissão na web para instalar o módulo. Usando sua ferramenta de gerenciamento de pacotes favorita, execute: amazon-ivs-web-broadcast $ npm install amazon-ivs-web-broadcast Em seguida, precisamos importá-lo para o nosso componente. No meu componente Broadcast.jsx, adicionei: import IVSBroadcastClient, { STANDARD_LANDSCAPE } from 'amazon-ivs-web-broadcast' ; Podemos criar uma instância do IVSBroadcastClient com a configuração de fluxo desejada e ingerir o endpoint de nosso canal Amazon IVS e configurá-lo no estado de nosso componente. }) }); this .setState({ broadcastClient : IVSBroadcastClient.create({ streamConfig : STANDARD_LANDSCAPE, ingestEndpoint : this .state.ingestEndpoint, Agora que temos uma instância do cliente, podemos adicionar nossa câmera ao cliente. Para isso 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 }); Adicionar o microfone do usuário ao cliente segue um padrão semelhante. }, }); const audioStream = await navigator.mediaDevices.getUserMedia({ audio : { deviceId : this .state.selectedAudioDeviceId this .state.broadcastClient.addAudioInputDevice(audioStream, 'mic1' ); devido ao modelo de segurança do navegador, precisamos obter permissões para acessar a câmera e o microfone do usuário. Consulte a para obter mais informações sobre isso e para ver como capturei uma lista de dispositivos e os apresentou em uma caixa de diálogo para permitir que o usuário escolha o dispositivo de transmissão se várias opções estiverem disponíveis. Observação: fonte do projeto no GitHub Agora podemos adicionar uma visualização ao vivo à página para que possamos ver o que nossos visualizadores verão no final das contas do jogador. <canvas ref={ this .previewRef} id= 'broadcast-preview' ></canvas> E anexe a visualização ao : broadcastClient this .state.broadcastClient.attachPreview( this .previewRef.current); Para iniciar a transmissão, adicione um botão à página e, no manipulador para a chamada do botão no (passando o necessário ). onClick startBroadcast() broadcastClient streamKey this .state.broadcastClient.startBroadcast( this .state.streamKey); Obtendo meus dados cerebrais Como mencionei acima, usei o biblioteca, que fornece a capacidade de conectar-se à faixa de cabeça e extrair os dados brutos. No entanto, não calcula as potências absolutas da banda para os dados EEG. Para isso, precisei buscar : . muse-js muse-js outra biblioteca eeg-pipes A primeira etapa é adicionar e importar as bibliotecas. $ npm install @neurosity/pipes $ npm install muse-js import { zipSamples, MuseClient } from 'muse-js' ; import { powerByBand, epoch, fft } from '@neurosity/pipes' ; Em seguida, adicionei um botão com um manipulador de cliques. No manipulador, eu conecte-se ao fone de ouvido, comece a ouvir os dados e assine o fluxo. zipSamples(client.eegReadings) .pipe( powerByBand(), ) .subscribe( } ); const client = new MuseClient(); await client.connect(); await client.start(); epoch({ duration : 1024 , interval : 250 , samplingRate : 256 }), fft({ bins : 256 }), ( 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 Publicando meus dados cerebrais como metadados cronometrados Agora que tenho um manipulador que coleta meus dados cerebrais do Muse headband, é hora de publicar esses dados como metadados cronometrados no live fluxo. A coisa incrível sobre é que ele está diretamente incorporado no fluxo de vídeo e permanece uma parte permanente desse fluxo. Isso significa que existe mesmo em versões gravadas, o que significa que, mesmo na reprodução sob demanda, podemos ouvir e responder aos eventos. timed metadata O Web Broadcast SDK não oferece suporte à publicação de metadados cronometrados do lado do cliente, portanto, teremos que usar ( ) por meio do . Para isso, criei uma função AWS Lambda. putMetadata docs AWS SDK para JavaScript }); }, }; } } } } }; } response.body = err.stack; } }; 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 ; callback( null , response); return ; Para publicar meus dados cerebrais como metadados cronometrados, criei um Amazon API Gateway para invocar a função e modificar o método acima para chamar a função AWS Lambda. subscribe() .pipe( powerByBand(), ) .subscribe( fetch(LAMBDA_URL, { }, }) }); } } ); zipSamples(client.eegReadings) epoch({ duration : 1024 , interval : 250 , samplingRate : 256 }), fft({ bins : 256 }), ( 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) { 'method' : 'POST' , 'mode' : 'no-cors' , 'headers' : { 'Content-Type' : 'application/json' , 'body' : JSON .stringify({ channelArn : this .state.channelArn, metadata : JSON .stringify(meta) Construindo a reprodução da transmissão ao vivo e mapeando meus dados cerebrais Depois que a transmissão ao vivo com exibição de transmissão de dados cerebrais foi concluída, foi tempo para criar uma experiência de reprodução que exibiria a transmissão ao vivo e mapeie os dados do cérebro em tempo real conforme eles chegam por meio de metadados cronometrados. Criando o reprodutor de transmissão ao vivo Podemos usar o IVS Web Player SDK via NPM, mas como ele usa WebAssembly, . Para evitar essa complicação, acho mais fácil usar o web player por meio de um tag e eu adicionei isso ao meu no meu aplicativo React. as coisas podem ficar complicadas <script> index.html <script src= "https://player.live-video.net/1.12.0/amazon-ivs-player.min.js" ></script> No meu componente, pego uma referência ao jogador e alguns elementos necessários. Playback.jsx const { IVSPlayer } = window ; const { create : createMediaPlayer, isPlayerSupported, PlayerEventType, PlayerState } = IVSPlayer; const { ENDED, PLAYING, READY, BUFFERING } = PlayerState; const { TEXT_METADATA_CUE, ERROR } = PlayerEventType; Para reprodução, usamos o nativo marcação. <video> <video ref={ this .videoRef} controls playsInline></video> E para inicializar o player e iniciar a reprodução: this .playerRef.current = createMediaPlayer(); this .playerRef.current.attachHTMLVideoElement( this .videoRef.current); this .playerRef.current.load(STREAM_URL); this .playerRef.current.play(); Ouvindo e respondendo a metadados cronometrados Agora que estamos reproduzindo a transmissão ao vivo, podemos ouvir e responder aos dados cerebrais recebidos. this .playerRef.current.addEventListener(TEXT_METADATA_CUE, this .onPlayerMetadata); Defina os dados do cérebro em nosso 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 E renderize-o com um gráfico de barras (com Chart.js): options={ { }, } } } /> <Bar data={ this .state.ch0} ref={ this .chartReferenceCh0} aspectRatio : 1 , title : { display : true , text : 'Channel: ' + channelNames[ 0 ] }, responsive : true , tooltips : { enabled : false legend : { display : false A visualização é legal e certamente fornece uma maneira divertida de ver meu dados cerebrais enquanto estou transmitindo um jogo ao vivo, mas não fornece uma tonelada de contexto. Achei que faria sentido incluir alguns cálculos para dar uma visão sobre o que os dados realmente significam. Para isso, encontrei alguns cálculos no que incluiu algumas fórmulas que podem ser usadas para calcular fatores como relaxamento (alfa dividido por delta) e concentração (beta dividido por teta). Outra uma maneira de derivar a fadiga ((teta + alfa) / beta). Envolvi esses cálculos em um componente útil e reutilizável. muse-lsl projeto no GitHub ótima postagem de blog que encontrei destacou </Col> </Row> <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 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 > Resumo Neste post, vimos como criei um aplicativo React para viver transmitir meus dados cerebrais com o Amazon IVS. Se você gostaria de saber mais sobre Amazon IVS, confira a série aqui no dev.to. Se você estiver interessado em experimentar o aplicativo ou apenas verificar o código-fonte completo do aplicativo, verifique-o no . Seus comentários, perguntas e feedback são sempre bem-vindos, então deixe um comentário aqui ou conecte-se comigo no Getting Started with Amazon Interactive Video Service GitHub Twitter links Brain to the Cloud - Parte I - Introdução do Projeto e Visão Geral da Arquitetura Cérebro para a nuvem - Parte II - Como carreguei meu cérebro para a nuvem Cérebro para a nuvem - Parte III - Examinando a relação entre a atividade cerebral e o desempenho do videogame Código fonte do projeto Publicado pela primeira vez . aqui