Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1a5a966

Browse files
authored
Defer publishing until signal is connected (#1465)
1 parent 6962f52 commit 1a5a966

File tree

5 files changed

+56
-8
lines changed

5 files changed

+56
-8
lines changed

.changeset/eight-horses-raise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"livekit-client": minor
3+
---
4+
5+
Defer publishing until signal is connected

examples/demo/demo.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,6 @@ const appActions = {
235235
appendLog(`signal connection established in ${signalConnectionTime}ms`);
236236
// speed up publishing by starting to publish before it's fully connected
237237
// publishing is accepted as soon as signal connection has established
238-
if (shouldPublish) {
239-
await room.localParticipant.enableCameraAndMicrophone();
240-
appendLog(`tracks published in ${Date.now() - startTime}ms`);
241-
updateButtonsForPublishState();
242-
}
243238
})
244239
.on(RoomEvent.ParticipantEncryptionStatusChanged, () => {
245240
updateButtonsForPublishState();
@@ -353,8 +348,19 @@ const appActions = {
353348
if ((<HTMLInputElement>$('e2ee')).checked) {
354349
await room.setE2EEEnabled(true);
355350
}
356-
357-
await room.connect(url, token, connectOptions);
351+
const publishPromise = new Promise<void>(async (resolve, reject) => {
352+
try {
353+
if (shouldPublish) {
354+
await room.localParticipant.enableCameraAndMicrophone();
355+
appendLog(`tracks published in ${Date.now() - startTime}ms`);
356+
updateButtonsForPublishState();
357+
}
358+
resolve();
359+
} catch (error) {
360+
reject(error);
361+
}
362+
});
363+
await Promise.all([room.connect(url, token, connectOptions), publishPromise]);
358364
const elapsed = Date.now() - startTime;
359365
appendLog(
360366
`successfully connected to ${room.name} in ${Math.round(elapsed)}ms`,

src/room/RTCEngine.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
248248
}
249249

250250
this.clientConfiguration = joinResponse.clientConfiguration;
251+
// emit signal connected event after a short delay to allow for join response to be processed on room
252+
setTimeout(() => {
253+
this.emit(EngineEvent.SignalConnected);
254+
}, 10);
251255
return joinResponse;
252256
} catch (e) {
253257
if (e instanceof ConnectionError) {
@@ -1500,6 +1504,7 @@ export type EngineEventCallbacks = {
15001504
remoteMute: (trackSid: string, muted: boolean) => void;
15011505
offline: () => void;
15021506
signalRequestResponse: (response: RequestResponse) => void;
1507+
signalConnected: () => void;
15031508
};
15041509

15051510
function supportOptionalDatachannel(protocol: number | undefined): boolean {

src/room/events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ export enum EngineEvent {
562562
LocalTrackSubscribed = 'localTrackSubscribed',
563563
Offline = 'offline',
564564
SignalRequestResponse = 'signalRequestResponse',
565+
SignalConnected = 'signalConnected',
565566
}
566567

567568
export enum TrackEvent {

src/room/participant/LocalParticipant.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
UserPacket,
2929
protoInt64,
3030
} from '@livekit/protocol';
31+
import { SignalConnectionState } from '../../api/SignalClient';
3132
import type { InternalRoomOptions } from '../../options';
3233
import { PCTransportState } from '../PCTransportManager';
3334
import type RTCEngine from '../RTCEngine';
@@ -866,7 +867,37 @@ export default class LocalParticipant extends Participant {
866867
if (opts.source) {
867868
track.source = opts.source;
868869
}
869-
const publishPromise = this.publish(track, opts, isStereo);
870+
const publishPromise = new Promise<LocalTrackPublication>(async (resolve, reject) => {
871+
try {
872+
if (this.engine.client.currentState !== SignalConnectionState.CONNECTED) {
873+
this.log.debug('deferring track publication until signal is connected', {
874+
...this.logContext,
875+
track: getLogContextFromTrack(track),
876+
});
877+
const onSignalConnected = async () => {
878+
return this.publish(track, opts, isStereo).then(resolve).catch(reject);
879+
};
880+
setTimeout(() => {
881+
this.engine.off(EngineEvent.SignalConnected, onSignalConnected);
882+
reject(
883+
new PublishTrackError(
884+
'publishing rejected as engine not connected within timeout',
885+
408,
886+
),
887+
);
888+
}, 15_000);
889+
this.engine.once(EngineEvent.SignalConnected, onSignalConnected);
890+
this.engine.on(EngineEvent.Closing, () => {
891+
this.engine.off(EngineEvent.SignalConnected, onSignalConnected);
892+
reject(new PublishTrackError('publishing rejected as engine closed', 499));
893+
});
894+
} else {
895+
return await this.publish(track, opts, isStereo);
896+
}
897+
} catch (e) {
898+
reject(e);
899+
}
900+
});
870901
this.pendingPublishPromises.set(track, publishPromise);
871902
try {
872903
const publication = await publishPromise;

0 commit comments

Comments
 (0)