or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connection.mddata.mdindex.mdinfo.mdmedia.md

media.mddocs/

0

# Media Streams

1

2

Add, remove, and manage audio/video streams with support for track-level operations, dynamic stream modification, and advanced WebRTC transceiver management.

3

4

## Capabilities

5

6

### Stream Management

7

8

Add and remove complete MediaStreams from the peer connection.

9

10

```javascript { .api }

11

/**

12

* Add a MediaStream to the connection

13

* @param stream - MediaStream to add (from getUserMedia, etc.)

14

*/

15

peer.addStream(stream: MediaStream): void;

16

17

/**

18

* Remove a MediaStream from the connection

19

* @param stream - MediaStream to remove

20

*/

21

peer.removeStream(stream: MediaStream): void;

22

```

23

24

**Usage Examples:**

25

26

```javascript

27

const Peer = require('simple-peer');

28

29

// Get user media

30

navigator.mediaDevices.getUserMedia({

31

video: true,

32

audio: true

33

}).then(stream => {

34

// Create peer with initial stream

35

const peer = new Peer({

36

initiator: true,

37

stream: stream // Constructor option

38

});

39

40

// Or add stream after creation

41

const peer2 = new Peer();

42

peer2.addStream(stream);

43

44

// Remove stream later

45

setTimeout(() => {

46

peer.removeStream(stream);

47

}, 10000);

48

});

49

50

// Multiple streams

51

Promise.all([

52

navigator.mediaDevices.getUserMedia({ video: true }),

53

navigator.mediaDevices.getDisplayMedia({ video: true })

54

]).then(([cameraStream, screenStream]) => {

55

const peer = new Peer({

56

initiator: true,

57

streams: [cameraStream, screenStream] // Constructor option

58

});

59

60

// Or add individually

61

// peer.addStream(cameraStream);

62

// peer.addStream(screenStream);

63

});

64

```

65

66

### Track Management

67

68

Manage individual MediaStreamTracks for fine-grained control over media.

69

70

```javascript { .api }

71

/**

72

* Add a MediaStreamTrack to the connection

73

* @param track - MediaStreamTrack to add

74

* @param stream - MediaStream to attach the track to

75

*/

76

peer.addTrack(track: MediaStreamTrack, stream: MediaStream): void;

77

78

/**

79

* Remove a MediaStreamTrack from the connection

80

* @param track - MediaStreamTrack to remove

81

* @param stream - MediaStream the track was attached to

82

*/

83

peer.removeTrack(track: MediaStreamTrack, stream: MediaStream): void;

84

85

/**

86

* Replace a MediaStreamTrack with another track

87

* @param oldTrack - Track to replace

88

* @param newTrack - New track to use

89

* @param stream - MediaStream the old track was attached to

90

*/

91

peer.replaceTrack(oldTrack: MediaStreamTrack, newTrack: MediaStreamTrack, stream: MediaStream): void;

92

```

93

94

**Usage Examples:**

95

96

```javascript

97

navigator.mediaDevices.getUserMedia({

98

video: true,

99

audio: true

100

}).then(stream => {

101

const peer = new Peer({ initiator: true });

102

const videoTrack = stream.getVideoTracks()[0];

103

const audioTrack = stream.getAudioTracks()[0];

104

105

// Add individual tracks

106

peer.addTrack(videoTrack, stream);

107

peer.addTrack(audioTrack, stream);

108

109

// Replace video track (switch camera)

110

navigator.mediaDevices.getUserMedia({

111

video: { facingMode: 'environment' }

112

}).then(newStream => {

113

const newVideoTrack = newStream.getVideoTracks()[0];

114

peer.replaceTrack(videoTrack, newVideoTrack, stream);

115

});

116

117

// Remove audio track (mute)

118

peer.removeTrack(audioTrack, stream);

119

});

120

```

121

122

### Transceiver Management

123

124

Advanced WebRTC transceiver management for complex media scenarios.

125

126

```javascript { .api }

127

/**

128

* Add an RTCRtpTransceiver to the connection

129

* @param kind - Media kind (commonly 'audio' or 'video', but accepts any string)

130

* @param init - RTCRtpTransceiverInit options

131

*/

132

peer.addTransceiver(kind: string, init?: RTCRtpTransceiverInit): void;

133

134

interface RTCRtpTransceiverInit {

135

direction?: 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive';

136

streams?: MediaStream[];

137

sendEncodings?: RTCRtpEncodingParameters[];

138

}

139

```

140

141

**Usage Examples:**

142

143

```javascript

144

const peer = new Peer({ initiator: true });

145

146

// Add receive-only transceiver

147

peer.addTransceiver('video', {

148

direction: 'recvonly'

149

});

150

151

// Add transceiver with specific streams

152

navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {

153

peer.addTransceiver('audio', {

154

direction: 'sendrecv',

155

streams: [stream]

156

});

157

});

158

159

// Add transceiver with encoding parameters

160

peer.addTransceiver('video', {

161

direction: 'sendonly',

162

sendEncodings: [

163

{ rid: 'high', maxBitrate: 1000000 },

164

{ rid: 'low', maxBitrate: 200000, scaleResolutionDownBy: 2 }

165

]

166

});

167

```

168

169

### Media Events

170

171

Handle incoming media streams and tracks from the remote peer.

172

173

```javascript { .api }

174

// Receive complete MediaStream

175

peer.on('stream', (stream: MediaStream) => void);

176

177

// Receive individual MediaStreamTrack

178

peer.on('track', (track: MediaStreamTrack, stream: MediaStream) => void);

179

```

180

181

**Usage Examples:**

182

183

```javascript

184

const peer = new Peer();

185

186

// Handle incoming streams

187

peer.on('stream', stream => {

188

console.log('Received stream with', stream.getTracks().length, 'tracks');

189

190

// Display video stream

191

const video = document.querySelector('video');

192

if ('srcObject' in video) {

193

video.srcObject = stream;

194

} else {

195

video.src = URL.createObjectURL(stream); // Older browsers

196

}

197

video.play();

198

});

199

200

// Handle individual tracks

201

peer.on('track', (track, stream) => {

202

console.log('Received track:', track.kind, track.id);

203

204

if (track.kind === 'video') {

205

const video = document.createElement('video');

206

video.srcObject = new MediaStream([track]);

207

video.play();

208

document.body.appendChild(video);

209

} else if (track.kind === 'audio') {

210

const audio = document.createElement('audio');

211

audio.srcObject = new MediaStream([track]);

212

audio.play();

213

}

214

});

215

```

216

217

### Dynamic Media Control

218

219

Dynamically add, remove, and modify media streams during an active connection.

220

221

**Usage Examples:**

222

223

```javascript

224

const peer1 = new Peer({ initiator: true });

225

const peer2 = new Peer();

226

227

// Setup signaling

228

peer1.on('signal', data => peer2.signal(data));

229

peer2.on('signal', data => peer1.signal(data));

230

231

// Start without media

232

peer1.on('connect', () => {

233

console.log('Connected - adding media later');

234

});

235

236

// Add media after connection

237

function addCamera() {

238

navigator.mediaDevices.getUserMedia({

239

video: true,

240

audio: true

241

}).then(stream => {

242

peer1.addStream(stream);

243

return stream;

244

}).then(stream => {

245

// Store for later removal

246

window.currentStream = stream;

247

});

248

}

249

250

// Remove media

251

function removeCamera() {

252

if (window.currentStream) {

253

peer1.removeStream(window.currentStream);

254

window.currentStream.getTracks().forEach(track => track.stop());

255

window.currentStream = null;

256

}

257

}

258

259

// Switch camera

260

function switchCamera() {

261

if (window.currentStream) {

262

const videoTrack = window.currentStream.getVideoTracks()[0];

263

264

navigator.mediaDevices.getUserMedia({

265

video: { facingMode: 'environment' }

266

}).then(newStream => {

267

const newVideoTrack = newStream.getVideoTracks()[0];

268

peer1.replaceTrack(videoTrack, newVideoTrack, window.currentStream);

269

270

// Stop old track

271

videoTrack.stop();

272

273

// Update stream reference

274

window.currentStream.removeTrack(videoTrack);

275

window.currentStream.addTrack(newVideoTrack);

276

});

277

}

278

}

279

280

// Toggle audio

281

function toggleAudio(enabled) {

282

if (window.currentStream) {

283

const audioTrack = window.currentStream.getAudioTracks()[0];

284

if (audioTrack) {

285

audioTrack.enabled = enabled;

286

}

287

}

288

}

289

```

290

291

### Screen Sharing

292

293

Handle screen sharing streams with proper setup and cleanup.

294

295

**Usage Examples:**

296

297

```javascript

298

const peer = new Peer({ initiator: true });

299

300

async function startScreenShare() {

301

try {

302

// Get screen share stream

303

const screenStream = await navigator.mediaDevices.getDisplayMedia({

304

video: true,

305

audio: true

306

});

307

308

// Add to peer connection

309

peer.addStream(screenStream);

310

311

// Handle screen share ending

312

screenStream.getVideoTracks()[0].addEventListener('ended', () => {

313

console.log('Screen sharing ended');

314

peer.removeStream(screenStream);

315

316

// Optionally switch back to camera

317

return navigator.mediaDevices.getUserMedia({ video: true });

318

});

319

320

return screenStream;

321

} catch (err) {

322

console.error('Screen sharing failed:', err);

323

}

324

}

325

326

// Replace camera with screen share

327

async function switchToScreenShare() {

328

const cameraStream = window.currentCameraStream;

329

const screenStream = await startScreenShare();

330

331

if (cameraStream && screenStream) {

332

const cameraVideoTrack = cameraStream.getVideoTracks()[0];

333

const screenVideoTrack = screenStream.getVideoTracks()[0];

334

335

// Replace camera with screen

336

peer.replaceTrack(cameraVideoTrack, screenVideoTrack, cameraStream);

337

338

// Stop camera

339

cameraVideoTrack.stop();

340

}

341

}

342

```

343

344

### Error Handling

345

346

Handle media-related errors and track failures.

347

348

```javascript { .api }

349

// Media-specific error codes

350

interface MediaError extends Error {

351

code: 'ERR_ADD_TRANSCEIVER' | 'ERR_SENDER_REMOVED' | 'ERR_SENDER_ALREADY_ADDED' |

352

'ERR_TRACK_NOT_ADDED' | 'ERR_REMOVE_TRACK' | 'ERR_UNSUPPORTED_REPLACETRACK';

353

}

354

```

355

356

**Usage Examples:**

357

358

```javascript

359

const peer = new Peer({ initiator: true });

360

361

peer.on('error', err => {

362

switch (err.code) {

363

case 'ERR_ADD_TRANSCEIVER':

364

console.error('Failed to add transceiver:', err.message);

365

break;

366

case 'ERR_SENDER_REMOVED':

367

console.error('Track sender was removed:', err.message);

368

break;

369

case 'ERR_SENDER_ALREADY_ADDED':

370

console.error('Track already added to stream:', err.message);

371

break;

372

case 'ERR_TRACK_NOT_ADDED':

373

console.error('Cannot remove track - was never added:', err.message);

374

break;

375

case 'ERR_UNSUPPORTED_REPLACETRACK':

376

console.error('replaceTrack not supported in this browser');

377

break;

378

}

379

});

380

381

// Safe track operations

382

function safeAddTrack(peer, track, stream) {

383

try {

384

peer.addTrack(track, stream);

385

return true;

386

} catch (err) {

387

console.error('Failed to add track:', err.message);

388

return false;

389

}

390

}

391

392

function safeReplaceTrack(peer, oldTrack, newTrack, stream) {

393

try {

394

peer.replaceTrack(oldTrack, newTrack, stream);

395

return true;

396

} catch (err) {

397

console.error('Failed to replace track:', err.message);

398

// Fallback: remove old and add new

399

try {

400

peer.removeTrack(oldTrack, stream);

401

peer.addTrack(newTrack, stream);

402

return true;

403

} catch (fallbackErr) {

404

console.error('Fallback also failed:', fallbackErr.message);

405

return false;

406

}

407

}

408

}

409

```