Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: convert track-based classes into stream-based classes #59

Merged
merged 9 commits into from
Jul 19, 2023
4 changes: 3 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"language": "en",
"words": [
"Alboe",
"appliable",
"bitauth",
"bitjson",
"cimg",
Expand Down Expand Up @@ -32,8 +33,9 @@
"transpiled",
"typedoc",
"untracked",
"WCME",
"Wcme",
"WCME",
"webex",
"webrtc"
],
"flagWords": [],
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
"watch": "rollup -c ./rollup.config.js -w"
},
"dependencies": {
"@webex/ts-events": "^1.1.0",
"@webex/web-media-effects": "^2.7.0",
"events": "^3.3.0",
"js-logger": "^1.6.1",
"typed-emitter": "^2.1.0",
Expand Down
107 changes: 77 additions & 30 deletions src/device/device-management.spec.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,61 @@
import * as media from '../media';
import { LocalCameraTrack } from '../media/local-camera-track';
import { LocalDisplayTrack } from '../media/local-display-track';
import { LocalMicrophoneTrack } from '../media/local-microphone-track';
import { LocalCameraStream } from '../media/local-camera-stream';
import { LocalDisplayStream } from '../media/local-display-stream';
import { LocalMicrophoneStream } from '../media/local-microphone-stream';
import { LocalSystemAudioStream } from '../media/local-system-audio-stream';
import { createBrowserMock } from '../mocks/create-browser-mock';
import MediaStreamStub from '../mocks/media-stream-stub';
import { mocked } from '../mocks/mock';
import { createCameraTrack, createDisplayTrack, createMicrophoneTrack } from './device-management';
import { createMockedStream, createMockedStreamWithAudio } from '../util/test-utils';
import {
createCameraStream,
createDisplayStream,
createDisplayStreamWithAudio,
createMicrophoneStream,
} from './device-management';

jest.mock('../mocks/media-stream-stub');

describe('Device Management', () => {
// const mockedMedia = createBrowserMock(media);
createBrowserMock(MediaStreamStub, 'MediaStream');

const mockStream = mocked(new MediaStream());
const track = new MediaStreamTrack();
mockStream.getTracks.mockReturnValue([track]);
const mockStream = createMockedStream();

describe('createMicrophoneTrack', () => {
describe('createMicrophoneStream', () => {
jest
.spyOn(media, 'getUserMedia')
.mockImplementation()
.mockReturnValue(Promise.resolve(mockStream as unknown as MediaStream));

it('should call getUserMedia', async () => {
expect.assertions(1);

await createMicrophoneTrack(LocalMicrophoneTrack, { deviceId: 'test-device-id' });
await createMicrophoneStream({ deviceId: 'test-device-id' });
expect(media.getUserMedia).toHaveBeenCalledWith({
audio: {
deviceId: 'test-device-id',
},
});
});

it('should return a LocalMicrophoneTrack instance', async () => {
it('should return a LocalMicrophoneStream instance', async () => {
expect.assertions(1);

const localMicrophoneTrack = await createMicrophoneTrack(LocalMicrophoneTrack, {
const localMicrophoneStream = await createMicrophoneStream({
deviceId: 'test-device-id',
});
expect(localMicrophoneTrack).toBeInstanceOf(LocalMicrophoneTrack);
expect(localMicrophoneStream).toBeInstanceOf(LocalMicrophoneStream);
});
});

describe('createCameraTrack', () => {
describe('createCameraStream', () => {
jest
.spyOn(media, 'getUserMedia')
.mockImplementation()
.mockReturnValue(Promise.resolve(mockStream as unknown as MediaStream));

it('should call getUserMedia', async () => {
expect.assertions(1);

await createCameraTrack(LocalCameraTrack, { deviceId: 'test-device-id' });
await createCameraStream({ deviceId: 'test-device-id' });
expect(media.getUserMedia).toHaveBeenCalledWith({
video: {
deviceId: 'test-device-id',
Expand All @@ -64,7 +66,7 @@ describe('Device Management', () => {
it('should call getUserMedia with constraints', async () => {
expect.assertions(1);

await createCameraTrack(LocalCameraTrack, {
await createCameraStream({
deviceId: 'test-device-id',
aspectRatio: 1.777,
width: 1920,
Expand All @@ -84,42 +86,87 @@ describe('Device Management', () => {
});
});

it('should return a LocalCameraTrack instance', async () => {
it('should return a LocalCameraStream instance', async () => {
expect.assertions(1);

const localCameraTrack = await createCameraTrack(LocalCameraTrack, {
const localCameraStream = await createCameraStream({
deviceId: 'test-device-id',
});
expect(localCameraTrack).toBeInstanceOf(LocalCameraTrack);
expect(localCameraStream).toBeInstanceOf(LocalCameraStream);
});
});

describe('createDisplayTrack', () => {
describe('createDisplayStream', () => {
jest
.spyOn(media, 'getDisplayMedia')
.mockImplementation()
.mockReturnValue(Promise.resolve(mockStream as unknown as MediaStream));

it('should call getDisplayMedia', async () => {
expect.assertions(1);

await createDisplayTrack(LocalDisplayTrack);
await createDisplayStream();
expect(media.getDisplayMedia).toHaveBeenCalledWith({ video: true });
});

it('should return a LocalDisplayTrack instance', async () => {
it('should return a LocalDisplayStream instance', async () => {
expect.assertions(2);

const localDisplayTrack = await createDisplayTrack(LocalDisplayTrack);
expect(localDisplayTrack).toBeInstanceOf(LocalDisplayTrack);
expect(localDisplayTrack.videoContentHint).toBeUndefined();
const localDisplayStream = await createDisplayStream();
expect(localDisplayStream).toBeInstanceOf(LocalDisplayStream);
expect(localDisplayStream.contentHint).toBeUndefined();
});

it('should preserve the content hint', async () => {
expect.assertions(1);

const localDisplayTrack = await createDisplayTrack(LocalDisplayTrack, 'motion');
expect(localDisplayTrack.videoContentHint).toBe('motion');
const localDisplayStream = await createDisplayStream('motion');
expect(localDisplayStream.contentHint).toBe('motion');
});
});

describe('createDisplayStreamWithAudio', () => {
jest
.spyOn(media, 'getDisplayMedia')
.mockReturnValue(Promise.resolve(mockStream as unknown as MediaStream));

// This mock implementation is needed because createDisplayStreamWithAudio will create a new
// MediaStream from the video track of the mocked stream, so we need to make sure this new
// stream can get the mocked stream's track as well.
jest.spyOn(MediaStream.prototype, 'getTracks').mockImplementation(() => mockStream.getTracks());

it('should call getDisplayMedia with audio', async () => {
expect.assertions(1);

await createDisplayStreamWithAudio();
expect(media.getDisplayMedia).toHaveBeenCalledWith({ video: true, audio: true });
});

it('should return a LocalDisplayStream instance and null if no audio track exists', async () => {
expect.assertions(2);

const [localDisplayStream, localSystemAudioStream] = await createDisplayStreamWithAudio();
expect(localDisplayStream).toBeInstanceOf(LocalDisplayStream);
expect(localSystemAudioStream).toBeNull();
});

it('should return a LocalDisplayStream and a LocalSystemAudioStream instance if audio track exists', async () => {
expect.assertions(2);

const mockStreamWithAudio = createMockedStreamWithAudio();
jest
.spyOn(media, 'getDisplayMedia')
.mockReturnValueOnce(Promise.resolve(mockStreamWithAudio as unknown as MediaStream));

const [localDisplayStream, localSystemAudioStream] = await createDisplayStreamWithAudio();
expect(localDisplayStream).toBeInstanceOf(LocalDisplayStream);
expect(localSystemAudioStream).toBeInstanceOf(LocalSystemAudioStream);
});

it('should preserve the content hint', async () => {
expect.assertions(1);

const [localDisplayStream] = await createDisplayStreamWithAudio('motion');
expect(localDisplayStream.contentHint).toBe('motion');
});
});
});
Loading