Skip to content

Commit

Permalink
feat(MeetingsSdkAdapter): add the capability to join the meeting muted
Browse files Browse the repository at this point in the history
  • Loading branch information
akoushke committed Jan 25, 2020
1 parent 042a63b commit 2e1e2c2
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 18 deletions.
47 changes: 38 additions & 9 deletions src/MeetingsSDKAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,16 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter {
* @private
*/
attachMedia(ID, {type, stream}) {
const meeting = this.meetings[ID];
const meeting = {...this.meetings[ID]};

switch (type) {
case MEDIA_TYPE_LOCAL:
this.meetings[ID] = {
...meeting,
localAudio: new MediaStream(stream.getAudioTracks()),
localVideo: new MediaStream(stream.getVideoTracks()),
// Attach the media streams only if the streams are unmuted
// `disableLocalAudio/Video` change inside handle media stream methods
localAudio: meeting.disabledLocalAudio ? null : new MediaStream(stream.getAudioTracks()),
localVideo: meeting.disabledLocalVideo ? null : new MediaStream(stream.getVideoTracks()),
};
break;
case MEDIA_TYPE_REMOTE_AUDIO:
Expand All @@ -134,7 +136,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter {
* @private
*/
removeMedia(ID, {type}) {
const meeting = this.meetings[ID];
const meeting = {...this.meetings[ID]};

switch (type) {
case MEDIA_TYPE_LOCAL:
Expand Down Expand Up @@ -210,12 +212,21 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter {
try {
const sdkMeeting = this.fetchMeeting(ID);
const {localAudio, localVideo} = this.meetings[ID];
const localStream = new MediaStream([localAudio.getAudioTracks()[0], localVideo.getVideoTracks()[0]]);
const [localStream] = await sdkMeeting.getMediaStreams(DEFAULT_MEDIA_SETTINGS);

await sdkMeeting.join();

// SDK requires to join the meeting before adding the local stream media to the meeting
await sdkMeeting.addMedia({localStream, DEFAULT_MEDIA_SETTINGS});

// Mute either streams after join if user had muted them before joining
if (localAudio === null) {
await sdkMeeting.muteAudio();
}

if (localVideo === null) {
await sdkMeeting.muteVideo();
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(`Unable to join meeting "${ID}"`, error);
Expand Down Expand Up @@ -295,16 +306,25 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter {
const sdkMeeting = this.fetchMeeting(ID);

try {
const isInSession = this.meetings[ID].remoteAudio !== null;
let audioEnabled = this.meetings[ID].localAudio !== null;

if (audioEnabled) {
await sdkMeeting.muteAudio();
// Mute the audio only if there is an active meeting
if (isInSession) {
await sdkMeeting.muteAudio();
}

// Store the current local audio stream to avoid an extra request call
this.meetings[ID].disabledLocalAudio = this.meetings[ID].localAudio;
this.meetings[ID].localAudio = null;
audioEnabled = false;
} else {
await sdkMeeting.unmuteAudio();
// Unmute the audio only if there is an active meeting
if (isInSession) {
await sdkMeeting.unmuteAudio();
}

// Retrieve the stored local audio stream
this.meetings[ID].localAudio = this.meetings[ID].disabledLocalAudio;
this.meetings[ID].disabledLocalAudio = null;
Expand Down Expand Up @@ -376,16 +396,25 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter {
const sdkMeeting = this.fetchMeeting(ID);

try {
const isInSession = this.meetings[ID].remoteVideo !== null;
let videoEnabled = this.meetings[ID].localVideo !== null;

if (videoEnabled) {
await sdkMeeting.muteVideo();
// Mute the video only if there is an active meeting
if (isInSession) {
await sdkMeeting.muteVideo();
}

// Store the current local video stream to avoid an extra request call
this.meetings[ID].disabledLocalVideo = this.meetings[ID].localVideo;
this.meetings[ID].localVideo = null;
videoEnabled = false;
} else {
await sdkMeeting.unmuteVideo();
// Unmute the video only if there is an active meeting
if (isInSession) {
await sdkMeeting.unmuteVideo();
}

// Retrieve the stored local video stream
this.meetings[ID].localVideo = this.meetings[ID].disabledLocalVideo;
this.meetings[ID].disabledLocalVideo = null;
Expand Down
91 changes: 82 additions & 9 deletions src/MeetingsSDKAdapter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ describe('Meetings SDK Adapter', () => {
});

describe('attachMedia()', () => {
test('sets `localAudio` and `localVideo`, if the event type is `local`', () => {
const mockMediaStreamInstance = {
let mockMediaStreamInstance, event;

beforeEach(() => {
mockMediaStreamInstance = {
getAudioTrack: () => [],
getVideoTrack: () => [],
};
const event = {
event = {
type: 'local',
stream: {
getAudioTracks: jest.fn(() => ['localAudio']),
Expand All @@ -59,16 +61,57 @@ describe('Meetings SDK Adapter', () => {
};

global.MediaStream = jest.fn(() => mockMediaStreamInstance);
});

test('keeps `localAudio` empty, if the event type is `local` and the audio stream is empty', () => {
meetingSDKAdapter.meetings[meetingID] = {
disabledLocalAudio: {},
};

meetingSDKAdapter.attachMedia(meetingID, event);

expect(meetingSDKAdapter.meetings[meetingID]).toMatchObject({
localAudio: null,
});
});

test('keeps `localVideo` empty, if the event type is `local` and the audio stream is empty', () => {
meetingSDKAdapter.meetings[meetingID] = {
disabledLocalVideo: {},
};

meetingSDKAdapter.attachMedia(meetingID, event);

expect(meetingSDKAdapter.meetings[meetingID]).toMatchObject({
localVideo: null,
});
});

test('keeps both `localVideo` and `localVideo` empty, if the event type is `local` and the audio stream is empty', () => {
meetingSDKAdapter.meetings[meetingID] = {
disabledLocalVideo: {},
disabledLocalAudio: {},
};

meetingSDKAdapter.attachMedia(meetingID, event);

expect(meetingSDKAdapter.meetings[meetingID]).toMatchObject({
localVideo: null,
localAudio: null,
});
});

test('sets `localAudio` and `localVideo`, if the event type is `local`', () => {
meetingSDKAdapter.attachMedia(meetingID, event);

expect(meetingSDKAdapter.meetings[meetingID]).toMatchObject({
localAudio: mockMediaStreamInstance,
localVideo: mockMediaStreamInstance,
});
});

test('sets `remoteAudio`, if the event type is `remoteAudio`', () => {
const event = {
event = {
type: 'remoteAudio',
stream: 'remoteAudio',
};
Expand All @@ -80,7 +123,7 @@ describe('Meetings SDK Adapter', () => {
});

test('sets `remoteVideo`, if the event type is `remoteVideo`', () => {
const event = {
event = {
type: 'remoteVideo',
stream: 'remoteVideo',
};
Expand All @@ -93,7 +136,7 @@ describe('Meetings SDK Adapter', () => {

test('returns the same meeting object, if the event type is not declared', () => {
meetingSDKAdapter.meetings[meetingID] = meeting;
const event = {
event = {
type: 'NA',
stream: {},
};
Expand All @@ -104,15 +147,15 @@ describe('Meetings SDK Adapter', () => {
});

describe('removeMedia()', () => {
test('nullifies `localAudio` and `localVideo`, if the event type is `local`', () => {
test('removes `localAudio` and `localVideo`, if the event type is `local`', () => {
meetingSDKAdapter.removeMedia(meetingID, {type: 'local'});
expect(meetingSDKAdapter.meetings[meetingID]).toMatchObject({
localAudio: null,
localVideo: null,
});
});

test('nullifies `remoteAudio`, if the event type is `remoteAudio`', () => {
test('removes `remoteAudio`, if the event type is `remoteAudio`', () => {
const event = {
type: 'remoteAudio',
};
Expand All @@ -123,7 +166,7 @@ describe('Meetings SDK Adapter', () => {
});
});

test('nullifies `remoteVideo`, if the event type is `remoteVideo`', () => {
test('removes `remoteVideo`, if the event type is `remoteVideo`', () => {
const event = {
type: 'remoteVideo',
};
Expand Down Expand Up @@ -228,9 +271,24 @@ describe('Meetings SDK Adapter', () => {
meetingSDKAdapter.meetings[meetingID] = {
...meeting,
localAudio: {},
remoteAudio: {},
};
});

test('skips muting audio if there is an inactive meeting', async () => {
meetingSDKAdapter.meetings[meetingID].remoteAudio = null;

await meetingSDKAdapter.handleLocalAudio(meetingID);
expect(mockSDKMeeting.muteAudio).not.toHaveBeenCalled();
});

test('skips unmuting audio if there is an inactive meeting', async () => {
meetingSDKAdapter.meetings[meetingID].remoteAudio = null;

await meetingSDKAdapter.handleLocalAudio(meetingID);
expect(mockSDKMeeting.unmuteAudio).not.toHaveBeenCalled();
});

test('mutes audio if the the audio track is enabled', async () => {
await meetingSDKAdapter.handleLocalAudio(meetingID);
expect(mockSDKMeeting.muteAudio).toHaveBeenCalled();
Expand Down Expand Up @@ -315,9 +373,24 @@ describe('Meetings SDK Adapter', () => {
meetingSDKAdapter.meetings[meetingID] = {
...meeting,
localVideo: {},
remoteVideo: {},
};
});

test('skips muting video if there is an inactive meeting', async () => {
meetingSDKAdapter.meetings[meetingID].remoteVideo = null;

await meetingSDKAdapter.handleLocalVideo(meetingID);
expect(mockSDKMeeting.muteVideo).not.toHaveBeenCalled();
});

test('skips unmuting video if there is an inactive meeting', async () => {
meetingSDKAdapter.meetings[meetingID].remoteVideo = null;

await meetingSDKAdapter.handleLocalVideo(meetingID);
expect(mockSDKMeeting.unmuteVideo).not.toHaveBeenCalled();
});

test('mutes video if the the video track is enabled', async () => {
await meetingSDKAdapter.handleLocalVideo(meetingID);
expect(mockSDKMeeting.muteVideo).toHaveBeenCalled();
Expand Down

0 comments on commit 2e1e2c2

Please sign in to comment.