Activating the microphone device on the MediaStream results in an echo of one's own voice

I am in the process of creating an Angular application that enables two users to have a video call using the Openvidu calling solution.

As part of this application, I have implemented a feature that allows users to switch between different cameras or microphones while on the call.

When a new microphone is selected, the previous microphone track is stopped and removed from the stream before adding the new one. This functionality is demonstrated in the code snippet below:

async onMicrophoneSelected(event: any) {
        var currentMediaStream: MediaStream = this.localUsersService.getWebcamPublisher().stream.getMediaStream();
        var currentAudioTrack: MediaStreamTrack;
        var currentVideoTrack: MediaStreamTrack;

        var newAudioInfo: MediaDeviceInfo; 
        var newAudioTrack: MediaStreamTrack;
        var newVideoTrack: MediaStreamTrack;

        // Identifying current video & audio tracks in use
        currentMediaStream.getTracks().forEach((track) => {
            if (track.kind === 'audio') {
                currentAudioTrack = track;
                currentAudioTrack.stop();  
            }

            if (track.kind === 'video') {
                currentVideoTrack = track;
            }
        });

        
        await navigator.mediaDevices.enumerateDevices().then((res) => {
            res.forEach((device) => {
                
                if (device.kind === 'audioinput' && device.deviceId === event.value) {
                    newAudioInfo = device;
                }
            });
        });

        
        await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: newAudioInfo.deviceId } } }).then((stream) => {
            newAudioTrack = stream.getAudioTracks()[0];
        });


        this.localUsersService
            .getWebcamPublisher()
            .replaceTrack(newAudioTrack)
            .then(() => {
                console.log(currentMediaStream.getTracks(), '<<<-- checking stream after changes');
            });
    }

Once the above code executes successfully, the active microphone should be switched to the newly selected one during the call.

While this change works as intended, I am experiencing an issue where there is a loud echo when switching microphones, causing me to hear myself through the new microphone. Any suggestions on how to resolve this would be greatly appreciated. Thank you for your assistance.

Note: echoCancellation was not able to solve this problem.

Answer №1

I successfully tested this code on Firefox, Safari, and Google browsers, so go ahead and implement it without any worries.

The issue of echo that I encountered was because I mistakenly called the initwebcamPublisher() function within the ngOnInit() method of the Settings component. This function is already executed once during the initiation of the app, and calling it again led to a duplicate webcam publisher.

After rectifying this mistake, only the onMicrophoneSelect() function remains functional:

async onMicrophoneSelected(event: any) {
        const audioSource = event?.value;

        if (!!audioSource) {
            // Check if new deviceId is different from the previous one
            if (this.oVDevicesService.needUpdateAudioTrack(audioSource)) {
                const mirror = this.oVDevicesService.cameraNeedsMirror(this.camSelected.device);
                this.openViduWebRTCService.unpublishWebcamPublisher();
                this.openViduWebRTCService.replaceTrack(null, audioSource, mirror);
                this.openViduWebRTCService.publishWebcamPublisher();
                this.oVDevicesService.setMicSelected(audioSource);
                this.micSelected = this.oVDevicesService.getMicSelected();
            }
            // Publish microphone stream
            this.publishAudio(true);
            this.isAudioActive = true;

            return;
        }

        // Unpublish microphone stream
        this.publishAudio(false);
        this.isAudioActive = false;
    }

Upon selecting a new microphone, the current video and audio streams are momentarily unpublished, resulting in a brief blank screen for about 5ms before reappearing with both video and audio from the newly selected microphone.

The key steps involved are:

  1. Unpublishing the old publisher using unpublishWebcamPublisher()
  2. Utilizing the replaceTrack() method to switch microphones
  3. Republishing the new publisher using
    this.openViduWebRTCService.publishWebcamPublisher();

To further enhance this process and eliminate the split-second blank screen when the camera and microphone streams are unpublished, consider optimizing the

this.openViduWebRTCService.publishWebcamPublisher();
method.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adjust the appearance of matSelect when the selection menu is activated

What is the best way to adjust mat-select properties when its options are open? <mat-select class="selector"> <mat-option><mat-option> </mat-select> .selector:focus { color: green; } I attempted using focus, but ...

TensorflowJS Error: The property 'fetch' cannot be read as it is undefined

I am working on an Angular 7 application and attempting to load the mobilenet model by following the instructions in this example. To do this, I first installed tensorflowjs using the command npm install @tensorflow/tfjs (based on the steps provided in th ...

Make the switch from TypeScript namespaces to ES2015 modules

After making adjustments to my TypeScript configuration, I am now encountering errors related to the no-namespace rule. Here is how my current setup involving namespaces looks like: Exporting classes within a namespace: namespace MyNamespace { export ...

You are unable to assign to 'total' as it is a constant or a property that cannot be modified

Upon running ng build --prod in my project, I encountered the following error: src\app\components\xxxx\xxxx.component.html(116,100): : Cannot assign to 'total' because it is a constant or a read-only property. The proble ...

The imported package is not functioning properly within the project

I've recently developed a Typescript Package and I want to test it in an application before publishing it on NPM. The main file (index.ts) of the package is structured like this => import Builder from './core/builder'; export default ...

Trigger refetchQueries post-execution of a mutation operation

In the past, I executed a mutation in a similar manner as shown below: export const useEditLocationName = () => { const [editFavoriteLocationName] = useEditFavoriteLocationNameMutation({ refetchQueries: [{ query: GetMyFavouritePlacesDocument}], ...

Troubleshoot: Child element not displaying when using *ngIf in Ionic 3

I'm working on an app with Ionic 3 that includes animations. After installing the necessary package: npm install --save CSS-animator Below is a snippet from my template: <div class="alert" *ngIf="!show" #myElement> <h5>Here is my ani ...

Definition of Promise resolve type in Visual Code's d.ts file

Need help with: // api.js export function getLayout(){ return axios.get('/api/layout').then(res => res.data) } // api.d.ts declare interface JSONResponse { meta: object, data: Array<Field> } export declare function getLayout ...

Passing specific props to child components based on their type in a React application using TypeScript

Sorry if this question has already been addressed somewhere else, but I couldn't seem to find a solution. I'm looking for a way to pass props conditionally to children components based on their type (i.e. component type). For example, consider ...

Tips for stopping TypeScript code blocks from being compiled by the Angular AOT Webpack plugin

Is there a way to exclude specific code from Angular's AOT compiler? For instance, the webpack-strip-block loader can be utilized to eliminate code between comments during production. export class SomeComponent implements OnInit { ngOnInit() { ...

Execute TSC on the Hosted Build Agent

Currently, I am diving into TypeScript and have managed to create a basic app that I would like to deploy using VSTS on Azure App Service. My straightforward build definition involves the following steps: Utilize "Node Tool Installer (preview)" to set up ...

Leveraging vuex in conjunction with typescript allows for efficient management of state in namespace modules,

I am currently integrating vuex with typescript and namespaces module in my project. Within this setup, I have two distinct modules: "UserProfile" and "Trips". So far, everything is functioning smoothly within the confines of each module. However, I have ...

When trying to use preact as an alias for react, the error "Module not found: 'react/jsx-runtime'" is thrown

Avoid using the outdated guide I linked; follow the one provided in the answer instead I am trying to transition from react to preact by following their migration guide. I updated my webpack.config.js to include: alias: { "react": "pr ...

How to Include a JavaScript Library without Export in Angular 2.0.0 using Angular CLI and Webpack

In my Angular 2.0.0 project, I use Angular CLI and Webpack for building. I'm looking to incorporate a JS library (specifically xmltojson.js from https://www.npmjs.com/package/xmltojson) that contains a variable (xmlToJSON) referencing a function. Thi ...

What are the benefits of incorporating a proxy.conf.json file into an Angular application?

Imagine we have a server running on http://localhost:8080/. Rather than configuring the back-end's base URL from environment.ts file, we can create a proxy.conf.json file with the code below: { "/api": { "target": "http://localhost:8080", ...

What is the best way to create a data type that enables unrestricted index retrieval while ensuring that the value retrieved will never be

By enabling the noUncheckedIndexedAccess option in TypeScript, we ensure that when accessing object properties with arbitrary keys, the value type includes both the specified type and undefined. This behavior is generally appropriate as it aligns with run ...

Troubleshooting issues with setting errors on a FormGroup instance in Angular Reactive Forms are proving to be more challenging

Currently I am working with Angular 4.4.3 reactive forms to create custom validation for a group of controls within a form. As per the documentation on AbstractControl.setErrors, this method updates the errors property of the AbstractControl that it's ...

A new interface property type that is customized based on the type property that is passed in

My dilemma lies in a generic interface with a field depending on the passed type. I'm exploring the possibility of having another field that can accept any type from the passed type. For instance: interface sampleObject { name: fullName age: n ...

Tips for expanding third-party classes in a versatile manner using Typescript

tl;dr: Seeking a better way to extend 3rd-party lib's class in JavaScript. Imagine having a library that defines a basic entity called Animal: class Animal { type: string; } Now, you want to create specific instances like a dog and a cat: const ...

Comparing Angular 2 with Angular.js, React.js, and Typescript

Hello there, I am a fresh-faced web developer looking to create a modest website for my personal use. However, my knowledge is limited when it comes to JavaScript and jQuery concepts. In order to expand my skills and build an enhanced website, I decided ...