今年の初め、私は「ブレイン」と名付けたとても楽しいプロジェクトを作成しました。 to the Cloud」でプレイ中に脳内データをクラウドに保存しました Call of Duty の関係を分析できるように 認知機能とビデオゲームのパフォーマンス。三部構成で書きました ブログ投稿シリーズといくつかの楽しいビデオを作成して、私の調査結果を要約します そのプロジェクト。これらを確認したい場合は、 この投稿の下部にあるリンク。それを公開してから数ヶ月後 プロジェクトの開始後、私は Twitch でリード デベロッパー アドボケイトとして働き始めました。 Amazon Interactive Video Service (Amazon IVS) - フルマネージド ソリューション ライブのインタラクティブなビデオ ストリーミング ソリューションを作成するためのものです (詳細については、 をご覧ください)。 「Brain to the Cloud」プロジェクトの次のステップは明らかでした。自分の脳を 必要があったのです。 このシリーズ ライブ ストリーミングする 私の脳を放送する コードを見る前に、最終製品を見てみましょう。 2つあります アプリケーションのビュー: ブロードキャスト ビューと再生ビュー。の ブロードキャスト ビューでは、ライブ ビデオをプレビューして、 ブロードキャストし、Muse ヘッドバンドを接続して脳データをストリーミングします ヘッドバンドから入手。再生ビューでは、ライブを表示します ストリーム 要素、脳データをリアルタイムでグラフ化 <video> プロジェクト概要 このプロジェクトには 5 つのステップがあります。 ライブ ストリームをブロードキャストする 脳のデータをキャプチャ ライブ ストリーム内で脳データを時限メタデータとして公開する ライブ ストリームの再生 時間指定されたメタデータをリッスンし、リアルタイムでグラフに脳データをレンダリングします このようなものをグラフィカルに描写したい場合は、次のようになります。 プロジェクトのビルド このプロジェクトには React を使用しました。なんで?まあ、経験は豊富だけど Vue と Angular を使用していますが、私はおそらく最後の開発者の 1 人です。 React を試す地球。そろそろすべてを理解する時が来たと思いました 誇大宣伝があり、これが難しいことではないことはわかっていました それを使って構築するプロジェクト。経験がないので、私はそうではありません。 フレームワークの「上級」ユーザーと呼ばれるものですが、私は言わなければなりません 私はこれまでに見たものにとても満足しています。プロセスを見つけた 楽しく、フレームワークと「戦っている」とは思いませんでした。しかし このブログ投稿は、JavaScript フレームワークに関する私の意見ではありません。 将来の投稿のためにそれを保存します。代わりに、私がどのように放送するかについて話しましょう 私の脳! ハードウェア オリジナルの「Brain to the Cloud」プロジェクトでは、「ヴィンテージ」の EEG を使用しました 私の脳の測定値をキャプチャするための MindFlex と呼ばれるヘッドセット。割と効きました まあ、ESP-12を追加してデバイスを「ハック」する必要がありました デバイスから読み取り値を引き出して送信するためのマイクロコントローラ それらをクラウドに。今回は少し新しいものに手を伸ばしました - 変更なしで使用できるもの。少ししてから 調査の結果、 に落ち着きました。ありがたいことに、 と呼ばれる非常に優れたオープンソース ライブラリがあり、これを使用すると、Web Bluetooth を使用して Web ブラウザーで直接脳の測定値にアクセスできます (もちろん、サポートされているブラウザーで)。 Muse S ヘッドバンド muse-js ライブ ストリーム ブロードキャスト 最近まで、 IVS を使用したライブ ストリーミングでは、 RTMPS としてストリームをブロードキャストするためのサードパーティ クライアント。しかし、私たちは最近 はゲームチェンジャーを立ち上げました: 。 名前が示すように、この SDK を使用すると、 Webブラウザから直接WebRTC経由でライブストリーミング。明らかに、これは 自分の脳をライブ ストリーミングするのにぴったりです。 私の脳のデータと一緒にブロードキャストするための「オールインワン」ソリューション サードパーティのソフトウェアや外部スクリプトに依存しないライブ ストリーム。 Amazon Amazon IVS Web Broadcast SDK React アプリに Web ブロードキャストを追加する を利用するために必要なすべてのステップを検討するつもりはありません。 この投稿の Web ブロードキャスト SDK。代わりに、ハイライトを見て、 それがどのように機能するかについての一般的な考えを得る。心配しないでください - 別の投稿があります を使用するための「段階的な」プロセスについて詳しく説明します。 Web ブロードキャスト SDK ですので、ご期待ください。そうは言っても、取りましょう このプロジェクトで SDK をどのように使用したかを簡単に説明します。私の最初のステップ をインストールするために Web ブロードキャストを使用することでした。 モジュール。お気に入りのパッケージ管理ツールを使用して、次を実行します。 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); 私の脳のデータを取得する 上で述べたように、私は このライブラリは、ヘッドバンドに接続して生データを取得する機能を提供します。でも、 は、EEG データの絶対帯域パワーを計算しません。このために、 に手を伸ばす必要がありました。 . muse-js muse-js 別のライブラリ eeg-pipes 最初のステップは、ライブラリを追加してインポートすることです。 $ npm install @neurosity/pipes $ npm install muse-js import { zipSamples, MuseClient } from 'muse-js' ; import { powerByBand, epoch, fft } from '@neurosity/pipes' ; 次に、クリック ハンドラーを含むボタンを追加しました。ハンドラーで、私は ヘッドセットに接続し、データのリッスンを開始し、 ストリーム。 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 自分の脳データを Timed Metadata として公開する これで、Muse から脳のデータを収集するハンドラーができました ヘッドバンド、そのデータを時間指定されたメタデータとしてライブで公開する時が来ました ストリーム。 すごいところは ビデオ ストリームに直接埋め込まれ、そのストリームの永続的な部分として残ります。つまり、記録されたバージョンにも存在するということです。つまり、オンデマンドの再生でも、イベントをリッスンして応答することができます。 timed metadata Web Broadcast SDK は、クライアント側からの時限メタデータの公開をサポートしていないため、使用する必要があります ( ) 経由。このために、AWS Lambda 関数を作成しました。 putMetadata ドキュメント AWS SDK for 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 ; 脳のデータを時限メタデータとして公開するために、Amazon API Gateway を作成して関数を呼び出し、 上記のメソッドを使用して 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) ライブ ストリーム再生の構築と脳データのグラフ化 脳内データ放送ビューのライブストリームが完了すると、 ライブ ストリームを表示する再生エクスペリエンスを作成する時間 時限メタデータを介して脳のデータをリアルタイムでグラフ化します。 ライブ ストリーム プレーヤーの作成 NPM 経由で IVS Web Player SDK を使用できますが、WebAssembly を使用するため 。そのトリッキーさを避けるために、私は Web プレーヤーを タグと私はそれを私の 私のReactアプリで。 、扱いが難しくなる可能性があります <script> index.html <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 を使用) でレンダリングします。 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 ビジュアライゼーションはクールで、確かに私のものを見る楽しい方法を提供します ゲームのライブ ストリーミング中に脳のデータを取得しましたが、大量のデータは提供されません。 環境。だから私はいくつかの計算を含めることは理にかなっているだろうと考えました データが実際に何を意味するかについての洞察を提供します。そのために、見つけた でのいくつかの計算 これには、次のような要因を計算するために使用できるいくつかの式が含まれていました リラクゼーション(アルファをデルタで割る)、集中力(ベータを次で割る) シータ)。 。これらの計算を便利で再利用可能なコンポーネントにまとめました。 muse-lsl GitHub のプロジェクト 私が見つけた別の素晴らしいブログ投稿では、疲労 ((シータ + アルファ) / ベータ) を導き出す方法が強調されていました </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 > 概要 この投稿では、私がどのようにして React アプリケーションを作成したかを見ていきました。 Amazon IVS で脳のデータをストリーミングします。詳しく知りたい方は Amazon IVS については、こちらの dev.to で シリーズをご覧ください。アプリケーションを試してみたい、またはアプリケーションの完全なソースを確認したいだけの場合は、 で確認してください。コメント、質問、フィードバックはいつでも大歓迎です。ここにコメントを残すか、 で私に連絡してください。 Amazon Interactive Video Service の入門 GitHub Twitter リンク Brain to the Cloud - パート I - プロジェクトの紹介とアーキテクチャの概要 クラウドへの脳 - パート II - 脳をクラウドにアップロードする方法 Brain to the Cloud - パート III - 脳の活動とビデオ ゲームのパフォーマンスの関係を調べる プロジェクトのソース コード 初公開は 。 こちら