建立專案
建立專案。
| 12
 
 | npm create vite@latestcd webrtc-example
 
 | 
安裝 ESLint 套件。
| 1
 | npm i eslint eslint-config-airbnb -D
 | 
在專案根目錄新增 .eslintrc.cjs 檔:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | module.exports = {extends: 'airbnb',
 env: {
 browser: true,
 node: true,
 },
 rules: {
 'no-new': 'off',
 },
 };
 
 | 
實作
修改 main.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 
 | import './style.css';
 class Meeting {
 constructor() {
 this.streamButton = document.querySelector('#stream-button');
 this.videoButton = document.querySelector('#video-button');
 this.audioButton = document.querySelector('#audio-button');
 this.mainVideo = document.querySelector('#main-video');
 
 this.isVideoEnabled = true;
 this.isAudioEnabled = true;
 
 this.videoTracks = [];
 this.audioTracks = [];
 
 this.streamButton.addEventListener('click', this.toggleStream.bind(this));
 this.videoButton.addEventListener('click', this.toggleVideo.bind(this));
 this.audioButton.addEventListener('click', this.toggleAudio.bind(this));
 }
 
 async toggleStream() {
 let stream = this.mainVideo.srcObject;
 
 this.streamButton.textContent = stream ? '開始' : '結束';
 
 if (stream) {
 stream.getTracks().forEach((track) => track.stop());
 this.mainVideo.srcObject = null;
 return;
 }
 
 stream = await navigator.mediaDevices.getUserMedia({
 audio: true,
 video: { width: { ideal: 4096 }, height: { ideal: 2160 } },
 });
 
 this.videoTracks = stream.getVideoTracks();
 this.audioTracks = stream.getAudioTracks();
 
 this.videoTracks[0].enabled = this.isVideoEnabled;
 this.audioTracks[0].enabled = this.isAudioEnabled;
 
 this.mainVideo.srcObject = stream;
 }
 
 toggleVideo() {
 this.isVideoEnabled = !this.isVideoEnabled;
 this.videoButton.textContent = this.isVideoEnabled ? '關閉視訊' : '開啟視訊';
 
 if (this.videoTracks.length > 0) {
 this.videoTracks[0].enabled = this.isVideoEnabled;
 }
 }
 
 toggleAudio() {
 this.isAudioEnabled = !this.isAudioEnabled;
 this.audioButton.textContent = this.isAudioEnabled ? '關閉音訊' : '開啟音訊';
 
 if (this.audioTracks.length > 0) {
 this.audioTracks[0].enabled = this.isAudioEnabled;
 }
 }
 }
 
 new Meeting();
 
 | 
修改 index.html 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | <!doctype html><html lang="en">
 <head>
 <meta charset="UTF-8" />
 <link rel="icon" type="image/svg+xml" href="/vite.svg" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>Vite App</title>
 </head>
 <body>
 <div id="app">
 <button id="stream-button">開始</button>
 <button id="video-button">關閉視訊</button>
 <button id="audio-button">關閉音訊</button>
 <video id="main-video" width="100%" height="100%" autoplay playsinline></video>
 </div>
 <script type="module" src="/main.js"></script>
 </body>
 </html>
 
 | 
修改 style.css 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | :root {background-color: #242424;
 }
 
 body {
 margin: 0;
 }
 
 #video {
 transform: scaleX(-1);
 }
 
 | 
程式碼
參考資料