Skip to content

Commit 7fade59

Browse files
author
Aidan Zimmermann
committed
STREAM-1153: update how we access tracks and streams
1 parent a468720 commit 7fade59

3 files changed

Lines changed: 60 additions & 74 deletions

File tree

src/sessions/live-monitoring-session-handler.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export class LiveMonitoringSessionHandler extends BaseSessionHandler {
6464
params.mediaStream.getTracks().forEach((track) => {
6565
addMediaPromise = addMediaPromise.then(() => {
6666
this.sdk.logger.info('Adding screen track to live screen monitoring session', { trackId: track.id, label: track.label, conversationId: session.conversationId, sessionType: this.sessionType });
67-
return session.pc.addTrack(track);
67+
const trackStream = createNewStreamWithTrack(track);
68+
return session.pc.addTrack(track, trackStream);
6869
});
6970
});
7071
await addMediaPromise;
@@ -80,26 +81,22 @@ export class LiveMonitoringSessionHandler extends BaseSessionHandler {
8081
sessionInfo);
8182
}
8283

83-
// Use mediaStreams if provided
84-
if (params.mediaStreams && params.mediaStreams.length > 0) {
85-
this.log('info', `Attaching ${params.mediaStreams.length} media streams to ${videoElements.length} video elements`, sessionInfo);
86-
87-
params.mediaStreams.forEach((mediaStreamItem, index) => {
88-
if (index < videoElements.length) {
89-
const videoElement = videoElements[index];
90-
videoElement.muted = true;
91-
videoElement.autoplay = true;
92-
videoElement.srcObject = mediaStreamItem.stream;
93-
this.log('info', `Attached media stream to video element at index ${index}`, {
94-
streamId: mediaStreamItem.stream.id,
95-
metadata: mediaStreamItem.metadata,
96-
...sessionInfo
97-
});
98-
}
99-
});
100-
84+
// Listen for incoming tracks via peer connection
85+
let streamIndex = 0;
86+
session.pc.ontrack = (event) => {
87+
if (streamIndex < videoElements.length) {
88+
const videoElement = videoElements[streamIndex];
89+
videoElement.muted = true;
90+
videoElement.autoplay = true;
91+
videoElement.srcObject = event.streams[0];
92+
this.log('info', `Attached remote stream to video element at index ${streamIndex}`, {
93+
streamId: event.streams[0].id,
94+
...sessionInfo
95+
});
96+
streamIndex++;
97+
}
10198
session.emit('incomingMedia');
102-
}
99+
};
103100
}
104101

105102
async endSession (conversationId: string, session: IExtendedMediaSession, reason?: Constants.JingleReasonCondition): Promise<void> {

src/types/interfaces.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -667,11 +667,6 @@ export interface IAcceptSessionRequest extends ISdkMediaDeviceIds {
667667
*/
668668
mediaStream?: MediaStream;
669669

670-
/**
671-
* array of media streams with associated metadata
672-
*/
673-
mediaStreams?: { stream: MediaStream; metadata: ScreenRecordingMetadata }[];
674-
675670
/**
676671
* metadata about screens and tracks. This is required for screen recording sessions
677672
*/

test/unit/sessions/live-monitoring-session-handler.test.ts

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,23 @@ describe('acceptSessionForTarget', () => {
142142
.rejects.toThrow('Cannot accept live screen monitoring session without providing a media stream');
143143
});
144144

145-
it('should set outbound stream and add tracks', async () => {
145+
it('should set outbound stream and add tracks with individual streams', async () => {
146146
const mockStream = new MockStream({ video: true });
147147
const session = new MockSession();
148148
const addTrackSpy = jest.fn().mockResolvedValue(null);
149+
const createNewStreamSpy = jest.spyOn(mediaUtils, 'createNewStreamWithTrack').mockReturnValue(new MockStream() as any);
149150
session.pc.addTrack = addTrackSpy;
150151

151152
const params = { mediaStream: mockStream };
152153
await handler.acceptSessionForTarget(session as any, params as any);
153154

154155
expect(session._outboundStream).toBe(mockStream);
156+
expect(createNewStreamSpy).toHaveBeenCalledTimes(mockStream.getTracks().length);
155157
expect(addTrackSpy).toHaveBeenCalledTimes(mockStream.getTracks().length);
158+
// Verify addTrack is called with both track and stream
159+
mockStream.getTracks().forEach((track, index) => {
160+
expect(addTrackSpy).toHaveBeenNthCalledWith(index + 1, track, expect.any(MockStream));
161+
});
156162
});
157163
});
158164

@@ -167,103 +173,91 @@ describe('acceptSessionForObserver', () => {
167173
await expect(handler.acceptSession(session, { conversationId: session.conversationId, liveMonitoringObserver: true, audioElement: document.createElement('audio') })).rejects.toThrowError(/requires videoElements array or videoElement/);
168174
});
169175

170-
it('should attach mediaStreams to video elements when provided', async () => {
176+
it('should set up ontrack event handler for incoming streams', async () => {
171177
const video1 = document.createElement('video');
172178
const video2 = document.createElement('video');
173179
const videoElements = [video1, video2];
174180

175-
const stream1 = new MockStream({ video: true }) as any;
176-
const stream2 = new MockStream({ video: true }) as any;
177-
const metadata1 = { screenId: 'screen1', trackId: 'track1', originX: 0, originY: 0, resolutionX: 1920, resolutionY: 1080, primary: true };
178-
const metadata2 = { screenId: 'screen2', trackId: 'track2', originX: 1920, originY: 0, resolutionX: 1920, resolutionY: 1080, primary: false };
179-
180-
const mediaStreams = [
181-
{ stream: stream1, metadata: metadata1 },
182-
{ stream: stream2, metadata: metadata2 }
183-
];
184-
181+
const mockStream1 = new MockStream({ video: true }) as any;
182+
const mockStream2 = new MockStream({ video: true }) as any;
185183
const emitSpy = jest.spyOn(session, 'emit');
186184

187185
await handler.acceptSession(session, {
188186
conversationId: session.conversationId,
189187
liveMonitoringObserver: true,
190-
videoElements,
191-
mediaStreams
188+
videoElements
192189
});
193190

194-
expect(video1.srcObject).toBe(stream1);
191+
// Verify ontrack handler is set
192+
expect(session.pc.ontrack).toBeDefined();
193+
194+
// Simulate track events
195+
session.pc.ontrack({ streams: [mockStream1] } as any);
196+
session.pc.ontrack({ streams: [mockStream2] } as any);
197+
198+
expect(video1.srcObject).toBe(mockStream1);
195199
expect(video1.muted).toBe(true);
196200
expect(video1.autoplay).toBe(true);
197201

198-
expect(video2.srcObject).toBe(stream2);
202+
expect(video2.srcObject).toBe(mockStream2);
199203
expect(video2.muted).toBe(true);
200204
expect(video2.autoplay).toBe(true);
201205

202206
expect(emitSpy).toHaveBeenCalledWith('incomingMedia');
207+
expect(emitSpy).toHaveBeenCalledTimes(2);
203208
});
204209

205210
it('should only attach streams up to the number of available video elements', async () => {
206211
const video1 = document.createElement('video');
207212
const videoElements = [video1]; // Only one video element
208213

209-
const stream1 = new MockStream({ video: true }) as any;
210-
const stream2 = new MockStream({ video: true }) as any;
211-
const metadata = { screenId: 'screen1', trackId: 'track1', originX: 0, originY: 0, resolutionX: 1920, resolutionY: 1080, primary: true };
212-
213-
const mediaStreams = [
214-
{ stream: stream1, metadata },
215-
{ stream: stream2, metadata } // This won't be attached
216-
];
214+
const mockStream1 = new MockStream({ video: true }) as any;
215+
const mockStream2 = new MockStream({ video: true }) as any;
217216

218217
await handler.acceptSession(session, {
219218
conversationId: session.conversationId,
220219
liveMonitoringObserver: true,
221-
videoElements,
222-
mediaStreams
220+
videoElements
223221
});
224222

225-
expect(video1.srcObject).toBe(stream1);
226-
// stream2 should not be attached anywhere
223+
// Simulate track events
224+
session.pc.ontrack({ streams: [mockStream1] } as any);
225+
session.pc.ontrack({ streams: [mockStream2] } as any);
226+
227+
expect(video1.srcObject).toBe(mockStream1);
228+
// Second stream should not be attached since no more video elements
227229
});
228230

229-
it('should use videoElement field when no videoElements provided ', async () => {
231+
it('should use videoElement field when no videoElements provided', async () => {
230232
const videoElement = document.createElement('video');
231-
232-
const stream1 = new MockStream({ video: true }) as any;
233-
const stream2 = new MockStream({ video: true }) as any;
234-
const metadata = { screenId: 'screen1', trackId: 'track1', originX: 0, originY: 0, resolutionX: 1920, resolutionY: 1080, primary: true };
235-
236-
const mediaStreams = [
237-
{ stream: stream1, metadata },
238-
{ stream: stream2, metadata } // This won't be attached
239-
];
233+
const mockStream = new MockStream({ video: true }) as any;
240234

241235
await handler.acceptSession(session, {
242236
conversationId: session.conversationId,
243237
liveMonitoringObserver: true,
244-
videoElement,
245-
mediaStreams
238+
videoElement
246239
});
247240

248-
expect(videoElement.srcObject).toBe(stream1);
249-
// stream2 should not be attached anywhere
241+
// Simulate track event
242+
session.pc.ontrack({ streams: [mockStream] } as any);
243+
244+
expect(videoElement.srcObject).toBe(mockStream);
250245
});
251246

252247
it('should use default video element when no videoElements or videoElement provided', async () => {
253248
const defaultVideo = document.createElement('video');
254249
mockSdk._config.defaults!.videoElement = defaultVideo;
255-
256-
const stream = new MockStream({ video: true }) as any;
257-
const metadata = { screenId: 'screen1', trackId: 'track1', originX: 0, originY: 0, resolutionX: 1920, resolutionY: 1080, primary: true };
258-
const mediaStreams = [{ stream, metadata }];
250+
const mockStream = new MockStream({ video: true }) as any;
259251

260252
await handler.acceptSession(session, {
261253
conversationId: session.conversationId,
262-
liveMonitoringObserver: true,
263-
mediaStreams
254+
liveMonitoringObserver: true
264255
});
265256

266-
expect(defaultVideo.srcObject).toBe(stream);
257+
// Simulate track event
258+
session.pc.ontrack({ streams: [mockStream] } as any);
259+
260+
expect(defaultVideo.srcObject).toBe(mockStream);
267261
});
268262
});
269263

0 commit comments

Comments
 (0)