ToolsAbout MeContact

Using HomePod mini and AirPods with WebRTC

By Olivier Anguenot
Published in others
May 27, 2022
6 min read

Table Of Contents

1
Is HomePod mini the perfect Mac Mini speaker....
2
Using a HomePod mini with WebRTC
3
Using Airpods
4
Conclusion
Using HomePod mini and AirPods with WebRTC

Recently I bought an Apple HomePod mini to control my HomeKit devices such as my electrical plugs and my garage door. The experience is good (as for other assistants) and I can now switch on or off the printer just by speaking… No need to go under my desk where my printer is to manually switch it on!

As I already have a pair of AirPods too, I decided to check if these devices can be use when making WebRTC calls. So, this experience is limited to the Apple addicts :-)

Is HomePod mini the perfect Mac Mini speaker…

The experience of connecting the Homepod to my Mac mini was successful. If the Mac is connected to the same network as the HomePod, it detects your device, and you can select it in the Mac sound panel.

The HomePod is connected using the AirPlay technology. This is great for streaming but here there is a delay of some seconds each time you start or stop your music for example.

But it works great and so the HomePod can be used as an external speaker. For my Mac Mini, this is enough because the internal speaker proposed is great for sound system but not for playing music…

Additionally, I added the HomePod to HomeKit to control my connected plugs and accessories. Everything is working well.

So for entertainment use, it is ok. But what about more professional use, such for telecommuting and video conferencing with colleagues or clients?.

Are the HomePod perfect for these usages too ?

homepod mini

Using a HomePod mini with WebRTC

The first showstopper was the lack of support of the output devices and associated setSinkId API in Safari to be able to have a 100% Apple experience. So, I used Chrome.

Note: As you will see in the following paragraph, as it is an AirPlay device, you need to select in the Mac sound panel for using it. So, it will be used in Safari and Firefox too but not through API.

Can HomePod mini be used as an external microphone ?

Using HomePod with WebRTC means being able to use it as an external microphone and as an external speaker.

Let check first, if we could use it as a microphone.

To quickly have the result, I called the API getUserMedia and checked if the track obtained is from the HomePod or not.

const stream = await navigator.mediaDevices.getUserMedia({audio: true});
const audioTrack = stream.getAudioTracks()[0];

// MediaStreamTrack {kind: 'audio', id: '1e432156-29cd-4648-921b-67332892c429', label: 'Default - RODE NT-USB (19f7:0003)', enabled: true, muted: false,…}

The Homepod has not been selected. Hum… this probably means that the microphone of the HomePod is not usable for WebRTC.

To confirm, I used the API enumerateDevices and effectively the HomePod is not listed as an audioinput device and so can’t be used as a microphone.

Can HomePod be used as an external speaker ?

Now, let check if the HomePod can be used as an external speaker.

As you may know, at that time of writing and even if the W3C specification on MediaCapture Output is not new (first draft has been written in 2015), only Chrome is able to list the output devices that can be used and proposes to select them using the API setSinkId.

Firefox’s implementation of setSinkId is still behind a flag and nothing found with Safari Technology Preview…

Additionally, to that method, this specification introduces a new method selectAudioOutput for prompting the user to select the specific audio output device he would like to use. But as explained in the specification, the lack of homogenization around the autoplay is a brake to propose that API. So no implementation exists at this time.

So ok… I will just use the setSinkId in Chrome…

For the first test, I didn’t select the HomePod as my default speaker in the Mac sound panel. In that case, calling enumerateDevices didn’t enumerate it.

I have to select it first in the Mac sound panel and only after I called the eumerateDevices API in Chrome to see if the HomePod is listed

const devices = await navigator.mediaDevices.enumerateDevices();

// MediaDeviceInfo {deviceId: '67b8f458a6df...b46', kind: 'audiooutput', label: 'AirPlay (AirPlay)', groupId: '604b960cf...4fa'}

This time, I found it but not exactly with the name I expected to find: AirPlay (Airplay) is the pretty name given to the HomePod… Don’t know what happens if you have more than one HomePod :-)

Just for the information, I connected my Freebox Player (Internet provider multimedia box) and I did the same test. As the result, the Freebox Player is identified as Freebox Player (AirPLay) which is really better. It is a shame that the HomePod is not better identified. Is Chrome doing this on purpose?…

Now, that I have my HomePod listed, the next is to try to switch to that speaker using the API setSinkId.

  const outputSelect = document.querySelector('#outputDevicesSelect');
  const audioElt = document.querySelector("#audioElt");

  outputSelect.onchange = async (event) => {
    try {
      await audioElt.setSinkId(event.target.value);
    } catch (err) {
      // In case of error
    }
  }

I succeeded to switch the audio to the HomePod and switch from different speakers to the HomePod and vice versa.

I then tried to play a sound. As it is connected using Airplay, there is a some seconds of delay between the click for starting to play and the moment when I hear the sound. But it works great, and I have no issue to use it.

Using the HomePod mini in a WebRTC call

For testing the HomePod in real situation, I took our worldwide Alcatel-Lucent Enterprise Rainbow solution and made a WebRTC call from my Rainbow Android application (Lenovo tablet) to my Rainbow Desktop application (Mac). I configured the Rainbow Desktop for using the HomePod as the speaker and my Rode device as the microphone.

The experience was excellent. Voice was clear and loud. And no delay between the voice and the video was seen. I was worried about Airplay connectivity, but I didn’t detect any problems.

This result needs perhaps more tries to be confirmed but my test was conclusive, so for me, the HomePod mini can be used as a speaker for having WebRTC calls.

Using Airpods

Regarding the Airpods, I should not have any surprises when using them. They should propose to act as microphone and speaker (earpiece).

airpods

Discovering the Airpods

In order for the browser to detect the Airpods, they should be set in your ears.

Once placed in your ears, they appear in the Mac Sound panel and can be listed by using the API enumerateDevices.

const devices = await navigator.mediaDevices.enumerateDevices();

// InputDeviceInfo {deviceId: 'default', kind: 'audioinput', label: 'AirPods', groupId: 'b067ddb7d3e0a051c5bc320a033ed934e2ab8166a8bda18f3a393e6a221ce862'}
// InputDeviceInfo {deviceId: '23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d', kind: 'audioinput', label: 'AirPods', groupId: 'b067ddb7d3e0a051c5bc320a033ed934e2ab8166a8bda18f3a393e6a221ce862'}
// MediaDeviceInfo {deviceId: 'default', kind: 'audiooutput', label: 'AirPods', groupId: '0eaa06962d3daf3ede1d2e2eed22b91901ed2b170b5b4be12c68d49ca4bb9c6a'}
// MediaDeviceInfo {deviceId: '61b7d914c37b31ac931c57c137ffaee7225702cebe1539a1d7e42b4e227cee2a', kind: 'audiooutput', label: 'AirPods', groupId: '0eaa06962d3daf3ede1d2e2eed22b91901ed2b170b5b4be12c68d49ca4bb9c6a'}

This is the habit in Chrome, the system default device is displayed twice in the list: one time with label equals to default and a second time with its real deviceId.

Unlike for the HomePod, this time, the Airpods are clearly identified: no doubt is possible.

But something is strange in Chrome, the groupId which should be the same when devices belong to the same physical equipment is different here: We have a groupId for the microphone and a second one for the speaker…

To be sure, I tested using Firefox (by activating the flag setSinkId in about:config) and Firefox groups the two devices by having a unique groupId. Well done Firefox!

That’s why, after checking that there is no existing issue opened in Chrome, I created a new Chrome issue to check if there is a reason or to fix this bug.

This bug was already detected since Chrome M99: https://bugs.chromium.org/p/chromium/issues/detail?id=1292367.

Detecting the Airpods

I made a second test by using the event devicechange to see if and when the Airpods are detected.

To be honest, I don’t like this event because it only informs the application that something changed at the devices level. It is up to your application then to call enumerateDevices again and to compare: If there are more devices than before, this means that the user plugs or connects physical equipment. Otherwise, the user has disconnected one.

Not really developers friendly.

Here is a little function I made to compare between the list of devices got before the event devicechange and after.

let currentListOfDevices = [];  // Current list of devices
let devicesChanged = false;     // Devices just changed

const compare = (current, update) => {
    // Return the number of devices added (positive) or removed (negative) and the devices information
    let result = {
        count: 0,
        list: [],
    };

    // Same number of devices. We assume that there is no difference.
    if (current.length === update.length) {
        return result;
    }

    if (current.length > update.length) {
        // This is the case when devices have been plugged in
        let newDevices = current.filter((device) => {
            return !update.some((elt) => elt.deviceId === device.deviceId);
        });

        return {
            count: newDevices.length,
            list: newDevices,
        };
    }

    // Here, devices have been unplugged
    let removedDevices = update.filter((device) => {
        return !current.some((elt) => {
            return elt.deviceId === device.deviceId;
        });
    });

    return {
        count: 0 - removedDevices.length,
        list: removedDevices,
    };
};

navigator.mediaDevices.ondevicechange = async (event) => {
    if(!devicesChanged) {
      devicesChanged = true;
        setTimeout(async () => {
            const devices = await navigator.mediaDevices.enumerateDevices();
            // diff contains the list of devices added or removed
            const diff = compare(currentListOfDevices, devices);
            // Reset
            devicesChanged = false;
        }, 500);
    }
}

Using that code, I got the following result:

  • devicechange is triggered only when the AirPods are put in your ears, not when they are moved out ot the box

  • devicechange is triggered as soon as you remove the AirPods from your ears.

To go further, if they are several devices added but with the same groupId, you can deduce that the user has connected a single physical device (except for the AirPods at this time…).

Note: Using the devicechange event is not trivial. For example, adding or removing the Airpods in Chrome triggers events 4 times while only once in Firefox and Safari. So in Chrome, be sure to get the devices after the last event, else, the list can be wrong…

Then, I observed a strange thing when connected my AirPods:

  • Airpods are selected in the Mac sound panel

  • Calling getUserMedia without specifying the deviceId of the AirPods leads to a track obtained from another device…

So, I have to add a constraint on the deviceId to obtain a track from the AirPods.

const constraints = { audio: { deviceId: { exact: '23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d' }} }; // deviceId of the AirPods got from enumerateDevices
const stream = await navigator.mediaDevices.getUserMedia(constraints);

const audioTrack = stream.getAudioTracks()[0];
// MediaStreamTrack {kind: 'audio', id: 'd58e1f88-4835-4258-8e91-53c8b32d1fa5', label: 'AirPods', enabled: true, muted: false, …}

Using the AirPods in a WebRTC call

The AirPods work really great in a WebRTC call. I didn’t encounter any issues with echo cancellation. My recipient was hearing me well, without any problems.

I checked which constraints could be applied on the AirPods to see if we can send an audio stereo stream. Calling the API getCapabilities on the track obtained will reveal the answer

// Target the Airpods
const constraints = { audio: { deviceId: { exact: '23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d'} }};
// Get the stream
const stream = await navigator.mediaDevices.getUserMedia(constraints);
// Get the audio track coming from the Airpods
const track = stream.getAudioTracks()[0];

// Get the capabilities
track.getCapabilities();

// autoGainControl: (2) [true, false]
// channelCount: {max: 1, min: 1}
// deviceId: "23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d"
// echoCancellation: (2) [true, false]
// groupId: "ba15099a5a280fccb98205d558a61b1baec70be81b5d73b4d15323127c413310"
// latency: {max: 0.170666, min: 0.005333}
// noiseSuppression: (2) [true, false]
// sampleRate: {max: 48000, min: 24000}
// sampleSize: {max: 16, min: 16}

And the answer is no. AirPods microphone captures in mono. At home, I tested several microphones: Only my external Rode NT-USB microphone was able to support capturing in stereo.

Conclusion

The HomePod and the AirPods are great products, they can be used in many situations and are for sure well integrated in the Apple ecosystem.

But for my professional usage, I will continue to use my external physical device for conferencing that integrates a microphone and a speaker: Background noise is well removed, I have no problem when the children are making noise, and I can still hear the front doorbell :-)

This let me doing conferencing comfortably!


Tags

#life
Previous Article
Building your own-video pipeline
Olivier Anguenot

Olivier Anguenot

Your WebRTC copilot

Topics

api
dev
others

Related Posts

Time to refresh the Website!
March 30, 2022
3 min
© 2022, All Rights Reserved.

Quick Links

Work with meAbout MeContact Us

Social Media