@gjsify/webrtc 0.4.0 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +73 -70
- package/src/get-user-media.ts +0 -131
- package/src/gst-enum-maps.ts +0 -125
- package/src/gst-init.ts +0 -49
- package/src/gst-stats-parser.ts +0 -137
- package/src/gst-utils.ts +0 -41
- package/src/index.ts +0 -104
- package/src/internal/gst-types.ts +0 -122
- package/src/media-device-info.ts +0 -33
- package/src/media-devices.ts +0 -191
- package/src/media-stream-track.ts +0 -159
- package/src/media-stream.ts +0 -96
- package/src/register/data-channel.ts +0 -11
- package/src/register/error.ts +0 -11
- package/src/register/media-devices.ts +0 -10
- package/src/register/media.ts +0 -15
- package/src/register/peer-connection.ts +0 -20
- package/src/register.spec.ts +0 -55
- package/src/register.ts +0 -10
- package/src/rtc-certificate.ts +0 -110
- package/src/rtc-data-channel.ts +0 -283
- package/src/rtc-dtls-transport.ts +0 -48
- package/src/rtc-dtmf-sender.ts +0 -146
- package/src/rtc-error.ts +0 -49
- package/src/rtc-events.ts +0 -64
- package/src/rtc-ice-candidate.ts +0 -115
- package/src/rtc-ice-transport.ts +0 -104
- package/src/rtc-peer-connection.ts +0 -1039
- package/src/rtc-rtp-receiver.ts +0 -122
- package/src/rtc-rtp-sender.ts +0 -471
- package/src/rtc-rtp-transceiver.ts +0 -131
- package/src/rtc-sctp-transport.ts +0 -48
- package/src/rtc-session-description.ts +0 -64
- package/src/rtc-stats-report.ts +0 -39
- package/src/rtc-track-event.ts +0 -45
- package/src/rtp-capabilities.ts +0 -48
- package/src/tee-multiplexer.ts +0 -75
- package/src/test.mts +0 -11
- package/src/webrtc.spec.ts +0 -1186
- package/src/wpt-helpers.ts +0 -156
- package/src/wpt-media.spec.ts +0 -1154
- package/src/wpt.spec.ts +0 -1136
- package/tsconfig.json +0 -36
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
// W3C RTCRtpTransceiver for GJS.
|
|
2
|
-
//
|
|
3
|
-
// Wraps GstWebRTC.WebRTCRTPTransceiver. Reads mid, direction, currentDirection
|
|
4
|
-
// from the native object. direction setter maps back to GStreamer enum.
|
|
5
|
-
//
|
|
6
|
-
// Reference: refs/node-gst-webrtc/src/webrtc/RTCRtpTransceiver.ts (ISC)
|
|
7
|
-
// Reference: W3C WebRTC spec § 5.4
|
|
8
|
-
|
|
9
|
-
import type GstWebRTC from 'gi://GstWebRTC?version=1.0';
|
|
10
|
-
|
|
11
|
-
import { gstDirectionToW3C, w3cDirectionToGst } from './gst-enum-maps.js';
|
|
12
|
-
import { RTCRtpSender, type RTCRtpTransceiverDirection, type RTCRtpCodecCapability } from './rtc-rtp-sender.js';
|
|
13
|
-
import { RTCRtpReceiver } from './rtc-rtp-receiver.js';
|
|
14
|
-
|
|
15
|
-
export class RTCRtpTransceiver {
|
|
16
|
-
private _gstTrans: GstWebRTC.WebRTCRTPTransceiver;
|
|
17
|
-
readonly sender: RTCRtpSender;
|
|
18
|
-
readonly receiver: RTCRtpReceiver;
|
|
19
|
-
private _stopped = false;
|
|
20
|
-
private _codecPreferences: RTCRtpCodecCapability[] = [];
|
|
21
|
-
|
|
22
|
-
constructor(
|
|
23
|
-
gstTrans: GstWebRTC.WebRTCRTPTransceiver,
|
|
24
|
-
sender: RTCRtpSender,
|
|
25
|
-
receiver: RTCRtpReceiver,
|
|
26
|
-
) {
|
|
27
|
-
this._gstTrans = gstTrans;
|
|
28
|
-
this.sender = sender;
|
|
29
|
-
this.receiver = receiver;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get mid(): string | null {
|
|
33
|
-
if (this._stopped) return null;
|
|
34
|
-
const m = this._gstTrans.mid;
|
|
35
|
-
return (m === '' || m == null) ? null : String(m);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get direction(): RTCRtpTransceiverDirection {
|
|
39
|
-
if (this._stopped) return 'stopped';
|
|
40
|
-
return gstDirectionToW3C(this._gstTrans.direction);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
set direction(d: RTCRtpTransceiverDirection) {
|
|
44
|
-
if (this._stopped) {
|
|
45
|
-
throw new DOMException(
|
|
46
|
-
"Cannot set direction on a stopped transceiver",
|
|
47
|
-
'InvalidStateError',
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
if (d === 'stopped') {
|
|
51
|
-
throw new TypeError("The provided value 'stopped' is not a valid enum value of type RTCRtpTransceiverDirection.");
|
|
52
|
-
}
|
|
53
|
-
const valid: RTCRtpTransceiverDirection[] = ['sendrecv', 'sendonly', 'recvonly', 'inactive'];
|
|
54
|
-
if (!valid.includes(d)) {
|
|
55
|
-
throw new TypeError(`The provided value '${d}' is not a valid enum value of type RTCRtpTransceiverDirection.`);
|
|
56
|
-
}
|
|
57
|
-
this._gstTrans.direction = w3cDirectionToGst(d);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
get currentDirection(): RTCRtpTransceiverDirection | null {
|
|
61
|
-
if (this._stopped) return null;
|
|
62
|
-
// GIR exposes both snake_case `current_direction` and camelCase
|
|
63
|
-
// `currentDirection` getters — they refer to the same GObject
|
|
64
|
-
// property. Read snake_case first; fall back to camelCase for
|
|
65
|
-
// older GstWebRTC bindings that omitted the snake_case alias.
|
|
66
|
-
const cd = this._gstTrans.current_direction ?? this._gstTrans.currentDirection;
|
|
67
|
-
if (cd == null) return null;
|
|
68
|
-
const w3c = gstDirectionToW3C(cd);
|
|
69
|
-
return w3c === 'inactive' ? null : w3c;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get stopped(): boolean {
|
|
73
|
-
return this._stopped;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
stop(): void {
|
|
77
|
-
if (this._stopped) return;
|
|
78
|
-
this._stopped = true;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
setCodecPreferences(codecs: RTCRtpCodecCapability[]): void {
|
|
82
|
-
if (!Array.isArray(codecs)) {
|
|
83
|
-
throw new TypeError('codecs must be an array');
|
|
84
|
-
}
|
|
85
|
-
if (codecs.length === 0) {
|
|
86
|
-
this._codecPreferences = [];
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const kind = this.receiver.track.kind;
|
|
91
|
-
const recvCaps = RTCRtpReceiver.getCapabilities(kind);
|
|
92
|
-
const sendCaps = RTCRtpSender.getCapabilities(kind);
|
|
93
|
-
if (!recvCaps || !sendCaps) {
|
|
94
|
-
throw new DOMException('No capabilities available', 'InvalidModificationError');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const allCaps = [...recvCaps.codecs, ...sendCaps.codecs];
|
|
98
|
-
|
|
99
|
-
for (const codec of codecs) {
|
|
100
|
-
if (!codec || typeof codec !== 'object') {
|
|
101
|
-
throw new TypeError('Each codec must be an object');
|
|
102
|
-
}
|
|
103
|
-
if (typeof codec.mimeType !== 'string' || typeof codec.clockRate !== 'number') {
|
|
104
|
-
throw new TypeError('codec must have mimeType (string) and clockRate (number)');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const isResiliency = /\/(rtx|red|ulpfec)$/i.test(codec.mimeType);
|
|
108
|
-
if (isResiliency) continue;
|
|
109
|
-
|
|
110
|
-
const match = allCaps.find((c) =>
|
|
111
|
-
c.mimeType.toLowerCase() === codec.mimeType.toLowerCase() &&
|
|
112
|
-
c.clockRate === codec.clockRate &&
|
|
113
|
-
(codec.channels === undefined || c.channels === codec.channels) &&
|
|
114
|
-
(codec.sdpFmtpLine === undefined || c.sdpFmtpLine === codec.sdpFmtpLine)
|
|
115
|
-
);
|
|
116
|
-
if (!match) {
|
|
117
|
-
throw new DOMException(
|
|
118
|
-
`Codec ${codec.mimeType} ${codec.clockRate} is not in capabilities`,
|
|
119
|
-
'InvalidModificationError',
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
this._codecPreferences = [...codecs];
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** @internal */
|
|
128
|
-
get _nativeTransceiver(): GstWebRTC.WebRTCRTPTransceiver {
|
|
129
|
-
return this._gstTrans;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// W3C RTCSctpTransport for GJS.
|
|
2
|
-
//
|
|
3
|
-
// Created when a data channel is negotiated. Wraps the SCTP association
|
|
4
|
-
// over the DTLS transport. State transitions from connecting → connected
|
|
5
|
-
// when the first data channel opens.
|
|
6
|
-
//
|
|
7
|
-
// Reference: W3C WebRTC spec § 6.1
|
|
8
|
-
// Reference: refs/wpt/webrtc/RTCSctpTransport-constructor.html
|
|
9
|
-
|
|
10
|
-
import '@gjsify/dom-events/register/event-target';
|
|
11
|
-
|
|
12
|
-
import { RTCDtlsTransport } from './rtc-dtls-transport.js';
|
|
13
|
-
|
|
14
|
-
export type RTCSctpTransportState = 'connecting' | 'connected' | 'closed';
|
|
15
|
-
|
|
16
|
-
type EventHandler = ((ev: Event) => void) | null;
|
|
17
|
-
|
|
18
|
-
export class RTCSctpTransport extends EventTarget {
|
|
19
|
-
readonly transport: RTCDtlsTransport;
|
|
20
|
-
private _state: RTCSctpTransportState = 'connecting';
|
|
21
|
-
private _maxMessageSize: number = 262144; // 256 KB default per SCTP
|
|
22
|
-
private _maxChannels: number | null = 65535;
|
|
23
|
-
|
|
24
|
-
private _onstatechange: EventHandler = null;
|
|
25
|
-
|
|
26
|
-
constructor(dtlsTransport: RTCDtlsTransport) {
|
|
27
|
-
super();
|
|
28
|
-
this.transport = dtlsTransport;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
get state(): RTCSctpTransportState { return this._state; }
|
|
32
|
-
get maxMessageSize(): number { return this._maxMessageSize; }
|
|
33
|
-
get maxChannels(): number | null { return this._maxChannels; }
|
|
34
|
-
|
|
35
|
-
get onstatechange(): EventHandler { return this._onstatechange; }
|
|
36
|
-
set onstatechange(v: EventHandler) { this._onstatechange = v; }
|
|
37
|
-
|
|
38
|
-
// ---- Internal setters (called by RTCPeerConnection) ---------------------
|
|
39
|
-
|
|
40
|
-
/** @internal */
|
|
41
|
-
_setState(state: RTCSctpTransportState): void {
|
|
42
|
-
if (this._state === state) return;
|
|
43
|
-
this._state = state;
|
|
44
|
-
const ev = new Event('statechange');
|
|
45
|
-
this._onstatechange?.call(this, ev);
|
|
46
|
-
this.dispatchEvent(ev);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// RTCSessionDescription — W3C WebRTC session description (offer/answer/rollback).
|
|
2
|
-
//
|
|
3
|
-
// Reference: refs/node-gst-webrtc/src/webrtc/RTCSessionDescription.ts (ISC)
|
|
4
|
-
// Adapted for GJS using GstSdp + GstWebRTC.
|
|
5
|
-
|
|
6
|
-
import GstSdp from 'gi://GstSdp?version=1.0';
|
|
7
|
-
import GstWebRTC from 'gi://GstWebRTC?version=1.0';
|
|
8
|
-
|
|
9
|
-
export type RTCSdpType = 'offer' | 'pranswer' | 'answer' | 'rollback';
|
|
10
|
-
|
|
11
|
-
export interface RTCSessionDescriptionInit {
|
|
12
|
-
type?: RTCSdpType;
|
|
13
|
-
sdp?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function sdpTypeToGst(type: RTCSdpType): GstWebRTC.WebRTCSDPType {
|
|
17
|
-
switch (type) {
|
|
18
|
-
case 'offer': return GstWebRTC.WebRTCSDPType.OFFER;
|
|
19
|
-
case 'pranswer': return GstWebRTC.WebRTCSDPType.PRANSWER;
|
|
20
|
-
case 'answer': return GstWebRTC.WebRTCSDPType.ANSWER;
|
|
21
|
-
case 'rollback': return GstWebRTC.WebRTCSDPType.ROLLBACK;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function sdpTypeFromGst(type: GstWebRTC.WebRTCSDPType): RTCSdpType {
|
|
26
|
-
switch (type) {
|
|
27
|
-
case GstWebRTC.WebRTCSDPType.OFFER: return 'offer';
|
|
28
|
-
case GstWebRTC.WebRTCSDPType.PRANSWER: return 'pranswer';
|
|
29
|
-
case GstWebRTC.WebRTCSDPType.ANSWER: return 'answer';
|
|
30
|
-
case GstWebRTC.WebRTCSDPType.ROLLBACK: return 'rollback';
|
|
31
|
-
default: return 'offer';
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export class RTCSessionDescription {
|
|
36
|
-
readonly type: RTCSdpType;
|
|
37
|
-
readonly sdp: string;
|
|
38
|
-
|
|
39
|
-
constructor(init?: RTCSessionDescriptionInit) {
|
|
40
|
-
this.type = (init?.type ?? 'offer') as RTCSdpType;
|
|
41
|
-
this.sdp = init?.sdp ?? '';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
toJSON(): { type: RTCSdpType; sdp: string } {
|
|
45
|
-
return { type: this.type, sdp: this.sdp };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Build a GstWebRTC.WebRTCSessionDescription for use with webrtcbin signals. */
|
|
49
|
-
toGstDesc(): GstWebRTC.WebRTCSessionDescription {
|
|
50
|
-
const [ret, sdp] = GstSdp.SDPMessage.new_from_text(this.sdp);
|
|
51
|
-
if (ret !== GstSdp.SDPResult.OK) {
|
|
52
|
-
throw new Error(`Failed to parse SDP text (GstSDPResult=${ret})`);
|
|
53
|
-
}
|
|
54
|
-
return GstWebRTC.WebRTCSessionDescription.new(sdpTypeToGst(this.type), sdp);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static fromGstDesc(desc: GstWebRTC.WebRTCSessionDescription): RTCSessionDescription {
|
|
58
|
-
const sdpText = desc.sdp?.as_text?.() ?? '';
|
|
59
|
-
return new RTCSessionDescription({
|
|
60
|
-
type: sdpTypeFromGst(desc.type),
|
|
61
|
-
sdp: sdpText,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
package/src/rtc-stats-report.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// W3C RTCStatsReport — read-only Map<string, object> of WebRTC statistics.
|
|
2
|
-
//
|
|
3
|
-
// Reference: W3C WebRTC spec § 8.5
|
|
4
|
-
// The report is a frozen snapshot; .set()/.delete()/.clear() are no-ops.
|
|
5
|
-
|
|
6
|
-
export interface RTCStats {
|
|
7
|
-
timestamp: number;
|
|
8
|
-
type: string;
|
|
9
|
-
id: string;
|
|
10
|
-
[key: string]: unknown;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Read-only Map-like collection of stats entries keyed by id.
|
|
15
|
-
* W3C requires iteration support but not mutation.
|
|
16
|
-
*/
|
|
17
|
-
export class RTCStatsReport {
|
|
18
|
-
private readonly _map: Map<string, RTCStats>;
|
|
19
|
-
|
|
20
|
-
constructor(entries?: Iterable<[string, RTCStats]>) {
|
|
21
|
-
this._map = new Map(entries);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get size(): number { return this._map.size; }
|
|
25
|
-
|
|
26
|
-
get(key: string): RTCStats | undefined { return this._map.get(key); }
|
|
27
|
-
has(key: string): boolean { return this._map.has(key); }
|
|
28
|
-
|
|
29
|
-
forEach(callbackfn: (value: RTCStats, key: string, map: RTCStatsReport) => void, thisArg?: unknown): void {
|
|
30
|
-
this._map.forEach((value, key) => {
|
|
31
|
-
callbackfn.call(thisArg, value, key, this);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
entries(): IterableIterator<[string, RTCStats]> { return this._map.entries(); }
|
|
36
|
-
keys(): IterableIterator<string> { return this._map.keys(); }
|
|
37
|
-
values(): IterableIterator<RTCStats> { return this._map.values(); }
|
|
38
|
-
[Symbol.iterator](): IterableIterator<[string, RTCStats]> { return this._map.entries(); }
|
|
39
|
-
}
|
package/src/rtc-track-event.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// W3C RTCTrackEvent for GJS.
|
|
2
|
-
//
|
|
3
|
-
// Ported from refs/wpt/webrtc/RTCTrackEvent-constructor.html (W3C, BSD-3-Clause)
|
|
4
|
-
// Reference: W3C WebRTC spec § 5.7
|
|
5
|
-
|
|
6
|
-
import '@gjsify/dom-events/register/event-target';
|
|
7
|
-
|
|
8
|
-
import type { RTCRtpReceiver } from './rtc-rtp-receiver.js';
|
|
9
|
-
import type { RTCRtpTransceiver } from './rtc-rtp-transceiver.js';
|
|
10
|
-
import type { MediaStreamTrack } from './media-stream-track.js';
|
|
11
|
-
import type { MediaStream } from './media-stream.js';
|
|
12
|
-
|
|
13
|
-
export interface RTCTrackEventInit extends EventInit {
|
|
14
|
-
receiver: RTCRtpReceiver;
|
|
15
|
-
track: MediaStreamTrack;
|
|
16
|
-
streams?: MediaStream[];
|
|
17
|
-
transceiver: RTCRtpTransceiver;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class RTCTrackEvent extends Event {
|
|
21
|
-
readonly receiver: RTCRtpReceiver;
|
|
22
|
-
readonly track: MediaStreamTrack;
|
|
23
|
-
readonly streams: ReadonlyArray<MediaStream>;
|
|
24
|
-
readonly transceiver: RTCRtpTransceiver;
|
|
25
|
-
|
|
26
|
-
constructor(type: string, init: RTCTrackEventInit) {
|
|
27
|
-
super(type, init);
|
|
28
|
-
if (!init || typeof init !== 'object') {
|
|
29
|
-
throw new TypeError('RTCTrackEventInit is required');
|
|
30
|
-
}
|
|
31
|
-
if (!('receiver' in init)) {
|
|
32
|
-
throw new TypeError("Failed to construct 'RTCTrackEvent': required member receiver is not provided.");
|
|
33
|
-
}
|
|
34
|
-
if (!('track' in init)) {
|
|
35
|
-
throw new TypeError("Failed to construct 'RTCTrackEvent': required member track is not provided.");
|
|
36
|
-
}
|
|
37
|
-
if (!('transceiver' in init)) {
|
|
38
|
-
throw new TypeError("Failed to construct 'RTCTrackEvent': required member transceiver is not provided.");
|
|
39
|
-
}
|
|
40
|
-
this.receiver = init.receiver;
|
|
41
|
-
this.track = init.track;
|
|
42
|
-
this.streams = Object.freeze(init.streams ? [...init.streams] : []);
|
|
43
|
-
this.transceiver = init.transceiver;
|
|
44
|
-
}
|
|
45
|
-
}
|
package/src/rtp-capabilities.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Shared RTP codec capabilities for RTCRtpSender and RTCRtpReceiver.
|
|
2
|
-
//
|
|
3
|
-
// Both classes expose identical getCapabilities(kind) static methods per
|
|
4
|
-
// W3C WebRTC spec §§ 5.2 and 5.3. This module deduplicates the data.
|
|
5
|
-
|
|
6
|
-
import type { RTCRtpCapabilities } from './rtc-rtp-sender.js';
|
|
7
|
-
|
|
8
|
-
const AUDIO_CAPABILITIES: RTCRtpCapabilities = {
|
|
9
|
-
codecs: [
|
|
10
|
-
{ mimeType: 'audio/opus', clockRate: 48000, channels: 2, sdpFmtpLine: 'minptime=10;useinbandfec=1' },
|
|
11
|
-
{ mimeType: 'audio/G722', clockRate: 8000, channels: 1 },
|
|
12
|
-
{ mimeType: 'audio/PCMU', clockRate: 8000, channels: 1 },
|
|
13
|
-
{ mimeType: 'audio/PCMA', clockRate: 8000, channels: 1 },
|
|
14
|
-
{ mimeType: 'audio/telephone-event', clockRate: 8000, channels: 1 },
|
|
15
|
-
{ mimeType: 'audio/red', clockRate: 48000, channels: 2 },
|
|
16
|
-
],
|
|
17
|
-
headerExtensions: [
|
|
18
|
-
{ uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level' },
|
|
19
|
-
{ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
|
|
20
|
-
{ uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
|
|
21
|
-
],
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const VIDEO_CAPABILITIES: RTCRtpCapabilities = {
|
|
25
|
-
codecs: [
|
|
26
|
-
{ mimeType: 'video/VP8', clockRate: 90000 },
|
|
27
|
-
{ mimeType: 'video/rtx', clockRate: 90000 },
|
|
28
|
-
{ mimeType: 'video/H264', clockRate: 90000, sdpFmtpLine: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f' },
|
|
29
|
-
{ mimeType: 'video/VP9', clockRate: 90000 },
|
|
30
|
-
{ mimeType: 'video/red', clockRate: 90000 },
|
|
31
|
-
{ mimeType: 'video/ulpfec', clockRate: 90000 },
|
|
32
|
-
],
|
|
33
|
-
headerExtensions: [
|
|
34
|
-
{ uri: 'urn:ietf:params:rtp-hdrext:toffset' },
|
|
35
|
-
{ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
|
|
36
|
-
{ uri: 'urn:3gpp:video-orientation' },
|
|
37
|
-
{ uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
|
|
38
|
-
{ uri: 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id' },
|
|
39
|
-
{ uri: 'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id' },
|
|
40
|
-
],
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/** Shared implementation for RTCRtpSender.getCapabilities / RTCRtpReceiver.getCapabilities. */
|
|
44
|
-
export function getRtpCapabilities(kind: string): RTCRtpCapabilities | null {
|
|
45
|
-
if (kind === 'audio') return AUDIO_CAPABILITIES;
|
|
46
|
-
if (kind === 'video') return VIDEO_CAPABILITIES;
|
|
47
|
-
return null;
|
|
48
|
-
}
|
package/src/tee-multiplexer.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
// GStreamer tee element manager for multi-PC fan-out.
|
|
2
|
-
//
|
|
3
|
-
// When a single MediaStreamTrack (backed by a GStreamer source) needs to
|
|
4
|
-
// feed multiple RTCPeerConnections, a tee element is inserted after the
|
|
5
|
-
// source. Each PC gets its own branch (encoder chain → webrtcbin sink).
|
|
6
|
-
//
|
|
7
|
-
// Reference: refs/node-gst-webrtc/src/media/TeeMultiplexer.ts (ISC)
|
|
8
|
-
// Reference: packages/web/webrtc-native/src/vala/receiver-bridge.vala (tee pattern)
|
|
9
|
-
|
|
10
|
-
import { Gst } from './gst-init.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Manages a GStreamer `tee` element that fans out one source to multiple
|
|
14
|
-
* consumer branches. Each branch gets its own src pad from the tee.
|
|
15
|
-
*/
|
|
16
|
-
export class TeeMultiplexer {
|
|
17
|
-
private _tee: any; // Gst.Element
|
|
18
|
-
private _pipeline: any; // Gst.Pipeline
|
|
19
|
-
private _branchCount = 0;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Create a tee in the given pipeline and link it to the source's output.
|
|
23
|
-
* The source must already be in the pipeline.
|
|
24
|
-
*/
|
|
25
|
-
constructor(pipeline: any, source: any) {
|
|
26
|
-
this._pipeline = pipeline;
|
|
27
|
-
this._tee = Gst.ElementFactory.make('tee', null)!;
|
|
28
|
-
(this._tee as any).allow_not_linked = true;
|
|
29
|
-
|
|
30
|
-
pipeline.add(this._tee);
|
|
31
|
-
this._tee.sync_state_with_parent();
|
|
32
|
-
|
|
33
|
-
// Link source → tee
|
|
34
|
-
source.link(this._tee);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Request a new src pad from the tee for a consumer branch. */
|
|
38
|
-
requestSrcPad(): any /* Gst.Pad */ {
|
|
39
|
-
const padName = 'src_%u';
|
|
40
|
-
const srcPad = this._tee.request_pad_simple
|
|
41
|
-
? this._tee.request_pad_simple(padName)
|
|
42
|
-
: this._tee.get_request_pad(padName);
|
|
43
|
-
if (srcPad) this._branchCount++;
|
|
44
|
-
return srcPad;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Release a branch's src pad from the tee.
|
|
49
|
-
* Adds a DROP probe before unlinking to prevent errors.
|
|
50
|
-
*/
|
|
51
|
-
releaseSrcPad(srcPad: any): void {
|
|
52
|
-
if (!srcPad) return;
|
|
53
|
-
try {
|
|
54
|
-
// Block data on the pad before unlinking
|
|
55
|
-
srcPad.add_probe(
|
|
56
|
-
Gst.PadProbeType.BLOCK_DOWNSTREAM,
|
|
57
|
-
() => Gst.PadProbeReturn.DROP,
|
|
58
|
-
);
|
|
59
|
-
} catch { /* ignore if probe fails */ }
|
|
60
|
-
try {
|
|
61
|
-
const peer = srcPad.get_peer();
|
|
62
|
-
if (peer) srcPad.unlink(peer);
|
|
63
|
-
} catch { /* ignore */ }
|
|
64
|
-
try {
|
|
65
|
-
this._tee.release_request_pad(srcPad);
|
|
66
|
-
} catch { /* ignore */ }
|
|
67
|
-
this._branchCount--;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Number of active branches. */
|
|
71
|
-
get branchCount(): number { return this._branchCount; }
|
|
72
|
-
|
|
73
|
-
/** The tee element (for pipeline queries). */
|
|
74
|
-
get element(): any { return this._tee; }
|
|
75
|
-
}
|
package/src/test.mts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import webrtcSpec from './webrtc.spec.js';
|
|
2
|
-
import wptSpec from './wpt.spec.js';
|
|
3
|
-
import wptMediaSpec from './wpt-media.spec.js';
|
|
4
|
-
import registerSpec from './register.spec.js';
|
|
5
|
-
|
|
6
|
-
const results = {
|
|
7
|
-
webrtc: await webrtcSpec(),
|
|
8
|
-
wpt: await wptSpec(),
|
|
9
|
-
wptMedia: await wptMediaSpec(),
|
|
10
|
-
register: await registerSpec(),
|
|
11
|
-
};
|