Skip to content

Commit

Permalink
feat(media-helpers): update media helpers APIs (#4090)
Browse files Browse the repository at this point in the history
  • Loading branch information
brycetham authored Feb 11, 2025
1 parent ceeffb8 commit 61818c9
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 54 deletions.
2 changes: 1 addition & 1 deletion packages/@webex/media-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"deploy:npm": "yarn npm publish"
},
"dependencies": {
"@webex/internal-media-core": "2.12.3",
"@webex/internal-media-core": "2.14.0",
"@webex/ts-events": "^1.1.0",
"@webex/web-media-effects": "2.19.0"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/@webex/media-helpers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ export {
LocalCameraStream,
createMicrophoneStream,
createCameraStream,
createCameraAndMicrophoneStreams,
createDisplayStream,
createDisplayStreamWithAudio,
createDisplayMedia,
type VideoContentHint,
} from './webrtc-core';

Expand Down
54 changes: 43 additions & 11 deletions packages/@webex/media-helpers/src/webrtc-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import {
AudioDeviceConstraints,
createCameraStream as wcmeCreateCameraStream,
createCameraAndMicrophoneStreams as wcmeCreateCameraAndMicrophoneStreams,
createDisplayMedia as wcmeCreateDisplayMedia,
createDisplayStream as wcmeCreateDisplayStream,
createDisplayStreamWithAudio as wcmeCreateDisplayStreamWithAudio,
createMicrophoneStream as wcmeCreateMicrophoneStream,
LocalDisplayStream,
LocalSystemAudioStream,
LocalMicrophoneStream as WcmeLocalMicrophoneStream,
LocalCameraStream as WcmeLocalCameraStream,
VideoContentHint,
VideoDeviceConstraints,
} from '@webex/internal-media-core';
import {AddEvents, TypedEvent, WithEventsDummyType} from '@webex/ts-events';
Expand Down Expand Up @@ -138,17 +141,6 @@ class _LocalCameraStream extends WcmeLocalCameraStream {
}
}

export const createMicrophoneStream = (constraints?: AudioDeviceConstraints) =>
wcmeCreateMicrophoneStream(LocalMicrophoneStream, constraints);

export const createCameraStream = (constraints?: VideoDeviceConstraints) =>
wcmeCreateCameraStream(LocalCameraStream, constraints);

export const createDisplayStream = () => wcmeCreateDisplayStream(LocalDisplayStream);

export const createDisplayStreamWithAudio = () =>
wcmeCreateDisplayStreamWithAudio(LocalDisplayStream, LocalSystemAudioStream);

export const LocalMicrophoneStream = AddEvents<
typeof _LocalMicrophoneStream,
LocalMicrophoneStreamEvents
Expand All @@ -162,3 +154,43 @@ export const LocalCameraStream = AddEvents<typeof _LocalCameraStream, LocalCamer
);

export type LocalCameraStream = _LocalCameraStream & WithEventsDummyType<LocalCameraStreamEvents>;

export const createMicrophoneStream = (constraints?: AudioDeviceConstraints) =>
wcmeCreateMicrophoneStream(LocalMicrophoneStream, constraints);

export const createCameraStream = (constraints?: VideoDeviceConstraints) =>
wcmeCreateCameraStream(LocalCameraStream, constraints);

export const createCameraAndMicrophoneStreams = (constraints?: {
video?: VideoDeviceConstraints;
audio?: AudioDeviceConstraints;
}) => wcmeCreateCameraAndMicrophoneStreams(LocalCameraStream, LocalMicrophoneStream, constraints);

export const createDisplayStream = (videoContentHint?: VideoContentHint) =>
wcmeCreateDisplayStream(LocalDisplayStream, videoContentHint);

export const createDisplayStreamWithAudio = (videoContentHint?: VideoContentHint) =>
wcmeCreateDisplayStreamWithAudio(LocalDisplayStream, LocalSystemAudioStream, videoContentHint);

export const createDisplayMedia = (
options: {
video: {
constraints?: VideoDeviceConstraints;
videoContentHint?: VideoContentHint;
preferCurrentTab?: boolean;
selfBrowserSurface?: 'include' | 'exclude';
surfaceSwitching?: 'include' | 'exclude';
monitorTypeSurfaces?: 'include' | 'exclude';
};
audio?: {
constraints?: AudioDeviceConstraints;
systemAudio?: 'include' | 'exclude';
};
} = {video: {}}
) =>
wcmeCreateDisplayMedia({
video: {displayStreamConstructor: LocalDisplayStream, ...options?.video},
audio: options?.audio
? {systemAudioStreamConstructor: LocalSystemAudioStream, ...options.audio}
: undefined,
});
151 changes: 128 additions & 23 deletions packages/@webex/media-helpers/test/unit/spec/webrtc-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {
LocalSystemAudioStream,
createCameraStream,
createMicrophoneStream,
createCameraAndMicrophoneStreams,
createDisplayStream,
createDisplayStreamWithAudio,
createDisplayMedia,
} from '@webex/media-helpers';
import * as InternalMediaCoreModule from '@webex/internal-media-core';

Expand Down Expand Up @@ -115,36 +117,139 @@ describe('media-helpers', () => {
await checkSetServerMuted(false, false, false);
});
});
})
);

describe('#wcmeCreateMicrophoneStream, #wcmeCreateCameraStream', () => {
it('checks creating tracks', async () => {
const constraints = {deviceId: 'abc'};

const spy = sinon.stub(InternalMediaCoreModule, spyFn).returns('something');
const result = await createFn(constraints);
const functionsToTest = [
{
title: 'createCameraStream',
createFn: createCameraStream,
spyFn: 'createCameraStream',
classConstructors: [LocalCameraStream],
additionalOptions: {fake: 'constraints'},
},
{
title: 'createMicrophoneStream',
createFn: createMicrophoneStream,
spyFn: 'createMicrophoneStream',
classConstructors: [LocalMicrophoneStream],
additionalOptions: {fake: 'constraints'},
},
{
title: 'createCameraAndMicrophoneStreams',
createFn: createCameraAndMicrophoneStreams,
spyFn: 'createCameraAndMicrophoneStreams',
classConstructors: [LocalCameraStream, LocalMicrophoneStream],
additionalOptions: {video: {fake: 'constraints'}, audio: {fake: 'constraints'}},
},
{
title: 'createDisplayStream',
createFn: createDisplayStream,
spyFn: 'createDisplayStream',
classConstructors: [LocalDisplayStream],
additionalOptions: 'motion',
},
{
title: 'createDisplayStreamWithAudio',
createFn: createDisplayStreamWithAudio,
spyFn: 'createDisplayStreamWithAudio',
classConstructors: [LocalDisplayStream, LocalSystemAudioStream],
additionalOptions: 'motion',
},
];
functionsToTest.forEach(({title, createFn, spyFn, classConstructors, additionalOptions}) => {
describe(title, () => {
let wcmeCreateStreamSpy;
beforeEach(() => {
sinon.restore();
wcmeCreateStreamSpy = sinon.stub(InternalMediaCoreModule, spyFn);
});

assert.equal(result, 'something');
assert.calledOnceWithExactly(spy, className, constraints);
});
it('can be called without additional options', async () => {
await createFn();
assert.calledOnceWithExactly(wcmeCreateStreamSpy, ...classConstructors, undefined);
});
})
);

describe('createDisplayStream', () => {
it('checks createDisplayStream', async () => {
const spy = sinon.stub(InternalMediaCoreModule, 'createDisplayStream').returns('something');
const result = await createDisplayStream();
assert.equal(result, 'something');
assert.calledOnceWithExactly(spy, LocalDisplayStream);
it('can be called with additional options', async () => {
await createFn(additionalOptions);
assert.calledOnceWithExactly(
wcmeCreateStreamSpy,
...classConstructors,
additionalOptions
);
});
});
});

describe('createDisplayStreamWithAudio', () => {
it('checks createDisplayStreamWithAudio', async () => {
const spy = sinon.stub(InternalMediaCoreModule, 'createDisplayStreamWithAudio').returns('something');
const result = await createDisplayStreamWithAudio();
assert.equal(result, 'something');
assert.calledOnceWithExactly(spy, LocalDisplayStream, LocalSystemAudioStream);
describe('createDisplayMedia', () => {
let wcmeCreateDisplayMediaSpy;
beforeEach(() => {
sinon.restore();
wcmeCreateDisplayMediaSpy = sinon.stub(InternalMediaCoreModule, 'createDisplayMedia');
});

it('can be called with no options', async () => {
await createDisplayMedia();
assert.calledOnceWithExactly(wcmeCreateDisplayMediaSpy, {
video: {displayStreamConstructor: LocalDisplayStream},
audio: undefined,
});
});

it('can be called with just video', async () => {
await createDisplayMedia({video: {}});
assert.calledOnceWithExactly(wcmeCreateDisplayMediaSpy, {
video: {displayStreamConstructor: LocalDisplayStream},
audio: undefined,
});
});

it('can be called with additional video options', async () => {
const options = {
video: {
constraints: {fake: 'constraints'},
videoContentHint: 'motion',
preferCurrentTab: true,
selfBrowserSurface: 'include',
surfaceSwitching: 'include',
monitorTypeSurfaces: 'exclude',
},
};
await createDisplayMedia(options);
assert.calledOnceWithExactly(wcmeCreateDisplayMediaSpy, {
video: {displayStreamConstructor: LocalDisplayStream, ...options.video},
audio: undefined,
});
});

it('can be called with just video and audio', async () => {
await createDisplayMedia({video: {}, audio: {}});
assert.calledOnceWithExactly(wcmeCreateDisplayMediaSpy, {
video: {displayStreamConstructor: LocalDisplayStream},
audio: {systemAudioStreamConstructor: LocalSystemAudioStream},
});
});

it('can be called with additional video and audio options', async () => {
const options = {
video: {
constraints: {fake: 'constraints'},
videoContentHint: 'motion',
preferCurrentTab: true,
selfBrowserSurface: 'include',
surfaceSwitching: 'include',
monitorTypeSurfaces: 'exclude',
},
audio: {
constraints: {fake: 'constraints'},
systemAudio: 'exclude',
},
};
await createDisplayMedia(options);
assert.calledOnceWithExactly(wcmeCreateDisplayMediaSpy, {
video: {displayStreamConstructor: LocalDisplayStream, ...options.video},
audio: {systemAudioStreamConstructor: LocalSystemAudioStream, ...options.audio},
});
});
});
});
Expand Down
2 changes: 1 addition & 1 deletion packages/@webex/plugin-meetings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"dependencies": {
"@webex/common": "workspace:*",
"@webex/event-dictionary-ts": "^1.0.1643",
"@webex/internal-media-core": "2.12.3",
"@webex/internal-media-core": "2.14.0",
"@webex/internal-plugin-conversation": "workspace:*",
"@webex/internal-plugin-device": "workspace:*",
"@webex/internal-plugin-llm": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions packages/@webex/plugin-meetings/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ export {
LocalCameraStream,
createMicrophoneStream,
createCameraStream,
createCameraAndMicrophoneStreams,
createDisplayStream,
createDisplayStreamWithAudio,
createDisplayMedia,
FacingMode,
DisplaySurface,
PresetCameraConstraints,
Expand Down
2 changes: 1 addition & 1 deletion packages/calling/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
},
"dependencies": {
"@types/platform": "1.3.4",
"@webex/internal-media-core": "2.12.3",
"@webex/internal-media-core": "2.14.0",
"@webex/media-helpers": "workspace:*",
"async-mutex": "0.4.0",
"buffer": "6.0.3",
Expand Down
Loading

0 comments on commit 61818c9

Please sign in to comment.