add very early datachannel support
This commit is contained in:
parent
c02e1de001
commit
b84c90891c
5 changed files with 32 additions and 15 deletions
|
@ -22,7 +22,8 @@ export class LocalMedia {
|
|||
constructor(
|
||||
public readonly cameraTrack?: Track,
|
||||
public readonly screenShareTrack?: Track,
|
||||
public readonly microphoneTrack?: AudioTrack
|
||||
public readonly microphoneTrack?: AudioTrack,
|
||||
public readonly dataChannelOptions?: RTCDataChannelInit,
|
||||
) {}
|
||||
|
||||
withTracks(tracks: Track[]) {
|
||||
|
@ -32,7 +33,11 @@ export class LocalMedia {
|
|||
if (cameraTrack && microphoneTrack && cameraTrack.streamId !== microphoneTrack.streamId) {
|
||||
throw new Error("The camera and audio track should have the same stream id");
|
||||
}
|
||||
return new LocalMedia(cameraTrack, screenShareTrack, microphoneTrack as AudioTrack);
|
||||
return new LocalMedia(cameraTrack, screenShareTrack, microphoneTrack as AudioTrack, this.dataChannelOptions);
|
||||
}
|
||||
|
||||
withDataChannel(options: RTCDataChannelInit): LocalMedia {
|
||||
return new LocalMedia(this.cameraTrack, this.screenShareTrack, this.microphoneTrack as AudioTrack, options);
|
||||
}
|
||||
|
||||
get tracks(): Track[] {
|
||||
|
|
|
@ -85,6 +85,8 @@ export class PeerCall implements IDisposable {
|
|||
private sentEndOfCandidates: boolean = false;
|
||||
private iceDisconnectedTimeout?: Timeout;
|
||||
|
||||
private _dataChannel?: any;
|
||||
|
||||
constructor(
|
||||
private callId: string,
|
||||
private readonly options: Options,
|
||||
|
@ -112,7 +114,12 @@ export class PeerCall implements IDisposable {
|
|||
outer.options.emitUpdate(outer, undefined);
|
||||
});
|
||||
},
|
||||
onDataChannelChanged(dataChannel: DataChannel | undefined) {},
|
||||
onRemoteDataChannel(dataChannel: any | undefined) {
|
||||
outer.logItem.wrap("onRemoteDataChannel", log => {
|
||||
outer._dataChannel = dataChannel;
|
||||
outer.options.emitUpdate(outer, undefined);
|
||||
});
|
||||
},
|
||||
onNegotiationNeeded() {
|
||||
const promiseCreator = () => {
|
||||
return outer.logItem.wrap("onNegotiationNeeded", log => {
|
||||
|
@ -127,6 +134,8 @@ export class PeerCall implements IDisposable {
|
|||
});
|
||||
}
|
||||
|
||||
get dataChannel(): any | undefined { return this._dataChannel; }
|
||||
|
||||
get state(): CallState { return this._state; }
|
||||
|
||||
get remoteTracks(): Track[] {
|
||||
|
@ -144,6 +153,9 @@ export class PeerCall implements IDisposable {
|
|||
for (const t of this.localMedia.tracks) {
|
||||
this.peerConnection.addTrack(t);
|
||||
}
|
||||
if (this.localMedia.dataChannelOptions) {
|
||||
this._dataChannel = this.peerConnection.createDataChannel(this.localMedia.dataChannelOptions);
|
||||
}
|
||||
// after adding the local tracks, and wait for handleNegotiation to be called,
|
||||
// or invite glare where we give up our invite and answer instead
|
||||
await this.waitForState([CallState.InviteSent, CallState.CreateAnswer]);
|
||||
|
@ -160,7 +172,9 @@ export class PeerCall implements IDisposable {
|
|||
for (const t of this.localMedia.tracks) {
|
||||
this.peerConnection.addTrack(t);
|
||||
}
|
||||
|
||||
if (this.localMedia.dataChannelOptions) {
|
||||
this._dataChannel = this.peerConnection.createDataChannel(this.localMedia.dataChannelOptions);
|
||||
}
|
||||
let myAnswer: RTCSessionDescriptionInit;
|
||||
try {
|
||||
myAnswer = await this.peerConnection.createAnswer();
|
||||
|
|
|
@ -66,6 +66,10 @@ export class Member {
|
|||
return this.callDeviceMembership.device_id;
|
||||
}
|
||||
|
||||
get dataChannel(): any | undefined {
|
||||
return this.peerCall?.dataChannel;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
connect(localMedia: LocalMedia) {
|
||||
this.logItem.wrap("connect", () => {
|
||||
|
|
|
@ -26,21 +26,15 @@ export interface PeerConnectionHandler {
|
|||
onLocalIceCandidate(candidate: RTCIceCandidate);
|
||||
onIceGatheringStateChange(state: RTCIceGatheringState);
|
||||
onRemoteTracksChanged(tracks: Track[]);
|
||||
onDataChannelChanged(dataChannel: DataChannel | undefined);
|
||||
onRemoteDataChannel(dataChannel: any | undefined);
|
||||
onNegotiationNeeded();
|
||||
// request the type of incoming stream
|
||||
getPurposeForStreamId(streamId: string): SDPStreamMetadataPurpose;
|
||||
}
|
||||
// does it make sense to wrap this?
|
||||
export interface DataChannel {
|
||||
close();
|
||||
send();
|
||||
}
|
||||
|
||||
export interface PeerConnection {
|
||||
notifyStreamPurposeChanged(): void;
|
||||
get remoteTracks(): Track[];
|
||||
get dataChannel(): DataChannel | undefined;
|
||||
get iceGatheringState(): RTCIceGatheringState;
|
||||
get signalingState(): RTCSignalingState;
|
||||
get localDescription(): RTCSessionDescription | undefined;
|
||||
|
@ -52,7 +46,7 @@ export interface PeerConnection {
|
|||
addTrack(track: Track): void;
|
||||
removeTrack(track: Track): boolean;
|
||||
replaceTrack(oldTrack: Track, newTrack: Track): Promise<boolean>;
|
||||
createDataChannel(): DataChannel;
|
||||
createDataChannel(options: RTCDataChannelInit): any;
|
||||
dispose(): void;
|
||||
close(): void;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ class DOMPeerConnection implements PeerConnection {
|
|||
}
|
||||
|
||||
get remoteTracks(): Track[] { return this._remoteTracks; }
|
||||
get dataChannel(): DataChannel | undefined { return undefined; }
|
||||
get iceGatheringState(): RTCIceGatheringState { return this.peerConnection.iceGatheringState; }
|
||||
get localDescription(): RTCSessionDescription | undefined { return this.peerConnection.localDescription ?? undefined; }
|
||||
get signalingState(): RTCSignalingState { return this.peerConnection.signalingState; }
|
||||
|
@ -119,8 +118,8 @@ class DOMPeerConnection implements PeerConnection {
|
|||
}
|
||||
}
|
||||
|
||||
createDataChannel(): DataChannel {
|
||||
return undefined as any;// new DataChannel(this.peerConnection.createDataChannel());
|
||||
createDataChannel(options: RTCDataChannelInit): any {
|
||||
return this.peerConnection.createDataChannel("channel", options);
|
||||
}
|
||||
|
||||
private registerHandler() {
|
||||
|
@ -164,6 +163,7 @@ class DOMPeerConnection implements PeerConnection {
|
|||
this.handler.onNegotiationNeeded();
|
||||
break;
|
||||
case "datachannel":
|
||||
this.handler.onRemoteDataChannel((evt as RTCDataChannelEvent).channel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue