NotReadableError: Concurrent mic process limit

I am trying to implement a microphone switch feature where, whilst being on a call, i am able to replace my current in-use microphone with a new one.

After selecting the new microphone I want to change to, I receive a NotReadableError: Concurrent mic process limit. error message.

This is because the previous device isnt being removed/deactivated before adding the new device, this is visible from the permission icons here:

The old microphone is still active and thus when permitting the new device i receive the concurrent mic process limit error.

I am using replaceTrack() to swap to the new selected device.

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

		var newAudioTrack;
		var constraints;
		var mediaStream: MediaStream;
		var audioTrack: MediaStreamTrack;

		await navigator.mediaDevices.enumerateDevices().then((res) => {
			res.forEach((device) => {
				if (device.kind === 'audioinput' && device.deviceId === selectedDeviceId) {
					newAudioTrack = device;

                    // constraints specify new deviceId 
					constraints = {
						video: { facingMode: 'user' },
						audio: { deviceId: { exact: newAudioTrack['deviceId'] } },
					};

				}
			});
		});		

		mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
		audioTrack = mediaStream.getVideoTracks()[0];

		this.localUsersService
			.getWebcamPublisher()
			.replaceTrack(audioTrack)
			.then(() => {
				this.publishAudio(true);
				this.hasAudioDevices = true;
			});
	}

Please let me know how I can get around this issue

@CSantosM do you have any idea on how to solve the issue?

1 Like

@CSantosM @micael.gallego

Few updates since my last message:

  1. The issue with track.stop() not working consistently is only relevant on Firefox. The reason being that currently Firefox has a limit of having 1 active microphone at a time in a tab, and thus if the previous microphone track is not stopped successfully, we get the browser’s NotReadableError. This is something Firefox is planning on changing https://bugzilla.mozilla.org/show_bug.cgi?id=1238038.

  2. If you use Google Chrome browser for example. The track.stop() part of the code isnt as important to work because chromium browsers dont have a microphone limit in this way. And thus we can continue with replacing the track.

After testing this. The microphone successfully switches, however the issue is that just as the other user can hear me through my new microphone audio, so can I. There is a really loud echo of my own audio coming from the new microphone, and setting echoCancellation to true does not resolve this.

Any ideas on how to potentially resolve this would be really appreciated, thanks for reading.

@CSantosM @micael.gallego

I decided to update this thread as i found the solution and want other users to have also.

So I have this working on Firefox, Safari and Google browser so feel free to use this code.

The reason I was experiencing the echo issue is because I was running the initwebcamPublisher() in ngOnInit() of the Settings component… This funtion already runs once on initiation of the app, and doing it once more causes some sort of duplicate in the webcam publisher.

In removing that I am left with the working onMicrophoneSelect() :

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

        if (!!audioSource) {

            // checkin is new deviceId different than older?
            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
            this.publishAudio(true);
            this.isAudioActive = true;

            return;
        }

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

So once the user selects the new microphone, their current cam and mic are unpublished, causing them to appear blank for the other user for about 5ms, and then reappear with both same video and audio from the new selected microphone

The 3 most important parts here are:

  1. Unpublishing old publisher using unpublishWebcamPublisher()
  2. Using the replaceTrack() method to change microphone
  3. Republish the new publisher this.openViduWebRTCService.publishWebcamPublisher();

Nevertheless a great way to improve this to remove the split-second blank-screen that happens while the camera and mic are unpublished due to this.openViduWebRTCService.publishWebcamPublisher();