- TOP
- ã¿ã°äžèЧ
- WebRTC
WebRTC
ã€ãã³ã
該åœããã³ã³ãã³ããèŠã€ãããŸããã§ãã
ãã¬ãžã³
該åœããã³ã³ãã³ããèŠã€ãããŸããã§ãã
æè¡ããã°
ã¯ããã« Nintendo Switch 2 ã®ã²ãŒã ãã£ãããšã¯ ã·ã¹ãã æ§æ WebRTC + SFU ã¢ãŒããã¯ã㣠ãã«ããªãŒãžã§ã³éçš ãªããã«ããªãŒãžã§ã³ãªã®ã éžæçãªãã«ããªãŒãžã§ã³èšèš IaCïŒTerraformïŒã«ããå¹ççãªã€ã³ãã©ç®¡ç DynamoDB ã§ã®éçºææ³ ã³ã¹ãå¹çãæèããããŒãã«èšèš ææ³ ãŸãšã ã¯ããã« ããã«ã¡ã¯ãæ°äººã®ããªã¿ã§ãã å
æ¥éå¬ããã AWS Summit Japan 2026 ã«åå ããŠããŸããã æ°ããã»ãã·ã§ã³ã®äžã§ç¹ã«æ°ã«ãªã£ãã®ãããã²ãŒã ãã£ãããæ¯ããæè¡ãã§ãã ã¿ã€ãã« ç§èªèº«ãåè·ã§ã¯ã²ãŒã æ¥çã«æºãã£ãŠããããšãâŠ
ã¯ããã« ãããã®ãã¬ããžç·šééšã®æ³æã§ãã ããæ¥ããããã¬ç·šééšã«èªè
ããã®ã䟿ããå±ããŸãããããã«ã¯ããé«éœ¢è
ã®å®¶æãåã©ããå«ãã¡ãšãããªã§äŒè©±ããä»çµã¿ãããããã€ã³ã¿ãŒãããã®ãµãŒãã䜿ã£ãŠäœããŸãããã㣠[…]
ã¯ããã« ååã®èšäº ã§ã¯ãWebã¢ããªã§æ åãæ±ãéã®ç£æ¥çšéã«ããããªã¢ã«ã¿ã€ã ã³ãã¥ãã±ãŒã·ã§ã³å®çŸã®ããã®æ€èšãã€ã³ããšãintdashãšintdash-RTC SDKãšããéžæè¢ã玹ä»ããŸããã èŠç¹ããããããããš: SFUéžå®æã¯ãã³ããŒåºæã®å®è£
ã«äŸåããç¹ãèæ
®ãå¿
èŠ ã»ã³ãµãŒããŒã¿ãšã®çµ±åãé²ç»ã»è§£æã¯è¿œå ã®èšèšãå¿
èŠã«ãªãå¯èœæ§ intdashã¯ãç£æ¥çšéã«é©ããããäžã€ã®éžæè¢ åç·šã§ã¯æŠèŠããè§Šããªãã£ããããå®éã®äœ¿çšæã«ã€ããŠèå³ããæã¡ããã ããæ¹ãããã£ããããšæããŸãã æ¬èšäºã§ã¯ãintdash-RTC SDKã®å
·äœçãªå®è£
æ¹æ³ããµã³ãã«ã³ãŒãä»ãã§è§£èª¬ããŸããç°å¢ãæºåã§ããŠããã°ãçŽ30åã§åäœãããããªãã£ããã宿ããŸãã®ã§ããã²ã詊ããã ããã ã©ã€ãã©ãªã®æŠèŠ intdashã¯æ åã»é³å£°ã»ã»ã³ãµãŒããŒã¿ãçµ±åããŠäŒéã§ãããã©ãããã©ãŒã ã§ããintdash-RTC SDKã¯ãintdashã§æ±ãããŒã¿ã®ãã¡æ åã»é³å£°ãWebã¢ããªããç°¡åã«æ±ããããã«ããã©ã€ãã©ãªã§ãã æ¬ã©ã€ãã©ãªã¯3ã€ã®ã€ã³ã¿ãŒãã§ãŒã¹ã§æ§æãããŠããŸãã âââââââââââââââââââââââââââââââââââââââââââââââ â MediaConnection â çµ±å管ç âââââââââââââââââââââââ¬âââââââââââââââââââââââ†â MediaSender â MediaReceiver â éåä¿¡ âââââââââââââââââââââââŽââââââââââââââââââââââââ | ^ v | âââââââââââââââââââââââââââââââââââââââââââââââ â intdash (iSCP) â äŒé âââââââââââââââââââââââââââââââââââââââââââââââ MediaConnection: éåä¿¡ãçµ±å管çã start() / stop() ã§æ¥ç¶å¶åŸ¡ MediaSender: ããŒã«ã«ã¡ãã£ã¢ãintdashã«éä¿¡ MediaReceiver: intdashããã¡ãã£ã¢ãåä¿¡ããvideoèŠçŽ ã«çŽæ¥æ¥ç¶ æ¬ã©ã€ãã©ãªã¯ãTypeScript åãã®intdashéä¿¡ã©ã€ãã©ãª iscp-ts ã®ã©ãããŒãšããŠãå©çšã§ããŸãããä»åã®ãããªã¢ããªã±ãŒã·ã§ã³ã§ã¯æ¥ç¶èšå®ãçŽæ¥æå®ããã·ã³ãã«ãªäœ¿ãæ¹ãå¯èœã§ãã å®è£
ã¹ããã 以äžã§ã¯ãåºæ¬çãªãããªãã£ãããå®è£
ãããµã³ãã«ã³ãŒãã5ã€ã®ã¹ãããã«åããŠç޹ä»ããŸããå
šéã¯èšäºæ«å°Ÿã®ãAppendix: ãµã³ãã«ã³ãŒãå
šæãã«åæ²ããŠããŸãã 1. ã©ã€ãã©ãªã®importãšMediaConnectionã®äœæ // 1. ã©ã€ãã©ãªã®import import { createMediaConnection } from "@aptpod/intdash-rtc" ; // 2. MediaConnectionã®äœæïŒintdashãžã®æ¥ç¶ãå
éšã§è¡ããŸãïŒ const { mediaConnection } = await createMediaConnection( { address : "your-intdash.example.jp" , // intdashæ¥ç¶ã¢ãã¬ã¹ projectUuid : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" , // intdashãããžã§ã¯ãã®UUID nodeId : "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" , // éä¿¡å
ïŒèªååŽïŒã®ããŒãUUID enableTLS : true , apiToken : "your_token_here" , // intdash Web ConsoleããäœæããAPIããŒã¯ã³ïŒOAuth2ãµã€ã³ã€ã³ã䜿ãå Žåã¯apiTokenãçç¥ïŒ } , { sender : { // é³å£°ã«é¢ããèšå® audio : { codec : "PCM" , // PCM, OPUS, AACããµããŒã } , // æ åã«é¢ããèšå® video : { codec : "H264" , // H264, VP9ããµããŒã } , } , receiver : { sourceNodeIds : [ "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz" ] , // éä¿¡çžæã®ããŒãUUID } , } , ); @aptpod/intdash-rtc ãä»åã®intdash-RTC SDKã§ãããããimportããã ãã§ãintdashãä»ãããããªãã£ãããå®è£
ã§ããŸãïŒ @aptpod/iscp-ts 㯠peer dependency ãšããŠäœµããŠã€ã³ã¹ããŒã«ãå¿
èŠã§ãïŒã createMediaConnection 颿°ã§ãintdashãžã®æ¥ç¶ãšMediaConnectionã®äœæããŸãšããŠè¡ããŸãã第1åŒæ°ã§æ¥ç¶æ
å ±ïŒã¢ãã¬ã¹ã»ãããžã§ã¯ãUUIDã»ããŒãUUIDã»APIããŒã¯ã³ïŒãã第2åŒæ°ã§éåä¿¡ãªãã·ã§ã³ãæå®ããŸãããããã®å€ã¯ intdash Web Console ããååŸã§ããŸããAPIããŒã¯ã³ã¯é·æéæå¹ãªåºå®ããŒã¯ã³ã§ãããããå®å
šãªã¯ã³ã¿ã€ã ããŒã¯ã³ãOAuth2ã«ããèªèšŒãå©çšå¯èœã§ããéåä¿¡ãªãã·ã§ã³ã¯éå±€åãããæ§é ã«ãªã£ãŠããã sender.audio ã§é³å£°èšå®ã sender.video ã§æ åèšå®ã receiver ã§å信察象ããŒããæå®ããŸããã³ãŒããã¯ã¯åå®å
šãªæååãªãã©ã«åã§æå®ã§ããèšå®ãã¹ãé²ããŸãã 2. ããŒã«ã«ã¡ãã£ã¢ã®ååŸãšè¡šç€º // 3. ããŒã«ã«ã¡ãã£ã¢ã¹ããªãŒã ã®ååŸãšèšå® const localStream = await navigator .mediaDevices. getUserMedia ( { video : true , audio : true , } ); await mediaConnection.sender.setLocalMediaStream(localStream); // ããŒã«ã«æ åãvideoèŠçŽ ã«è¡šç€º const localVideoEl = document . getElementById ( "local-video" ) as HTMLVideoElement ; localVideoEl.srcObject = new MediaStream (localStream.getVideoTracks()); localVideoEl.muted = true ; await localVideoEl.play(); getUserMedia ã§ã«ã¡ã©ãšãã€ã¯ããã¹ããªãŒã ãååŸãã setLocalMediaStream ã§èšå®ããŸããååŸããã¹ããªãŒã ã¯ãã®ãŸãŸããŒã«ã«ã®videoèŠçŽ ã«ã衚瀺ã§ããŸãã 3. åä¿¡ã¡ãã£ã¢ã®videoèŠçŽ ãžã®æ¥ç¶ // 4. åä¿¡ã¡ãã£ã¢ã¹ããªãŒã ã®åŠç const remoteVideoEl = document . getElementById ( "remote-video" , ) as HTMLVideoElement ; mediaConnection.receiver.on( "statechange" , ( state ) => { if (state === "running" ) { // åä¿¡ãéå§ãããããvideoèŠçŽ ã«çŽæ¥æ¥ç¶ mediaConnection.receiver.attach(remoteVideoEl); } else if (state === "stopped" || state === "failed" ) { // åä¿¡ã忢ããããvideoèŠçŽ ããåæ mediaConnection.receiver.detach(remoteVideoEl); } } ); åä¿¡åŽã®ç¶æ
å€å㯠statechange ã€ãã³ãã§ç£èŠããŸãã running ã«ãªã£ãã attach() ã§videoèŠçŽ ã«çŽæ¥æ¥ç¶ã§ããŸããå
éšã®å€æåŠçïŒãã³ãŒãçïŒã¯intdash-RTC SDKãåŠçãããããæèããå¿
èŠããããŸããã 4. æ¥ç¶éå§ // 5. æ¥ç¶éå§ïŒrunningç¶æ
ãŸã§åŸ
æ©ïŒ await mediaConnection.start( { waitUntil : "running" } ); console . log ( "æ¥ç¶ã確ç«ããŸãã" ); start({ waitUntil: 'running' }) ã§æ¥ç¶ãéå§ãã running ç¶æ
ã«ãªããŸã§åŸ
æ©ããŸããããã«ãããæ¥ç¶ãå®å
šã«ç¢ºç«ããŠããæ¬¡ã®åŠçã«é²ããŸãã 5. UIæäœãšåæ¢åŠç // 6. UIæäœïŒæ åã»é³å£°ã®æå¹/ç¡å¹åãæ¿ãïŒ document . getElementById ( "toggle-video" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setVideoEnabled( !mediaConnection.sender.videoEnabled, ); console .log( `æ å: ${ enabled ? "æå¹" : "ç¡å¹" } ` ); } ); document . getElementById ( "toggle-audio" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setAudioEnabled( !mediaConnection.sender.audioEnabled, ); console .log( `é³å£°: ${ enabled ? "æå¹" : "ç¡å¹" } ` ); } ); // 7. 忢åŠçïŒã¯ãªãŒã³ã¢ããïŒ document . getElementById ( "stop" )?. addEventListener ( "click" , async () => { await mediaConnection. stop (); await mediaConnection.iscpConn. close (); localStream.getTracks(). forEach (( track ) => track. stop ()); console .log( "æ¥ç¶ãçµäºããŸãã" ); } ); setVideoEnabled / setAudioEnabled ã§æ åã»é³å£°ãåå¥ã«å¶åŸ¡ã§ããŸããçµäºæã¯ stop() ã§ã¡ãã£ã¢åŠçã忢ãã iscpConn.close() ã§intdashæ¥ç¶ãã¯ããŒãºããŸããå
éšã®ã¯ãŒã¯ã¬ããããããã¡ãèªåçã«ã¯ãªãŒã³ã¢ãããããŸãã å®éã®åäœã®ç¢ºèª ãã®ããã«ãWebRTCãšéè²ãªãç°¡æœãã§ãintdashã䜿ã£ãæ åã»é³å£°éä¿¡ãå®è£
ã§ããŸãã å®éã«ãµã³ãã«ã¢ããªãåäœãããæ§åã以äžã®åç»ã§ãã youtu.be ç»é¢ã®å·ŠåŽããµã³ãã«ã¢ããªãEasy Video Chatããå³åŽãintdashã«ä»å±ããç°¡æå¯èŠåããŒã«ãEdge Finderãã§ãã ãµã³ãã«ã¢ããªãEasy Video Chatãã«ã¯ãããªããïŒå·ŠïŒãšãçžæãïŒå³ïŒã®2ã€ã®æ å衚瀺ããããŸããä»åã®ãã¢ã§ã¯éä¿¡å
ãšåä¿¡å
ã®ããŒããåäžã«èšå®ããŠãããããå·Šå³ã«åãæ åã衚瀺ãããŠããŸããå·Šã®ãããªãã㯠getUserMedia ã§ååŸããããŒã«ã«æ åããã®ãŸãŸè¡šç€ºãããã®ãå³ã®ãçžæãã¯ãã®ããŒã«ã«ã¡ãã£ã¢ãintdashãžéä¿¡ããããšå床åä¿¡ããŠãã³ãŒãã»è¡šç€ºãããã®ã§ãã å®éã«äºè
éã§é話ããå Žåã¯ãçžæåŽã§ãåæ§ã«intdashãžã®æ¥ç¶ãšåä¿¡å
ããŒãã®æå®ãè¡ãããšã§ãåæ¹åã§ã®æ åã»é³å£°é話ãæç«ããŸãã åæã«Edge FinderåŽã§ã¯ãéä¿¡ãããH.264æ åãã¬ãŒã ãšPCMé³å£°ããŒã¿ããããããæç³»åã®ããŒã¿ãã€ã³ããšããŠintdashã«èšé²ãããŠããæ§åã確èªã§ããŸãã ãããªãæ¡åŒµæ§ ããŒã¿ã®å¯èŠåãšããã·ã¥ããŒãã®ã«ã¹ã¿ãã€ãº åç»ã§ç޹ä»ãããEdge Finderãã¯intdashã«æšæºã§ä»å±ããŠãããéåä¿¡ãããŠããããŒã¿ãããã«ç¢ºèªã§ããç°¡æããŒã«ã§ãã ããé«åºŠãªå¯èŠåãããã·ã¥ããŒãã®ã«ã¹ã¿ãã€ãºãå¿
èŠãªå Žåã¯ãåŒç€Ÿã®å¯èŠåã¢ããªã±ãŒã·ã§ã³ãVM2M Data Visualizerãããå©çšããã ããŸããããŒã³ãŒãã§æç³»åããŒã¿ã®ããã·ã¥ããŒããæ§ç¯ã§ããæ åãšã»ã³ãµãŒããŒã¿ãæå»åæãããåçããå€åœ©ãªãŠã£ãžã§ãããçµã¿åãããè§£æç»é¢ã®äœæã«å¯Ÿå¿ããŠããŸãã VM2M Data Visualizer: è€æ°ã®æ åãšæç³»åããŒã¿ãæå»åæããŠåçããã¿ã€ã ã©ã€ã³ãã¥ãŒ VM2M Data Visualizer: ã²ãŒãžã»ã°ã©ãã»ã¬ãŒããŒãã£ãŒããªã©å€åœ©ãªãŠã£ãžã§ãããçµã¿åãããã«ã¹ã¿ã ããã·ã¥ããŒã Appendix: ãµã³ãã«ã³ãŒãå
šæ ãããŸã§ã¹ãããããšã«åå²ããŠç޹ä»ããŠãããµã³ãã«ã³ãŒãã®å
šéãã以äžã«åæ²ããŸãã // 1. ã©ã€ãã©ãªã®import import { createMediaConnection } from "@aptpod/intdash-rtc" ; // 2. MediaConnectionã®äœæïŒintdashãžã®æ¥ç¶ãå
éšã§è¡ããŸãïŒ const { mediaConnection } = await createMediaConnection( { address : "your-intdash.example.jp" , // intdashæ¥ç¶ã¢ãã¬ã¹ projectUuid : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" , // intdashãããžã§ã¯ãã®UUID nodeId : "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" , // éä¿¡å
ïŒèªååŽïŒã®ããŒãUUID enableTLS : true , apiToken : "your_token_here" , // intdash Web ConsoleããäœæããAPIããŒã¯ã³ïŒOAuth2ãµã€ã³ã€ã³ã䜿ãå Žåã¯apiTokenãçç¥ïŒ } , { sender : { // é³å£°ã«é¢ããèšå® audio : { codec : "PCM" , // PCM, OPUS, AACããµããŒã } , // æ åã«é¢ããèšå® video : { codec : "H264" , // H264, VP9ããµããŒã } , } , receiver : { sourceNodeIds : [ "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz" ] , // éä¿¡çžæã®ããŒãUUID } , } , ); // 3. ããŒã«ã«ã¡ãã£ã¢ã¹ããªãŒã ã®ååŸãšèšå® const localStream = await navigator .mediaDevices. getUserMedia ( { video : true , audio : true , } ); await mediaConnection.sender.setLocalMediaStream(localStream); // ããŒã«ã«æ åãvideoèŠçŽ ã«è¡šç€º const localVideoEl = document . getElementById ( "local-video" ) as HTMLVideoElement ; localVideoEl.srcObject = new MediaStream (localStream.getVideoTracks()); localVideoEl.muted = true ; await localVideoEl.play(); // 4. åä¿¡ã¡ãã£ã¢ã¹ããªãŒã ã®åŠç const remoteVideoEl = document . getElementById ( "remote-video" , ) as HTMLVideoElement ; mediaConnection.receiver.on( "statechange" , ( state ) => { if (state === "running" ) { // åä¿¡ãéå§ãããããvideoèŠçŽ ã«çŽæ¥æ¥ç¶ mediaConnection.receiver.attach(remoteVideoEl); } else if (state === "stopped" || state === "failed" ) { // åä¿¡ã忢ããããvideoèŠçŽ ããåæ mediaConnection.receiver.detach(remoteVideoEl); } } ); // 5. æ¥ç¶éå§ïŒrunningç¶æ
ãŸã§åŸ
æ©ïŒ await mediaConnection.start( { waitUntil : "running" } ); console . log ( "æ¥ç¶ã確ç«ããŸãã" ); // 6. UIæäœïŒæ åã»é³å£°ã®æå¹/ç¡å¹åãæ¿ãïŒ document . getElementById ( "toggle-video" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setVideoEnabled( !mediaConnection.sender.videoEnabled, ); console .log( `æ å: ${ enabled ? "æå¹" : "ç¡å¹" } ` ); } ); document . getElementById ( "toggle-audio" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setAudioEnabled( !mediaConnection.sender.audioEnabled, ); console .log( `é³å£°: ${ enabled ? "æå¹" : "ç¡å¹" } ` ); } ); // 7. 忢åŠçïŒã¯ãªãŒã³ã¢ããïŒ document . getElementById ( "stop" )?. addEventListener ( "click" , async () => { await mediaConnection. stop (); await mediaConnection.iscpConn. close (); localStream.getTracks(). forEach (( track ) => track. stop ()); console .log( "æ¥ç¶ãçµäºããŸãã" ); } ); ãããã« æ¬èšäºã§ã¯ãintdash-RTC SDKã䜿ã£ããããªãã£ããã®å®è£
æ¹æ³ãèŠãŠããŸããã ãã€ã³ãã®ãŸãšã: WebRTCãšåçã®ç°¡æœãã§ãintdashçµç±ã®ãããªãã£ãããå®è£
å¯èœ æåã¯ãããªãã£ããããå§ããŠãå°æ¥ã¯ã»ã³ãµãŒããŒã¿ãå«ããã«ãã¢ãŒãã«ã·ã¹ãã ãžæ¡åŒµã§ããã®ãintdashã®åŒ·ã¿ã§ããåããã©ãããã©ãŒã ãåãSDKã§å¯Ÿå¿ã§ãããããæè¡éžå®ã§åŸæãããªã¹ã¯ãæžãããŸãã ã詊ããŠã¿ããããããå°ã詳ããç¥ãããããšããæ¹ã¯ããã²ãæ°è»œã« ãåãåãã ãã ãããæ¬ã©ã€ãã©ãªã¯çŸåšãåãåããããŒã¹ã§ã®å奿äŸãšãªã£ãŠããŸãã
åç»
該åœããã³ã³ãã³ããèŠã€ãããŸããã§ãã
æžç±
該åœããã³ã³ãã³ããèŠã€ãããŸããã§ãã







