Skip to content

Commit

Permalink
feat(calling): add updateMedia in call (webex#3284)
Browse files Browse the repository at this point in the history
  • Loading branch information
sreenara authored Jan 1, 2024
1 parent 497e769 commit 5814e3b
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 6 deletions.
22 changes: 22 additions & 0 deletions docs/samples/calling/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,28 @@ function populateSourceDevices(mediaDevice) {
select && select.appendChild(option);
}

async function changeInputStream() {
const selectedDevice = audioInputDevicesElem.options[audioInputDevicesElem.selectedIndex].value;

const constraints = {
audio: true,
deviceId: selectedDevice ? { exact: selectedDevice } : undefined
};
const newStream = await Calling.createMicrophoneStream(constraints);

call.updateMedia(newStream);
}

async function changeOutputStream() {
const selectedDevice = audioOutputDevicesElem.options[audioOutputDevicesElem.selectedIndex].value;
mediaStreamsRemoteAudio.setSinkId(selectedDevice);
}

async function changeStream() {
changeInputStream();
changeOutputStream();
}

/**
*
*/
Expand Down
5 changes: 2 additions & 3 deletions docs/samples/calling/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,8 @@ <h3 style="color: #1a73e8; margin-bottom: 0.25rem;">Call Transfer</h3>
<div>
<p class="note">NOTE: Choose your sending and receiving options for the meeting.</p>

<button id="sd-get-media-devices" type="button" onclick="clearMediaDeviceList(); getMediaDevices()">Get
Devices</button>

<button id="sd-get-media-devices" type="button" onclick="clearMediaDeviceList(); getMediaDevices()">Get Devices</button>
<button id="sd-change-media" type="button" onclick="changeStream()">Change Device</button>
<div class="u-mv">
<label>
<input type="checkbox" name="ts-media-direction" value="receiveAudio" checked="">receiveAudio
Expand Down
75 changes: 74 additions & 1 deletion packages/calling/src/CallingClient/calling/call.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ describe('Call Tests', () => {

expect(webex.request.mock.calls[0][0].body.metrics).toStrictEqual(disconnectStats);
});

it('dial fails if localAudioTrack is empty', async () => {
const mockStream = {
outputStream: {
Expand Down Expand Up @@ -439,14 +440,86 @@ describe('Call Tests', () => {
await waitForMsecs(50);
expect(warnSpy).toBeCalledTimes(1);
expect(warnSpy).toBeCalledWith(
`Did not find a local track while dialling the call ${call.getCorrelationId()}`,
`Did not find a local track while dialing the call ${call.getCorrelationId()}`,
{file: 'call', method: 'dial'}
);
expect(call['callStateMachine'].state.value).toBe('S_IDLE');
expect(call['mediaStateMachine'].state.value).toBe('S_ROAP_IDLE');

expect(webex.request).not.toBeCalledOnceWith();
});

it('update media after call creation with valid stream', () => {
const callManager = getCallManager(webex, defaultServiceIndicator);

const mockStream = {
outputStream: {
getAudioTracks: jest.fn().mockReturnValue([mockTrack]),
},
on: jest.fn(),
};

const localAudioStream = mockStream as unknown as MediaSDK.LocalMicrophoneStream;

const call = callManager.createCall(dest, CallDirection.OUTBOUND, deviceId, mockLineId);

call.dial(localAudioStream);

expect(mockTrack.enabled).toEqual(true);

const mockTrack2 = {
enabled: true,
};

const mockStream2 = {
outputStream: {
getAudioTracks: jest.fn().mockReturnValue([mockTrack2]),
},
on: jest.fn(),
};

const localAudioStream2 = mockStream2 as unknown as MediaSDK.LocalMicrophoneStream;

call.updateMedia(localAudioStream2);

expect(call['mediaConnection'].updateLocalTracks).toBeCalledOnceWith({audio: mockTrack2});
});

it('update media with invalid stream', () => {
const callManager = getCallManager(webex, defaultServiceIndicator);
const warnSpy = jest.spyOn(log, 'warn');

const mockStream = {
outputStream: {
getAudioTracks: jest.fn().mockReturnValue([mockTrack]),
},
on: jest.fn(),
};

const localAudioStream = mockStream as unknown as MediaSDK.LocalMicrophoneStream;

const call = callManager.createCall(dest, CallDirection.OUTBOUND, deviceId, mockLineId);

call.dial(localAudioStream);

expect(mockTrack.enabled).toEqual(true);

const errorStream = {
outputStream: {
getAudioTracks: jest.fn().mockReturnValue([]),
},
};

const localAudioStream2 = errorStream as unknown as MediaSDK.LocalMicrophoneStream;

call.updateMedia(localAudioStream2);

expect(call['mediaConnection'].updateLocalTracks).not.toBeCalled();
expect(warnSpy).toBeCalledOnceWith(
`Did not find a local track while updating media for call ${call.getCorrelationId()}. Will not update media`,
{file: 'call', method: 'updateMedia'}
);
});
});

describe('State Machine handler tests', () => {
Expand Down
30 changes: 28 additions & 2 deletions packages/calling/src/CallingClient/calling/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2016,7 +2016,7 @@ export class Call extends Eventing<CallEventTypes> implements ICall {
public async dial(localAudioStream: LocalMicrophoneStream) {
const localAudioTrack = localAudioStream.outputStream.getAudioTracks()[0];
if (!localAudioTrack) {
log.warn(`Did not find a local track while dialling the call ${this.getCorrelationId()}`, {
log.warn(`Did not find a local track while dialing the call ${this.getCorrelationId()}`, {
file: CALL_FILE,
method: 'dial',
});
Expand Down Expand Up @@ -2640,7 +2640,7 @@ export class Call extends Eventing<CallEventTypes> implements ICall {
}

/**
* .
* Mutes/Unmutes the call.
*
* @param localAudioTrack -.
*/
Expand All @@ -2655,6 +2655,32 @@ export class Call extends Eventing<CallEventTypes> implements ICall {
}
};

/**
* Change the audio stream of the call.
*
* @param newAudioStream - The new audio stream to be used in the call.
*/

public updateMedia = (newAudioStream: LocalMicrophoneStream): void => {
const localAudioTrack = newAudioStream.outputStream.getAudioTracks()[0];

if (!localAudioTrack) {
log.warn(
`Did not find a local track while updating media for call ${this.getCorrelationId()}. Will not update media`,
{
file: CALL_FILE,
method: 'updateMedia',
}
);

return;
}

this.mediaConnection.updateLocalTracks({
audio: localAudioTrack,
});
};

/**
* @param broadworksCorrelationInfo
*/
Expand Down
7 changes: 7 additions & 0 deletions packages/calling/src/CallingClient/calling/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,13 @@ export interface ICall extends Eventing<CallEventTypes> {
transferTarget?: string
): void;

/**
* Change the audio stream of the call.
*
* @param newAudioStream - The new audio stream to be used in the call.
*/
updateMedia(newAudioStream: LocalMicrophoneStream): void;

/**
* Fetches the information related to the call's Broadworks correlationId.
*
Expand Down

0 comments on commit 5814e3b

Please sign in to comment.