Skip to content

Commit 8e093b7

Browse files
authored
feat: add change input audio device function (#160)
1 parent 4558ec8 commit 8e093b7

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

src/AnamClient.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,28 @@ export default class AnamClient {
549549
return this.inputAudioState;
550550
}
551551

552+
public async changeAudioInputDevice(deviceId: string): Promise<void> {
553+
if (this.clientOptions?.disableInputAudio) {
554+
throw new Error(
555+
'AnamClient: Cannot change audio input device because input audio is disabled.',
556+
);
557+
}
558+
559+
if (!this._isStreaming) {
560+
throw new Error(
561+
'AnamClient: Cannot change audio input device while not streaming. Start streaming first.',
562+
);
563+
}
564+
565+
if (!this.streamingClient) {
566+
throw new Error(
567+
'AnamClient: Cannot change audio input device because streaming client is not available. Start streaming first.',
568+
);
569+
}
570+
571+
await this.streamingClient.changeAudioInputDevice(deviceId);
572+
}
573+
552574
public createTalkMessageStream(correlationId?: string): TalkMessageStream {
553575
if (!this.streamingClient) {
554576
throw new Error(

src/modules/StreamingClient.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,66 @@ export class StreamingClient {
269269
return this.peerConnection;
270270
}
271271

272+
public async changeAudioInputDevice(deviceId: string): Promise<void> {
273+
if (!this.peerConnection) {
274+
throw new Error(
275+
'StreamingClient - changeAudioInputDevice: peer connection is not initialized. Start streaming first.',
276+
);
277+
}
278+
279+
if (deviceId === null || deviceId === undefined) {
280+
throw new Error(
281+
'StreamingClient - changeAudioInputDevice: deviceId is required',
282+
);
283+
}
284+
285+
// Store the current mute state to preserve it
286+
const wasMuted = this.inputAudioState.isMuted;
287+
288+
try {
289+
// Stop the current audio stream tracks
290+
if (this.inputAudioStream) {
291+
this.inputAudioStream.getAudioTracks().forEach((track) => {
292+
track.stop();
293+
});
294+
}
295+
296+
// Request new audio stream with the new device ID
297+
const audioConstraints: MediaTrackConstraints = {
298+
echoCancellation: true,
299+
deviceId: {
300+
exact: deviceId,
301+
},
302+
};
303+
304+
this.inputAudioStream = await navigator.mediaDevices.getUserMedia({
305+
audio: audioConstraints,
306+
});
307+
308+
// Update the stored device ID
309+
this.audioDeviceId = deviceId;
310+
311+
// Replace the audio track in the peer connection
312+
await this.setupAudioTrack();
313+
314+
// Restore the mute state
315+
if (wasMuted) {
316+
this.muteAllAudioTracks();
317+
}
318+
319+
// Emit event to notify that the device has changed
320+
this.publicEventEmitter.emit(
321+
AnamEvent.INPUT_AUDIO_DEVICE_CHANGED,
322+
deviceId,
323+
);
324+
} catch (error) {
325+
console.error('Failed to change audio input device:', error);
326+
throw new Error(
327+
`StreamingClient - changeAudioInputDevice: ${error instanceof Error ? error.message : String(error)}`,
328+
);
329+
}
330+
}
331+
272332
public getInputAudioStream(): MediaStream | null {
273333
return this.inputAudioStream;
274334
}

src/types/events/public/AnamEvent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export enum AnamEvent {
1313
MIC_PERMISSION_PENDING = 'MIC_PERMISSION_PENDING',
1414
MIC_PERMISSION_GRANTED = 'MIC_PERMISSION_GRANTED',
1515
MIC_PERMISSION_DENIED = 'MIC_PERMISSION_DENIED',
16+
INPUT_AUDIO_DEVICE_CHANGED = 'INPUT_AUDIO_DEVICE_CHANGED',
1617
}

src/types/events/public/EventCallbacks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ export type EventCallbacks = {
2121
[AnamEvent.MIC_PERMISSION_PENDING]: () => void;
2222
[AnamEvent.MIC_PERMISSION_GRANTED]: () => void;
2323
[AnamEvent.MIC_PERMISSION_DENIED]: (error: string) => void;
24+
[AnamEvent.INPUT_AUDIO_DEVICE_CHANGED]: (deviceId: string) => void;
2425
};

0 commit comments

Comments
 (0)