paint-brush
我如何使用 Amazon IVS、Muse 头带和 React 直播我的大脑经过@amazonivs
4,596 讀數
4,596 讀數

我如何使用 Amazon IVS、Muse 头带和 React 直播我的大脑

太長; 讀書

这是我们第一次使用 React 直播我们的大脑数据。我们使用 Amazon IVS Web Broadcast SDK 将我们的实时大脑数据广播到云端。在这篇文章中,我们不会查看使用 SDK 的每一步。相反,我们将查看要点以大致了解其工作原理。第一步是安装am-ivcast模块运行到我们的广播工具中:在broadcast-broadcast模块中,我们需要将其导入到我们喜欢的包中: 在广播工具中,我们还有一步来获得进入项目。
featured image - 我如何使用 Amazon IVS、Muse 头带和 React 直播我的大脑
Amazon Interactive Video Service (IVS)  HackerNoon profile picture
0-item

今年早些时候,我创建了一个非常有趣的项目,我称之为“大脑
到云端”,我边玩边将我的大脑数据保存到云端
使命召唤,以便我可以分析我之间的关系
认知功能和视频游戏性能。我写了一个三部分
博客文章系列并制作了一些有趣的视频来总结我的发现
那个项目。如果你想检查这些,你可以参考
这篇文章底部的链接。在我发表这篇文章几个月后
项目,我开始在 Twitch 工作,担任
Amazon Interactive Video Service (Amazon IVS) - 一个完全托管的解决方案
用于创建实时交互式视频流解决方案(查看本系列以了解更多信息)。我的“大脑到云端”项目的下一步很明显——我需要直播我的大脑。

广播我的大脑

在查看代码之前,让我们先看看最终产品。有2个
应用程序的视图:广播视图和回放视图。在
广播视图,我们可以预览直播视频,启动
广播,并连接 Muse 头带以传输大脑数据
从头带获得。在播放视图中,我们显示实时
流与

<video>
元素,并实时绘制大脑数据图表

项目概况

这个项目有5个步骤:

  1. 广播直播
  2. 捕获大脑数据
  3. 在直播中将大脑数据作为定时元数据发布
  4. 回放直播
  5. 监听定时元数据并实时在图表中呈现大脑数据

如果您更喜欢此类事物的图形描述,则如下所示:

构建项目

我在这个项目中使用了 React。为什么?还好我经验丰富
使用 Vue 和 Angular,但我可能是最后一批开发者之一
earth 尝试 React。我想是时候弄清楚一切了
炒作是关于,我知道这不会是一个困难
用它构建的项目。由于我之前缺乏经验,我不是
你称之为框架的“高级”用户,但我不得不说
我对目前所看到的很满意。我找到了过程
愉快并且没有发现自己与框架“战斗”。但
这篇博文不是关于我对 JavaScript 框架的看法,所以我会
将其保存在以后的帖子中。相反,让我们谈谈我如何广播
我的脑子!

硬件

在我最初的“大脑到云端”项目中,我使用了“老式”脑电图
称为 MindFlex 的耳机可以捕捉我的大脑读数。它工作得很好
很好,但需要我通过添加 ESP-12 来“破解”设备
微控制器,以便从设备中提取读数并发送
他们到云端。这次我接触到了一些更新的东西——
以及我无需修改即可使用的东西。过了一会儿
研究后,我选择了Muse S 头带。值得庆幸的是,有一个非常棒的开源库,叫做muse-js ,它让我可以直接在带有网络蓝牙的网络浏览器中访问大脑读数(当然,在支持的浏览器中)。

现场直播

直到最近,使用Amazon IVS 进行直播还需要我们使用
第三方客户端将我们的流广播为 RTMPS。但是我们最近
推出了改变游戏规则的产品: Amazon IVS Web Broadcast SDK
顾名思义,这个 SDK 使我们能够广播我们的
直接从网络浏览器通过 WebRTC 直播。显然,这是一个
非常适合直播我的大脑,因为这意味着我可以创造
一种“一体式”解决方案,用于将我的大脑数据与我的大脑一起广播
无需依赖第三方软件或外部脚本即可进行直播。

将网络广播添加到 React 应用程序

我们不会查看使用
这篇文章中的 Web Broadcast SDK。相反,我们将着眼于亮点
大致了解它是如何工作的。别担心 - 我有另一篇文章
即将推出,我们将深入研究使用的“逐步”过程
Web Broadcast SDK,敬请期待。也就是说,让我们采取一个
快速了解我如何在此项目中使用 SDK。我的第一步
是使用网络广播来安装

amazon-ivs-web-broadcast
模块。使用您最喜欢的包管理工具,运行:

 $ npm install amazon-ivs-web-broadcast

接下来,我们需要将它导入到我们的组件中。在我的 Broadcast.jsx 组件中,我添加了:

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

我们可以使用所需的流配置创建 IVSBroadcastClient 的实例,并从我们的 Amazon IVS 通道获取端点并将其设置为我们组件的状态。

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

现在我们已经有了客户端实例,我们可以将相机添加到客户端。为此我们使用

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 });

将用户的麦克风添加到客户端遵循类似的模式。

 const audioStream = await navigator.mediaDevices.getUserMedia({    audio : {        deviceId : this .state.selectedAudioDeviceId }, }); this .state.broadcastClient.addAudioInputDevice(audioStream, 'mic1' );
注意:由于浏览器安全模型,我们需要获得访问用户摄像头和麦克风的权限。有关这方面的更多信息,请参阅GitHub 上的项目源代码,并查看我如何捕获列表
设备并在对话框中显示它们以允许用户选择
如果有多个选项可用,则广播设备。

现在我们可以在页面上添加实时预览,这样我们就可以看到我们的观众最终会在玩家端看到什么。

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

并将预览附加到

broadcastClient
:

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

要开始广播,请在页面中添加一个按钮,并在

onClick
按钮调用的处理程序
startBroadcast()
broadcastClient
(通过必要的
streamKey
).

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

获取我的大脑数据

正如我上面提到的,我使用了

muse-js
库,它提供了连接头带和提取原始数据的能力。然而,
 muse-js
不计算 EEG 数据的绝对波段功率。为此,我需要找到另一个图书馆
 eeg-pipes
.

第一步是添加和导入库。

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

接下来,我添加了一个带有点击处理程序的按钮。在处理程序中,我
连接耳机,开始监听数据,订阅
溪流。

 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
 } );

将我的大脑数据发布为定时元数据

现在我有了一个处理程序,可以从 Muse 收集我的大脑数据
头带,是时候将该数据作为实时元数据发布
溪流。

令人敬畏的事情
timed metadata
是它直接嵌入到视频流中,并且始终是该流的永久部分。这意味着它甚至存在于录制版本中,这意味着即使在点播播放中我们也可以侦听和响应事件。

Web Broadcast SDK 不支持从客户端发布定时元数据,所以我们必须使用

putMetadata
( docs ) 通过适用于 JavaScript 的 AWS 开发工具包。为此,我创建了一个 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 ; } };

为了将我的大脑数据发布为定时元数据,我创建了一个 Amazon API Gateway 来调用函数并修改

subscribe()
上面的方法来调用 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) }) }); } } );

构建实时流播放并绘制我的大脑数据图表

大脑数据广播视图的直播完成后,
是时候创建显示直播流的播放体验了
并通过定时元数据实时绘制大脑数据图表。

创建直播流媒体播放器

我们可以通过 NPM 使用 IVS Web Player SDK,但由于它使用 WebAssembly, 所以事情会变得棘手。为了避免这种麻烦,我发现通过

<script>
标签,我将其添加到我的
index.html
在我的 React 应用程序中。

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

在我的

Playback.jsx
组件,我获取了对播放器的引用和一些必要的元素。

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

对于回放,我们使用原生

<video>
标签。

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

并初始化播放器并开始播放:

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

监听和响应定时元数据

现在我们正在播放直播,我们可以收听传入的大脑数据并做出响应。

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

将大脑数据设置为我们的组件状态:

 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 }); }); };

并使用条形图(使用 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 
 } } } />

可视化很酷,当然提供了一种有趣的方式来查看我的
我在直播游戏时的大脑数据,但没有提供大量
语境。所以我认为包括一些计算是有意义的
深入了解数据的实际含义。为此,我发现
中的一些计算

muse-lsl
GitHub 上的项目
其中包括一些可用于计算因素的公式
放松(alpha 除以 delta)和专注(beta 除以
θ)。我发现的另一篇很棒的博客文章强调了一种推导疲劳的方法 ((theta + alpha) / beta)。我将这些计算封装在一个方便、可重复使用的组件中。

 <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>

概括

在这篇文章中,我们了解了我是如何创建一个 React 应用程序来运行的
使用 Amazon IVS 流式传输我的大脑数据。如果您想了解更多
Amazon IVS,请在 dev.to 上查看Amazon Interactive Video Service 入门系列。如果您有兴趣试用该应用程序或只是查看该应用程序的完整源代码,请在GitHub上查看。随时欢迎您提出意见、问题和反馈,请在此处发表评论或在Twitter上与我联系

链接