livekit-client
Advanced tools
Comparing version 0.6.7 to 0.7.0
@@ -0,1 +1,2 @@ | ||
import { DataPacket_Kind } from './proto/livekit_rtc'; | ||
import { LocalParticipant } from './room/participant/LocalParticipant'; | ||
@@ -11,3 +12,2 @@ import { Participant } from './room/participant/Participant'; | ||
export * from './room/track/LocalAudioTrack'; | ||
export * from './room/track/LocalDataTrack'; | ||
export * from './room/track/LocalTrackPublication'; | ||
@@ -17,3 +17,2 @@ export * from './room/track/LocalVideoTrack'; | ||
export * from './room/track/RemoteAudioTrack'; | ||
export * from './room/track/RemoteDataTrack'; | ||
export * from './room/track/RemoteTrackPublication'; | ||
@@ -26,2 +25,2 @@ export * from './room/track/RemoteVideoTrack'; | ||
export * from './version'; | ||
export { Room, RoomState, Participant, RemoteParticipant, LocalParticipant }; | ||
export { Room, RoomState, DataPacket_Kind, Participant, RemoteParticipant, LocalParticipant, }; |
@@ -25,3 +25,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.LocalParticipant = exports.RemoteParticipant = exports.Participant = exports.RoomState = exports.Room = void 0; | ||
exports.LocalParticipant = exports.RemoteParticipant = exports.Participant = exports.DataPacket_Kind = exports.RoomState = exports.Room = void 0; | ||
const livekit_rtc_1 = require("./proto/livekit_rtc"); | ||
Object.defineProperty(exports, "DataPacket_Kind", { enumerable: true, get: function () { return livekit_rtc_1.DataPacket_Kind; } }); | ||
const LocalParticipant_1 = require("./room/participant/LocalParticipant"); | ||
@@ -42,3 +44,2 @@ Object.defineProperty(exports, "LocalParticipant", { enumerable: true, get: function () { return LocalParticipant_1.LocalParticipant; } }); | ||
__exportStar(require("./room/track/LocalAudioTrack"), exports); | ||
__exportStar(require("./room/track/LocalDataTrack"), exports); | ||
__exportStar(require("./room/track/LocalTrackPublication"), exports); | ||
@@ -48,3 +49,2 @@ __exportStar(require("./room/track/LocalVideoTrack"), exports); | ||
__exportStar(require("./room/track/RemoteAudioTrack"), exports); | ||
__exportStar(require("./room/track/RemoteDataTrack"), exports); | ||
__exportStar(require("./room/track/RemoteTrackPublication"), exports); | ||
@@ -51,0 +51,0 @@ __exportStar(require("./room/track/RemoteVideoTrack"), exports); |
@@ -47,2 +47,3 @@ import _m0 from 'protobufjs/minimal'; | ||
} | ||
/** old DataTrack message */ | ||
export interface DataMessage { | ||
@@ -49,0 +50,0 @@ text: string | undefined; |
@@ -117,2 +117,21 @@ import _m0 from 'protobufjs/minimal'; | ||
} | ||
/** new DataPacket API */ | ||
export interface DataPacket { | ||
kind: DataPacket_Kind; | ||
user?: UserPacket | undefined; | ||
speaker?: ActiveSpeakerUpdate | undefined; | ||
} | ||
export declare enum DataPacket_Kind { | ||
RELIABLE = 0, | ||
LOSSY = 1, | ||
UNRECOGNIZED = -1 | ||
} | ||
export declare function dataPacket_KindFromJSON(object: any): DataPacket_Kind; | ||
export declare function dataPacket_KindToJSON(object: DataPacket_Kind): string; | ||
export interface UserPacket { | ||
/** participant ID of user that sent the message */ | ||
participantSid: string; | ||
/** user defined payload */ | ||
payload: Uint8Array; | ||
} | ||
export declare const SignalRequest: { | ||
@@ -230,2 +249,16 @@ encode(message: SignalRequest, writer?: _m0.Writer): _m0.Writer; | ||
}; | ||
export declare const DataPacket: { | ||
encode(message: DataPacket, writer?: _m0.Writer): _m0.Writer; | ||
decode(input: _m0.Reader | Uint8Array, length?: number | undefined): DataPacket; | ||
fromJSON(object: any): DataPacket; | ||
toJSON(message: DataPacket): unknown; | ||
fromPartial(object: DeepPartial<DataPacket>): DataPacket; | ||
}; | ||
export declare const UserPacket: { | ||
encode(message: UserPacket, writer?: _m0.Writer): _m0.Writer; | ||
decode(input: _m0.Reader | Uint8Array, length?: number | undefined): UserPacket; | ||
fromJSON(object: any): UserPacket; | ||
toJSON(message: UserPacket): unknown; | ||
fromPartial(object: DeepPartial<UserPacket>): UserPacket; | ||
}; | ||
declare type Builtin = Date | Function | Uint8Array | string | number | undefined; | ||
@@ -232,0 +265,0 @@ export declare type DeepPartial<T> = T extends Builtin ? T : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? { |
@@ -15,1 +15,4 @@ export declare class LivekitError { | ||
} | ||
export declare class PublishDataError extends LivekitError { | ||
constructor(message?: string); | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.UnexpectedConnectionState = exports.UnsupportedServer = exports.TrackInvalidError = exports.LivekitError = void 0; | ||
exports.PublishDataError = exports.UnexpectedConnectionState = exports.UnsupportedServer = exports.TrackInvalidError = exports.LivekitError = void 0; | ||
class LivekitError { | ||
@@ -29,2 +29,8 @@ constructor(code, message) { | ||
exports.UnexpectedConnectionState = UnexpectedConnectionState; | ||
class PublishDataError extends LivekitError { | ||
constructor(message) { | ||
super(13, message || 'Unable to publish data'); | ||
} | ||
} | ||
exports.PublishDataError = PublishDataError; | ||
//# sourceMappingURL=errors.js.map |
@@ -76,8 +76,2 @@ /** | ||
/** | ||
* a message received over a [[DataTrack]] | ||
* | ||
* args: (data, [[RemoteDataTrack]], [[RemoteParticipant]]) | ||
*/ | ||
TrackMessage = "trackMessage", | ||
/** | ||
* Active speakers changed. List of speakers are ordered by their audio level. | ||
@@ -95,5 +89,13 @@ * loudest speakers first. This will include the LocalParticipant too. | ||
* | ||
* args: (prevMetadata: string, Participant) | ||
* args: (prevMetadata: string, [[Participant]]) | ||
*/ | ||
MetadataChanged = "metadataChanged" | ||
MetadataChanged = "metadataChanged", | ||
/** | ||
* Data received from another participant. | ||
* Data packets provides the ability to use LiveKit to send/receive arbitrary payloads. | ||
* All participants in the room will receive the messages sent to the room. | ||
* | ||
* args (payload: Uint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]]) | ||
*/ | ||
DataReceived = "dataReceived" | ||
} | ||
@@ -108,4 +110,4 @@ export declare enum ParticipantEvent { | ||
TrackUnmuted = "trackUnmuted", | ||
TrackMessage = "trackMessage", | ||
MetadataChanged = "metadataChanged" | ||
MetadataChanged = "metadataChanged", | ||
DataReceived = "dataReceived" | ||
} | ||
@@ -118,4 +120,4 @@ /** @internal */ | ||
MediaTrackAdded = "mediaTrackAdded", | ||
DataChannelAdded = "dataChannelAdded", | ||
SpeakersUpdate = "speakersUpdate" | ||
SpeakersUpdate = "speakersUpdate", | ||
DataPacketReceived = "dataPacketReceived" | ||
} | ||
@@ -122,0 +124,0 @@ export declare enum TrackEvent { |
@@ -80,8 +80,2 @@ "use strict"; | ||
/** | ||
* a message received over a [[DataTrack]] | ||
* | ||
* args: (data, [[RemoteDataTrack]], [[RemoteParticipant]]) | ||
*/ | ||
RoomEvent["TrackMessage"] = "trackMessage"; | ||
/** | ||
* Active speakers changed. List of speakers are ordered by their audio level. | ||
@@ -99,5 +93,13 @@ * loudest speakers first. This will include the LocalParticipant too. | ||
* | ||
* args: (prevMetadata: string, Participant) | ||
* args: (prevMetadata: string, [[Participant]]) | ||
*/ | ||
RoomEvent["MetadataChanged"] = "metadataChanged"; | ||
/** | ||
* Data received from another participant. | ||
* Data packets provides the ability to use LiveKit to send/receive arbitrary payloads. | ||
* All participants in the room will receive the messages sent to the room. | ||
* | ||
* args (payload: Uint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]]) | ||
*/ | ||
RoomEvent["DataReceived"] = "dataReceived"; | ||
})(RoomEvent = exports.RoomEvent || (exports.RoomEvent = {})); | ||
@@ -113,4 +115,4 @@ var ParticipantEvent; | ||
ParticipantEvent["TrackUnmuted"] = "trackUnmuted"; | ||
ParticipantEvent["TrackMessage"] = "trackMessage"; | ||
ParticipantEvent["MetadataChanged"] = "metadataChanged"; | ||
ParticipantEvent["DataReceived"] = "dataReceived"; | ||
})(ParticipantEvent = exports.ParticipantEvent || (exports.ParticipantEvent = {})); | ||
@@ -124,4 +126,4 @@ /** @internal */ | ||
EngineEvent["MediaTrackAdded"] = "mediaTrackAdded"; | ||
EngineEvent["DataChannelAdded"] = "dataChannelAdded"; | ||
EngineEvent["SpeakersUpdate"] = "speakersUpdate"; | ||
EngineEvent["DataPacketReceived"] = "dataPacketReceived"; | ||
})(EngineEvent = exports.EngineEvent || (exports.EngineEvent = {})); | ||
@@ -128,0 +130,0 @@ var TrackEvent; |
import { ParticipantInfo } from '../../proto/livekit_models'; | ||
import { DataPacket_Kind } from '../../proto/livekit_rtc'; | ||
import { RTCEngine } from '../RTCEngine'; | ||
@@ -13,3 +14,2 @@ import { LocalAudioTrack } from '../track/LocalAudioTrack'; | ||
videoTracks: Map<string, LocalTrackPublication>; | ||
dataTracks: Map<string, LocalTrackPublication>; | ||
/** map of track sid => all published tracks */ | ||
@@ -30,2 +30,13 @@ tracks: Map<string, LocalTrackPublication>; | ||
updateInfo(info: ParticipantInfo): void; | ||
/** | ||
* Publish a new data payload to the room. Data will be forwarded to each | ||
* participant in the room | ||
* | ||
* @param data Uint8Array of the payload. To send string data, use TextEncoder.encode | ||
* @param kind whether to send this as reliable or lossy. | ||
* For data that you need delivery guarantee (such as chat messages), use Reliable. | ||
* For data that should arrive as quickly as possible, but you are ok with dropped | ||
* packets, use Lossy. | ||
*/ | ||
publishData(data: Uint8Array, kind: DataPacket_Kind): void; | ||
/** @internal */ | ||
@@ -32,0 +43,0 @@ onTrackUnmuted: (track: LocalVideoTrack | LocalAudioTrack) => void; |
@@ -18,6 +18,6 @@ "use strict"; | ||
const options_1 = require("../../options"); | ||
const livekit_rtc_1 = require("../../proto/livekit_rtc"); | ||
const errors_1 = require("../errors"); | ||
const events_1 = require("../events"); | ||
const LocalAudioTrack_1 = require("../track/LocalAudioTrack"); | ||
const LocalDataTrack_1 = require("../track/LocalDataTrack"); | ||
const LocalTrackPublication_1 = require("../track/LocalTrackPublication"); | ||
@@ -57,3 +57,2 @@ const LocalVideoTrack_1 = require("../track/LocalVideoTrack"); | ||
this.videoTracks = new Map(); | ||
this.dataTracks = new Map(); | ||
this.tracks = new Map(); | ||
@@ -98,50 +97,34 @@ this.engine = engine; | ||
// get local track id for use during publishing | ||
let cid; | ||
if (track instanceof LocalDataTrack_1.LocalDataTrack) { | ||
// use data channel name as the id, because id isn't created until later | ||
cid = track.name; | ||
} | ||
else { | ||
cid = track.mediaStreamTrack.id; | ||
} | ||
let cid = track.mediaStreamTrack.id; | ||
// create track publication from track | ||
const ti = yield this.engine.addTrack(cid, track.name, track.kind); | ||
const publication = new LocalTrackPublication_1.LocalTrackPublication(track.kind, ti, track); | ||
if (track instanceof LocalDataTrack_1.LocalDataTrack) { | ||
if (!this.engine.publisher) { | ||
throw new errors_1.UnexpectedConnectionState('publisher is closed'); | ||
} | ||
// add data track | ||
track.dataChannel = this.engine.publisher.pc.createDataChannel(track.name, track.dataChannelInit); | ||
let encodings = undefined; | ||
// for video | ||
if (track.kind === Track_1.Track.Kind.Video) { | ||
// TODO: support react native, which doesn't expose getSettings | ||
const settings = track.mediaStreamTrack.getSettings(); | ||
encodings = this.computeVideoEncodings(settings.width, settings.height, options); | ||
} | ||
else { | ||
let encodings = undefined; | ||
// for video | ||
if (track.kind === Track_1.Track.Kind.Video) { | ||
// TODO: support react native, which doesn't expose getSettings | ||
const settings = track.mediaStreamTrack.getSettings(); | ||
encodings = this.computeVideoEncodings(settings.width, settings.height, options); | ||
} | ||
else if (track.kind === Track_1.Track.Kind.Audio) { | ||
encodings = [ | ||
{ | ||
maxBitrate: (options === null || options === void 0 ? void 0 : options.audioBitrate) || options_1.AudioPresets.speech.maxBitrate, | ||
}, | ||
]; | ||
} | ||
if (!this.engine.publisher) { | ||
throw new errors_1.UnexpectedConnectionState('publisher is closed'); | ||
} | ||
loglevel_1.default.debug('publishing with encodings', encodings); | ||
const transceiver = this.engine.publisher.pc.addTransceiver(track.mediaStreamTrack, { | ||
direction: 'sendonly', | ||
sendEncodings: encodings, | ||
}); | ||
// store RTPSender | ||
track.sender = transceiver.sender; | ||
if (track instanceof LocalVideoTrack_1.LocalVideoTrack) { | ||
track.startMonitor(); | ||
} | ||
this.setPreferredCodec(transceiver, track.kind, options === null || options === void 0 ? void 0 : options.videoCodec); | ||
else if (track.kind === Track_1.Track.Kind.Audio) { | ||
encodings = [ | ||
{ | ||
maxBitrate: (options === null || options === void 0 ? void 0 : options.audioBitrate) || options_1.AudioPresets.speech.maxBitrate, | ||
}, | ||
]; | ||
} | ||
if (!this.engine.publisher) { | ||
throw new errors_1.UnexpectedConnectionState('publisher is closed'); | ||
} | ||
loglevel_1.default.debug('publishing with encodings', encodings); | ||
const transceiver = this.engine.publisher.pc.addTransceiver(track.mediaStreamTrack, { | ||
direction: 'sendonly', | ||
sendEncodings: encodings, | ||
}); | ||
// store RTPSender | ||
track.sender = transceiver.sender; | ||
if (track instanceof LocalVideoTrack_1.LocalVideoTrack) { | ||
track.startMonitor(); | ||
} | ||
this.setPreferredCodec(transceiver, track.kind, options === null || options === void 0 ? void 0 : options.videoCodec); | ||
this.addTrackPublication(publication); | ||
@@ -167,16 +150,14 @@ // send event for publication | ||
track.stop(); | ||
if (!(track instanceof LocalDataTrack_1.LocalDataTrack)) { | ||
let mediaStreamTrack; | ||
if (track instanceof MediaStreamTrack) { | ||
mediaStreamTrack = track; | ||
} | ||
else { | ||
mediaStreamTrack = track.mediaStreamTrack; | ||
} | ||
if (this.engine.publisher) { | ||
const senders = this.engine.publisher.pc.getSenders(); | ||
for (const sender of senders) { | ||
if (sender.track === mediaStreamTrack) { | ||
this.engine.publisher.pc.removeTrack(sender); | ||
} | ||
let mediaStreamTrack; | ||
if (track instanceof MediaStreamTrack) { | ||
mediaStreamTrack = track; | ||
} | ||
else { | ||
mediaStreamTrack = track.mediaStreamTrack; | ||
} | ||
if (this.engine.publisher) { | ||
const senders = this.engine.publisher.pc.getSenders(); | ||
for (const sender of senders) { | ||
if (sender.track === mediaStreamTrack) { | ||
this.engine.publisher.pc.removeTrack(sender); | ||
} | ||
@@ -194,5 +175,2 @@ } | ||
break; | ||
case Track_1.Track.Kind.Data: | ||
this.dataTracks.delete(publication.trackSid); | ||
break; | ||
} | ||
@@ -231,2 +209,31 @@ return publication; | ||
} | ||
/** | ||
* Publish a new data payload to the room. Data will be forwarded to each | ||
* participant in the room | ||
* | ||
* @param data Uint8Array of the payload. To send string data, use TextEncoder.encode | ||
* @param kind whether to send this as reliable or lossy. | ||
* For data that you need delivery guarantee (such as chat messages), use Reliable. | ||
* For data that should arrive as quickly as possible, but you are ok with dropped | ||
* packets, use Lossy. | ||
*/ | ||
publishData(data, kind) { | ||
if (data.length > 15000) { | ||
throw new errors_1.PublishDataError('data cannot be larger than 15k'); | ||
} | ||
const packet = { | ||
kind: kind, | ||
user: { | ||
participantSid: this.sid, | ||
payload: data, | ||
}, | ||
}; | ||
const msg = livekit_rtc_1.DataPacket.encode(packet).finish(); | ||
if (kind === livekit_rtc_1.DataPacket_Kind.LOSSY && this.engine.lossyDC) { | ||
this.engine.lossyDC.send(msg); | ||
} | ||
else if (kind === livekit_rtc_1.DataPacket_Kind.RELIABLE && this.engine.reliableDC) { | ||
this.engine.reliableDC.send(msg); | ||
} | ||
} | ||
getPublicationForTrack(track) { | ||
@@ -233,0 +240,0 @@ let publication; |
@@ -11,5 +11,2 @@ /// <reference types="node" /> | ||
}; | ||
export declare type DataTrackMap = { | ||
[key: string]: TrackPublication; | ||
}; | ||
export declare class Participant extends EventEmitter { | ||
@@ -19,3 +16,2 @@ protected participantInfo?: ParticipantInfo; | ||
videoTracks: Map<string, TrackPublication>; | ||
dataTracks: Map<string, TrackPublication>; | ||
/** map of track sid => all published tracks */ | ||
@@ -22,0 +18,0 @@ tracks: Map<string, TrackPublication>; |
@@ -17,3 +17,2 @@ "use strict"; | ||
this.videoTracks = new Map(); | ||
this.dataTracks = new Map(); | ||
this.tracks = new Map(); | ||
@@ -66,5 +65,2 @@ } | ||
break; | ||
case Track_1.Track.Kind.Data: | ||
this.dataTracks.set(publication.trackSid, publication); | ||
break; | ||
} | ||
@@ -71,0 +67,0 @@ } |
@@ -10,3 +10,2 @@ import { SignalClient } from '../../api/SignalClient'; | ||
videoTracks: Map<string, RemoteTrackPublication>; | ||
dataTracks: Map<string, RemoteTrackPublication>; | ||
tracks: Map<string, RemoteTrackPublication>; | ||
@@ -22,4 +21,2 @@ signalClient: SignalClient; | ||
/** @internal */ | ||
addSubscribedDataTrack(dataChannel: RTCDataChannel, sid: Track.SID, name: string): RemoteTrackPublication; | ||
/** @internal */ | ||
get hasMetadata(): boolean; | ||
@@ -26,0 +23,0 @@ getTrackPublication(sid: Track.SID): RemoteTrackPublication | undefined; |
@@ -10,3 +10,2 @@ "use strict"; | ||
const RemoteAudioTrack_1 = require("../track/RemoteAudioTrack"); | ||
const RemoteDataTrack_1 = require("../track/RemoteDataTrack"); | ||
const RemoteTrackPublication_1 = require("../track/RemoteTrackPublication"); | ||
@@ -24,3 +23,2 @@ const RemoteVideoTrack_1 = require("../track/RemoteVideoTrack"); | ||
this.videoTracks = new Map(); | ||
this.dataTracks = new Map(); | ||
} | ||
@@ -98,29 +96,2 @@ /** @internal */ | ||
/** @internal */ | ||
addSubscribedDataTrack(dataChannel, sid, name) { | ||
const track = new RemoteDataTrack_1.RemoteDataTrack(sid, name, dataChannel); | ||
let publication = this.getTrackPublication(sid); | ||
if (!publication) { | ||
publication = new RemoteTrackPublication_1.RemoteTrackPublication(Track_1.Track.Kind.Data, sid, name); | ||
publication.setTrack(track); | ||
this.addTrackPublication(publication); | ||
// only send this after metadata is filled in, which indicates the track | ||
// is published AFTER client connected to room | ||
if (this.hasMetadata) { | ||
this.emit(events_1.ParticipantEvent.TrackPublished, publication); | ||
} | ||
} | ||
else { | ||
publication.setTrack(track); | ||
} | ||
track.on(events_1.TrackEvent.Message, (data) => { | ||
// forward this | ||
this.emit(events_1.ParticipantEvent.TrackMessage, data, track); | ||
}); | ||
dataChannel.onclose = (ev) => { | ||
this.emit(events_1.ParticipantEvent.TrackUnsubscribed, track, publication); | ||
}; | ||
this.emit(events_1.ParticipantEvent.TrackSubscribed, track, publication); | ||
return publication; | ||
} | ||
/** @internal */ | ||
get hasMetadata() { | ||
@@ -188,5 +159,2 @@ return !!this.participantInfo; | ||
break; | ||
case Track_1.Track.Kind.Data: | ||
this.dataTracks.delete(sid); | ||
break; | ||
} | ||
@@ -193,0 +161,0 @@ // also send unsubscribe, if track is actively subscribed |
@@ -47,3 +47,2 @@ /// <reference types="node" /> | ||
private onTrackAdded; | ||
private onDataChannelAdded; | ||
private handleDisconnect; | ||
@@ -53,2 +52,3 @@ private handleParticipantUpdates; | ||
private handleSpeakerUpdate; | ||
private handleDataPacket; | ||
private getOrCreateParticipant; | ||
@@ -55,0 +55,0 @@ /** @internal */ |
@@ -94,2 +94,40 @@ "use strict"; | ||
}); | ||
this.handleSpeakerUpdate = (speakers) => { | ||
const activeSpeakers = []; | ||
const seenSids = {}; | ||
speakers.forEach((speaker) => { | ||
seenSids[speaker.sid] = true; | ||
if (speaker.sid === this.localParticipant.sid) { | ||
this.localParticipant.audioLevel = speaker.level; | ||
activeSpeakers.push(this.localParticipant); | ||
} | ||
else { | ||
const p = this.participants.get(speaker.sid); | ||
if (p) { | ||
p.audioLevel = speaker.level; | ||
activeSpeakers.push(p); | ||
} | ||
} | ||
}); | ||
if (!seenSids[this.localParticipant.sid]) { | ||
this.localParticipant.audioLevel = 0; | ||
} | ||
this.participants.forEach((p) => { | ||
if (!seenSids[p.sid]) { | ||
p.audioLevel = 0; | ||
} | ||
}); | ||
this.activeSpeakers = activeSpeakers; | ||
this.emit(events_2.RoomEvent.ActiveSpeakersChanged, activeSpeakers); | ||
}; | ||
this.handleDataPacket = (userPacket, kind) => { | ||
// find the participant | ||
const participant = this.participants.get(userPacket.participantSid); | ||
if (!participant) { | ||
return; | ||
} | ||
this.emit(events_2.RoomEvent.DataReceived, userPacket.payload, participant, kind); | ||
// also emit on the participant | ||
participant.emit(events_2.ParticipantEvent.DataReceived, userPacket.payload, kind); | ||
}; | ||
this.participants = new Map(); | ||
@@ -100,5 +138,2 @@ this.engine = new RTCEngine_1.RTCEngine(client, config); | ||
}); | ||
this.engine.on(events_2.EngineEvent.DataChannelAdded, (dataChannel) => { | ||
this.onDataChannelAdded(dataChannel); | ||
}); | ||
this.engine.on(events_2.EngineEvent.Disconnected, (reason) => { | ||
@@ -110,5 +145,4 @@ this.handleDisconnect(); | ||
}); | ||
this.engine.on(events_2.EngineEvent.SpeakersUpdate, (speakers) => { | ||
this.handleSpeakerUpdate(speakers); | ||
}); | ||
this.engine.on(events_2.EngineEvent.SpeakersUpdate, this.handleSpeakerUpdate); | ||
this.engine.on(events_2.EngineEvent.DataPacketReceived, this.handleDataPacket); | ||
} | ||
@@ -133,7 +167,2 @@ /** | ||
} | ||
onDataChannelAdded(dataChannel) { | ||
const [participantId, trackId, name] = utils_1.unpackDataTrackLabel(dataChannel.label); | ||
const participant = this.getOrCreateParticipant(participantId); | ||
participant.addSubscribedDataTrack(dataChannel, trackId, name); | ||
} | ||
handleDisconnect() { | ||
@@ -181,30 +210,2 @@ this.participants.clear(); | ||
} | ||
handleSpeakerUpdate(speakers) { | ||
const activeSpeakers = []; | ||
const seenSids = {}; | ||
speakers.forEach((speaker) => { | ||
seenSids[speaker.sid] = true; | ||
if (speaker.sid === this.localParticipant.sid) { | ||
this.localParticipant.audioLevel = speaker.level; | ||
activeSpeakers.push(this.localParticipant); | ||
} | ||
else { | ||
const p = this.participants.get(speaker.sid); | ||
if (p) { | ||
p.audioLevel = speaker.level; | ||
activeSpeakers.push(p); | ||
} | ||
} | ||
}); | ||
if (!seenSids[this.localParticipant.sid]) { | ||
this.localParticipant.audioLevel = 0; | ||
} | ||
this.participants.forEach((p) => { | ||
if (!seenSids[p.sid]) { | ||
p.audioLevel = 0; | ||
} | ||
}); | ||
this.activeSpeakers = activeSpeakers; | ||
this.emit(events_2.RoomEvent.ActiveSpeakersChanged, activeSpeakers); | ||
} | ||
getOrCreateParticipant(id, info) { | ||
@@ -237,5 +238,2 @@ let participant = this.participants.get(id); | ||
}); | ||
participant.on(events_2.ParticipantEvent.TrackMessage, (data, track) => { | ||
this.emit(events_2.RoomEvent.TrackMessage, data, track, participant); | ||
}); | ||
participant.on(events_2.ParticipantEvent.TrackSubscriptionFailed, (sid) => { | ||
@@ -242,0 +240,0 @@ this.emit(events_2.RoomEvent.TrackSubscriptionFailed, sid, participant); |
@@ -14,3 +14,4 @@ /// <reference types="node" /> | ||
useLegacy: boolean; | ||
privateDC?: RTCDataChannel; | ||
lossyDC?: RTCDataChannel; | ||
reliableDC?: RTCDataChannel; | ||
rtcConnected: boolean; | ||
@@ -31,2 +32,3 @@ iceConnected: boolean; | ||
private configure; | ||
private handleDataMessage; | ||
private handleWSClose; | ||
@@ -33,0 +35,0 @@ private negotiate; |
@@ -24,3 +24,4 @@ "use strict"; | ||
const utils_1 = require("./utils"); | ||
const placeholderDataChannel = '_private'; | ||
const lossyDataChannel = '_lossy'; | ||
const reliableDataChannel = '_reliable'; | ||
const maxWSRetries = 10; | ||
@@ -33,2 +34,13 @@ class RTCEngine extends events_1.EventEmitter { | ||
this.pendingTrackResolvers = {}; | ||
this.handleDataMessage = (message) => { | ||
// decode | ||
const dp = livekit_rtc_1.DataPacket.decode(new Uint8Array(message.data)); | ||
if (dp.speaker) { | ||
// dispatch speaker updates | ||
this.emit(events_2.EngineEvent.SpeakersUpdate, dp.speaker.speakers); | ||
} | ||
else if (dp.user) { | ||
this.emit(events_2.EngineEvent.DataPacketReceived, dp.user, dp.kind); | ||
} | ||
}; | ||
// websocket reconnect behavior. if websocket is interrupted, and the PeerConnection | ||
@@ -194,8 +206,14 @@ // continues to work, we can reconnect to websocket to continue the session | ||
}; | ||
this.subscriber.pc.ondatachannel = (ev) => { | ||
this.emit(events_2.EngineEvent.DataChannelAdded, ev.channel); | ||
}; | ||
} | ||
// always have a blank data channel, to ensure there isn't an empty ice-ufrag | ||
this.privateDC = this.publisher.pc.createDataChannel(placeholderDataChannel); | ||
// data channels | ||
this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, { | ||
// will drop older packets that arrive | ||
ordered: true, | ||
maxRetransmits: 1, | ||
}); | ||
this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, { | ||
ordered: true, | ||
}); | ||
this.lossyDC.onmessage = this.handleDataMessage; | ||
this.reliableDC.onmessage = this.handleDataMessage; | ||
// configure signaling client | ||
@@ -202,0 +220,0 @@ this.client.onAnswer = (sd) => __awaiter(this, void 0, void 0, function* () { |
@@ -5,3 +5,2 @@ "use strict"; | ||
const LocalAudioTrack_1 = require("./LocalAudioTrack"); | ||
const LocalDataTrack_1 = require("./LocalDataTrack"); | ||
const LocalVideoTrack_1 = require("./LocalVideoTrack"); | ||
@@ -16,3 +15,3 @@ const TrackPublication_1 = require("./TrackPublication"); | ||
get isMuted() { | ||
if (!this.track || this.track instanceof LocalDataTrack_1.LocalDataTrack) { | ||
if (!this.track) { | ||
return false; | ||
@@ -19,0 +18,0 @@ } |
@@ -29,10 +29,1 @@ import { VideoCodec, VideoEncoding } from '../../options'; | ||
} | ||
/** | ||
* Options when publishing data tracks | ||
*/ | ||
export interface LocalDataTrackOptions { | ||
name?: string; | ||
maxPacketLifeTime?: number; | ||
maxRetransmits?: number; | ||
ordered?: boolean; | ||
} |
@@ -16,4 +16,3 @@ /// <reference types="node" /> | ||
Audio = "audio", | ||
Video = "video", | ||
Data = "data" | ||
Video = "video" | ||
} | ||
@@ -20,0 +19,0 @@ type SID = string; |
@@ -19,3 +19,2 @@ "use strict"; | ||
Kind["Video"] = "video"; | ||
Kind["Data"] = "data"; | ||
})(Kind = Track.Kind || (Track.Kind = {})); | ||
@@ -29,4 +28,2 @@ /** @internal */ | ||
return livekit_models_1.TrackType.VIDEO; | ||
case Kind.Data: | ||
return livekit_models_1.TrackType.DATA; | ||
} | ||
@@ -42,4 +39,2 @@ } | ||
return Kind.Video; | ||
case livekit_models_1.TrackType.DATA: | ||
return Kind.Data; | ||
} | ||
@@ -46,0 +41,0 @@ } |
import { AudioTrack } from './AudioTrack'; | ||
import { LocalAudioTrack } from './LocalAudioTrack'; | ||
import { LocalDataTrack } from './LocalDataTrack'; | ||
import { LocalVideoTrack } from './LocalVideoTrack'; | ||
import { RemoteAudioTrack } from './RemoteAudioTrack'; | ||
import { RemoteDataTrack } from './RemoteDataTrack'; | ||
import { RemoteVideoTrack } from './RemoteVideoTrack'; | ||
import { VideoTrack } from './VideoTrack'; | ||
export declare type LocalTrack = LocalAudioTrack | LocalVideoTrack | LocalDataTrack; | ||
export declare type RemoteTrack = RemoteAudioTrack | RemoteVideoTrack | RemoteDataTrack; | ||
export declare type LocalTrack = LocalAudioTrack | LocalVideoTrack; | ||
export declare type RemoteTrack = RemoteAudioTrack | RemoteVideoTrack; | ||
export declare type MediaTrack = AudioTrack | VideoTrack; |
export declare function unpackStreamId(packed: string): string[]; | ||
export declare function unpackDataTrackLabel(packed: string): string[]; | ||
export declare function useLegacyAPI(): boolean; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useLegacyAPI = exports.unpackDataTrackLabel = exports.unpackStreamId = void 0; | ||
exports.useLegacyAPI = exports.unpackStreamId = void 0; | ||
const separator = '|'; | ||
@@ -13,10 +13,2 @@ function unpackStreamId(packed) { | ||
exports.unpackStreamId = unpackStreamId; | ||
function unpackDataTrackLabel(packed) { | ||
const parts = packed.split(separator); | ||
if (parts.length !== 3) { | ||
return ['', '', '']; | ||
} | ||
return [parts[0], parts[1], parts[2]]; | ||
} | ||
exports.unpackDataTrackLabel = unpackDataTrackLabel; | ||
function useLegacyAPI() { | ||
@@ -23,0 +15,0 @@ // react native is using old stream based API |
@@ -1,2 +0,2 @@ | ||
export declare const version = "0.6.7"; | ||
export declare const protocolVersion = 1; | ||
export declare const version = "0.7.0"; | ||
export declare const protocolVersion = 2; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.protocolVersion = exports.version = void 0; | ||
exports.version = '0.6.7'; | ||
exports.protocolVersion = 1; | ||
exports.version = '0.7.0'; | ||
exports.protocolVersion = 2; | ||
//# sourceMappingURL=version.js.map |
@@ -6,3 +6,2 @@ import { | ||
LocalAudioTrack, | ||
LocalDataTrack, | ||
LocalTrack, | ||
@@ -13,3 +12,2 @@ LocalVideoTrack, | ||
ParticipantEvent, | ||
RemoteDataTrack, | ||
RemoteParticipant, | ||
@@ -23,2 +21,3 @@ RemoteTrack, | ||
} from '../src/index'; | ||
import { DataPacket_Kind } from '../src/proto/livekit_rtc'; | ||
@@ -94,11 +93,8 @@ let $ = function (id: string) { | ||
function handleMessage( | ||
msg: string | ArrayBuffer, | ||
track: RemoteDataTrack, | ||
participant: RemoteParticipant | ||
) { | ||
if (track.name === 'chat') { | ||
const chat = <HTMLTextAreaElement>$('chat'); | ||
chat.value += `${participant.identity}: ${msg}\n`; | ||
} | ||
const encoder = new TextEncoder(); | ||
const decoder = new TextDecoder(); | ||
function handleData(msg: Uint8Array, participant: RemoteParticipant) { | ||
const str = decoder.decode(msg); | ||
const chat = <HTMLTextAreaElement>$('chat'); | ||
chat.value += `${participant.identity}: ${str}\n`; | ||
} | ||
@@ -152,6 +148,3 @@ | ||
if (!publication.isSubscribed) return; | ||
if (publication.track! instanceof RemoteDataTrack) { | ||
} else { | ||
trackSubscribed(div, publication.track!, participant); | ||
} | ||
trackSubscribed(div, publication.track!, participant); | ||
}); | ||
@@ -167,6 +160,2 @@ } | ||
let currentRoom: Room; | ||
const chatTrack: LocalDataTrack = new LocalDataTrack({ | ||
name: 'chat', | ||
ordered: true, | ||
}); | ||
let videoTrack: LocalVideoTrack | undefined; | ||
@@ -204,3 +193,3 @@ let audioTrack: LocalAudioTrack; | ||
.on(RoomEvent.ParticipantDisconnected, participantDisconnected) | ||
.on(RoomEvent.TrackMessage, handleMessage) | ||
.on(RoomEvent.DataReceived, handleData) | ||
.on(RoomEvent.ActiveSpeakersChanged, handleSpeakerChanged) | ||
@@ -220,4 +209,2 @@ .on(RoomEvent.Disconnected, () => { | ||
room.localParticipant.publishTrack(chatTrack); | ||
appendLog('room participants', room.participants.keys()); | ||
@@ -291,4 +278,7 @@ room.participants.forEach((participant) => { | ||
if (textField.value) { | ||
chatTrack.send(textField.value); | ||
(<HTMLTextAreaElement>$('chat')).value += `me: ${textField.value}\n`; | ||
const msg = encoder.encode(textField.value); | ||
currentRoom.localParticipant.publishData(msg, DataPacket_Kind.RELIABLE); | ||
(<HTMLTextAreaElement>( | ||
$('chat') | ||
)).value += `${currentRoom.localParticipant.identity} (me): ${textField.value}\n`; | ||
textField.value = ''; | ||
@@ -295,0 +285,0 @@ } |
{ | ||
"name": "livekit-client", | ||
"version": "0.6.7", | ||
"version": "0.7.0", | ||
"description": "JavaScript/TypeScript client SDK for LiveKit", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
574602
9258