Skip to content

Commit 604a0b9

Browse files
lukasIOboks1971
andauthored
Fix track mapping when single peer connectionis used (#1696)
Co-authored-by: boks1971 <[email protected]>
1 parent 215c3ba commit 604a0b9

7 files changed

Lines changed: 89 additions & 17 deletions

File tree

.changeset/thick-wombats-battle.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"livekit-client": patch
3+
---
4+
5+
Fix track mapping when single peer connectionis used

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
},
5757
"dependencies": {
5858
"@livekit/mutex": "1.1.1",
59-
"@livekit/protocol": "1.42.0",
59+
"@livekit/protocol": "1.42.2",
6060
"events": "^3.3.0",
6161
"jose": "^6.1.0",
6262
"loglevel": "^1.9.2",

pnpm-lock.yaml

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/SignalClient.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,17 @@ export class SignalClient {
124124

125125
onClose?: (reason: string) => void;
126126

127-
onAnswer?: (sd: RTCSessionDescriptionInit, offerId: number) => void;
128-
129-
onOffer?: (sd: RTCSessionDescriptionInit, offerId: number) => void;
127+
onAnswer?: (
128+
sd: RTCSessionDescriptionInit,
129+
offerId: number,
130+
midToTrackId: { [key: string]: string },
131+
) => void;
132+
133+
onOffer?: (
134+
sd: RTCSessionDescriptionInit,
135+
offerId: number,
136+
midToTrackId: { [key: string]: string },
137+
) => void;
130138

131139
// when a new ICE candidate is made available
132140
onTrickle?: (sd: RTCIceCandidateInit, target: SignalTarget) => void;
@@ -715,12 +723,12 @@ export class SignalClient {
715723
if (msg.case === 'answer') {
716724
const sd = fromProtoSessionDescription(msg.value);
717725
if (this.onAnswer) {
718-
this.onAnswer(sd, msg.value.id);
726+
this.onAnswer(sd, msg.value.id, msg.value.midToTrackId);
719727
}
720728
} else if (msg.case === 'offer') {
721729
const sd = fromProtoSessionDescription(msg.value);
722730
if (this.onOffer) {
723-
this.onOffer(sd, msg.value.id);
731+
this.onOffer(sd, msg.value.id, msg.value.midToTrackId);
724732
}
725733
} else if (msg.case === 'trickle') {
726734
const candidate: RTCIceCandidateInit = JSON.parse(msg.value.candidateInit!);

src/room/PCTransportManager.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,16 @@ export class PCTransportManager {
256256
return this.publisher.addTransceiverOfKind(kind, transceiverInit);
257257
}
258258

259+
getMidForReceiver(receiver: RTCRtpReceiver): string | null | undefined {
260+
const transceivers = this.subscriber
261+
? this.subscriber.getTransceivers()
262+
: this.publisher.getTransceivers();
263+
const matchingTransceiver = transceivers.find(
264+
(transceiver) => transceiver.receiver === receiver,
265+
);
266+
return matchingTransceiver?.mid;
267+
}
268+
259269
addPublisherTrack(track: MediaStreamTrack) {
260270
return this.publisher.addTrack(track);
261271
}

src/room/RTCEngine.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
202202

203203
private reliableReceivedState: TTLMap<string, number> = new TTLMap(reliabeReceiveStateTTL);
204204

205+
private midToTrackId: { [key: string]: string } = {};
206+
205207
constructor(private options: InternalRoomOptions) {
206208
super();
207209
this.log = getLogger(options.loggerName ?? LoggerNames.Engine);
@@ -499,15 +501,17 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
499501

500502
private setupSignalClientCallbacks() {
501503
// configure signaling client
502-
this.client.onAnswer = async (sd, offerId) => {
504+
this.client.onAnswer = async (sd, offerId, midToTrackId) => {
503505
if (!this.pcManager) {
504506
return;
505507
}
506508
this.log.debug('received server answer', {
507509
...this.logContext,
508510
RTCSdpType: sd.type,
509511
sdp: sd.sdp,
512+
midToTrackId,
510513
});
514+
this.midToTrackId = midToTrackId;
511515
await this.pcManager.setPublisherAnswer(sd, offerId);
512516
};
513517

@@ -521,11 +525,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
521525
};
522526

523527
// when server creates an offer for the client
524-
this.client.onOffer = async (sd, offerId) => {
528+
this.client.onOffer = async (sd, offerId, midToTrackId) => {
525529
this.latestRemoteOfferId = offerId;
526530
if (!this.pcManager) {
527531
return;
528532
}
533+
this.midToTrackId = midToTrackId;
529534
const answer = await this.pcManager.createSubscriberAnswerFromOffer(sd, offerId);
530535
if (answer) {
531536
this.client.sendAnswer(answer, offerId);
@@ -1629,6 +1634,16 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
16291634
window.removeEventListener('online', this.handleBrowserOnLine);
16301635
}
16311636
}
1637+
1638+
getTrackIdForReceiver(receiver: RTCRtpReceiver): string | undefined {
1639+
const mid = this.pcManager?.getMidForReceiver(receiver);
1640+
if (mid) {
1641+
const match = Object.entries(this.midToTrackId).find(([key]) => key === mid);
1642+
if (match) {
1643+
return match[1];
1644+
}
1645+
}
1646+
}
16321647
}
16331648

16341649
class SignalReconnectError extends Error {}

src/room/Room.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,11 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
13701370
// We'll defer these events until when the room is connected or eventually disconnected.
13711371
if (this.state === ConnectionState.Connecting || this.state === ConnectionState.Reconnecting) {
13721372
const reconnectedHandler = () => {
1373+
this.log.debug('deferring on track for later', {
1374+
mediaTrackId: mediaTrack.id,
1375+
mediaStreamId: stream.id,
1376+
tracksInStream: stream.getTracks().map((track) => track.id),
1377+
});
13731378
this.onTrackAdded(mediaTrack, stream, receiver);
13741379
cleanup();
13751380
};
@@ -1416,6 +1421,28 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
14161421
return;
14171422
}
14181423

1424+
// in single peer connection case, the trackID is locally generated,
1425+
// not the TR_ prefixed one generated by the server,
1426+
// use `mid` to find the appropriate track.
1427+
if (!trackId.startsWith('TR')) {
1428+
const id = this.engine.getTrackIdForReceiver(receiver);
1429+
if (!id) {
1430+
this.log.error(
1431+
`Tried to add a track whose 'sid' could not be found for a participant, that's not present. Sid: ${participantSid}`,
1432+
this.logContext,
1433+
);
1434+
return;
1435+
}
1436+
1437+
trackId = id;
1438+
}
1439+
if (!trackId.startsWith('TR')) {
1440+
this.log.warn(
1441+
`Tried to add a track whose 'sid' could not be determined for a participant, that's not present. Sid: ${participantSid}, streamId: ${streamId}, trackId: ${trackId}`,
1442+
{ ...this.logContext, rpID: participantSid, streamId, trackId },
1443+
);
1444+
}
1445+
14191446
let adaptiveStreamSettings: AdaptiveStreamSettings | undefined;
14201447
if (this.options.adaptiveStream) {
14211448
if (typeof this.options.adaptiveStream === 'object') {
@@ -2541,6 +2568,13 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
25412568
if (event !== RoomEvent.ActiveSpeakersChanged && event !== RoomEvent.TranscriptionReceived) {
25422569
// only extract logContext from arguments in order to avoid logging the whole object tree
25432570
const minimizedArgs = mapArgs(args).filter((arg: unknown) => arg !== undefined);
2571+
if (event === RoomEvent.TrackSubscribed || event === RoomEvent.TrackUnsubscribed) {
2572+
this.log.trace(`subscribe trace: ${event}`, {
2573+
...this.logContext,
2574+
event,
2575+
args: minimizedArgs,
2576+
});
2577+
}
25442578
this.log.debug(`room event ${event}`, { ...this.logContext, event, args: minimizedArgs });
25452579
}
25462580
return super.emit(event, ...args);

0 commit comments

Comments
 (0)