1"use strict";(self.webpackChunk_elegantstack_gatsby_starter_flexiblog_personal=self.webpackChunk_elegantstack_gatsby_starter_flexiblog_personal||[]).push([[5820],{771:function(e,t,n){n.r(t),n.d(t,{default:function(){return s}});var a=n(3696),i=n(9916);function o(e){const t=Object.assign({p:"p",h2:"h2",ul:"ul",li:"li",a:"a",strong:"strong",span:"span",code:"code",em:"em",h3:"h3",pre:"pre",del:"del",blockquote:"blockquote"},(0,i.RP)(),e.components);return a.createElement(a.Fragment,null,a.createElement(t.p,null,"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!"),"\n",a.createElement(t.p,null,"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 :-)"),"\n",a.createElement(t.h2,{id:"setup-used"},"Setup used"),"\n",a.createElement(t.p,null,"For that article, I used the following devices"),"\n",a.createElement(t.ul,null,"\n",a.createElement(t.li,null,"\n",a.createElement(t.p,null,a.createElement(t.a,{href:"https://amzn.to/3tshEkd"},"AirPods Pro (second generation)")),"\n"),"\n",a.createElement(t.li,null,"\n",a.createElement(t.p,null,a.createElement(t.a,{href:"https://www.apple.com/homepod-mini/"},"HomePod mini")),"\n"),"\n"),"\n",a.createElement("br"),"\n",a.createElement(t.h2,{id:"is-homepod-mini-the-perfect-mac-mini-speaker"},"Is HomePod mini the perfect Mac Mini speakerâ¦"),"\n",a.createElement(t.p,null,"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."),"\n",a.createElement(t.p,null,"The HomePod is connected using the ",a.createElement(t.a,{href:"https://en.wikipedia.org/wiki/AirPlay"},a.createElement(t.strong,null,"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."),"\n",a.createElement(t.p,null,"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â¦"),"\n",a.createElement(t.p,null,"Additionally, I added the HomePod to HomeKit to control my connected plugs and accessories. Everything is working well."),"\n",a.createElement(t.p,null,"So for entertainment use, it is ok. But what about more professional use, such for telecommuting and video conferencing with colleagues or clients?."),"\n",a.createElement(t.p,null,"Are the HomePod perfect for these usages too ?"),"\n",a.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<span\n class="gatsby-resp-image-wrapper"\n style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1140px; "\n >
1\n <span\n class="gatsby-resp-image-background-image"\n style="padding-bottom: 66.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url(\'data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAgQA/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAFyXHLVji//xAAcEAADAAEFAAAAAAAAAAAAAAABAgMEABESEyH/2gAIAQEAAQUCyKdapY8t9FFowxlSoHn/xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8BTZ//xAAWEQEBAQAAAAAAAAAAAAAAAAARAhD/2gAIAQIBAT8BkM//xAAaEAACAwEBAAAAAAAAAAAAAAABMQAQIQIR/9oACAEBAAY/AscZoDoYo/a//8QAGRABAQEBAQEAAAAAAAAAAAAAAQARMUFR/9oACAEBAAE/IcZ72crHxselsCUL4gCg2/V//9oADAMBAAIAAwAAABBM/wD/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxBVP//EABcRAQEBAQAAAAAAAAAAAAAAAAEAETH/2gAIAQIBAT8QY4tL/8QAGxABAAIDAQEAAAAAAAAAAAAAAQARITFRQWH/2gAIAQEAAT8QLaEB4S6NO67g97RrMsVVRaJi7Gc1qpfM/IgPvpc//9k=\'); background-size: cover; display: block;"\n ></span>\n <img\n class="gatsby-resp-image-image"\n alt="homepod mini"\n title=""\n src="/static/7d80c24e2a950467b0e667956cb869ad/0470c/homepod_mini.jpg"\n srcset="/static/7d80c24e2a950467b0e667956cb869ad/6c669/homepod_mini.jpg 285w,\n/static/7d80c24e2a950467b0e667956cb869ad/882a4/homepod_mini.jpg 570w,\n/static/7d80c24e2a950467b0e667956cb869ad/0470c/homepod_mini.jpg 1140w,\n/static/7d80c24e2a950467b0e667956cb869ad/d165a/homepod_mini.jpg 1400w"\n sizes="(max-width: 1140px) 100vw, 1140px"\n style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;"\n loading="lazy"\n decoding="async"\n />\n </span>'}}),"\n",a.createElement(t.h2,{id:"using-a-homepod-mini-with-webrtc"},"Using a HomePod mini with WebRTC"),"\n",a.createElement(t.p,null,"The first showstopper was the lack of support of the output devices and associated ",a.createElement(t.code,null,"setSinkId")," API in Safari to be able to have a 100% Apple experience. So, I used Chrome."),"\n",a.createElement(t.p,null,a.createElement(t.em,null,"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."),"\n",a.createElement(t.h3,{id:"can-homepod-mini-be-used-as-an-external-microphone-"},"Can HomePod mini be used as an external microphone ?"),"\n",a.createElement(t.p,null,"Using HomePod with WebRTC means being able to use it as an ",a.createElement(t.strong,null,"external microphone")," and as an ",a.createElement(t.strong,null,"external speaker"),"."),"\n",a.createElement(t.p,null,"Let check first, if we could use it as a microphone."),"\n",a.createElement(t.p,null,"To quickly have the result, I called the API ",a.createElement(t.code,null,"getUserMedia")," and checked if the track obtained is from the HomePod or not."),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"},"const stream = await navigator.mediaDevices.getUserMedia({audio: true});\nconst audioTrack = stream.getAudioTracks()[0];\n\n// MediaStreamTrack {kind: 'audio', id: '1e432156-29cd-4648-921b-67332892c429', label: 'Default - RODE NT-USB (19f7:0003)', enabled: true, muted: false,â¦}\n")),"\n",a.createElement(t.p,null,"The Homepod has not been selected. Hum⦠this probably means that the microphone of the HomePod is not usable for WebRTC."),"\n",a.createElement(t.p,null,"To confirm, I used the API ",a.createElement(t.code,null,"enumerateDevices")," and effectively the HomePod is not listed as an ",a.createElement(t.code,null,"audioinput")," device and so canât be used as a microphone."),"\n",a.createElement(t.h3,{id:"can-homepod-be-used-as-an-external-speaker-"},"Can HomePod be used as an external speaker ?"),"\n",a.createElement(t.p,null,"Now, let check if the HomePod can be used as an external speaker."),"\n",a.createElement(t.p,null,"As you may know, at that time of writing and even if the ",a.createElement(t.a,{href:"https://w3c.github.io/mediacapture-output/"},"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
1select them using the API ",a.createElement(t.code,null,"setSinkId"),"."),"\n",a.createElement(t.p,null,"Firefoxâs implementation of ",a.createElement(t.code,null,"setSinkId")," is still behind a flag and nothing found with Safari Technology Previewâ¦"),"\n",a.createElement(t.p,null,"Additionally, to that method, this specification introduces a new method ",a.createElement(t.code,null,"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 ",a.createElement(t.code,null,"autoplay")," is a brake to propose that API. So no implementation exists at this time."),"\n",a.createElement(t.p,null,"So ok⦠I will just use the ",a.createElement(t.code,null,"setSinkId")," in Chromeâ¦"),"\n",a.createElement(t.p,null,"For the first test, I didnât select the HomePod as my default speaker in the Mac sound panel. In that case, calling ",a.createElement(t.code,null,"enumerateDevices")," didnât enumerate it."),"\n",a.createElement(t.p,null,"I have to select it first in the Mac sound panel and only after I called the ",a.createElement(t.code,null,"eumerateDevices")," API in Chrome to see if the HomePod is listed"),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"},"const devices = await navigator.mediaDevices.enumerateDevices();\n\n// MediaDeviceInfo {deviceId: '67b8f458a6df...b46', kind: 'audiooutput', label: 'AirPlay (AirPlay)', groupId: '604b960cf...4fa'}\n")),"\n",a.createElement(t.p,null,"This time, I found it but not exactly with the name I expected to find: ",a.createElement(t.strong,null,"AirPlay (Airplay)")," is the pretty name given to the HomePod⦠Donât know what happens if you have more than one HomePod :-)"),"\n",a.createElement(t.p,null,"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 ",a.createElement(t.strong,null,"Freebox Player (AirPLay)")," which is really better. It is a shame that the HomePod is not better identified. Is Chrome doing this on purpose?â¦"),"\n",a.createElement(t.p,null,"Now, that I have my HomePod listed, the next is to try to switch to that speaker using the API ",a.createElement(t.code,null,"setSinkId"),"."),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"}," const outputSelect = document.querySelector('#outputDevicesSelect');\n const audioElt = document.querySelector(\"#audioElt\");\n\n outputSelect.onchange = async (event) => {\n try {\n await audioElt.setSinkId(event.target.value);\n } catch (err) {\n // In case of error\n }\n }\n")),"\n",a.createElement(t.p,null,"I succeeded to switch the audio to the HomePod and switch from different speakers to the HomePod and vice versa."),"\n",a.createElement(t.p,null,"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."),"\n",a.createElement(t.h3,{id:"using-the-homepod-mini-in-a-webrtc-call"},"Using the HomePod mini in a WebRTC call"),"\n",a.createElement(t.p,null,"For testing the HomePod in real situation, I took our worldwide ",a.createElement(t.a,{href:"https://www.openrainbow.com/"},"Alcatel-Lucent Enterprise Rainbow")," solution and made a WebRTC call from my ",a.createElement(t.strong,null,"Rainbow Android")," application (Lenovo tablet) to my ",a.createElement(t.strong,null,"Rainbow Desktop")," application (Mac). I configured the Rainbow Desktop for using the HomePod as the speaker and my Rode device as the microphone."),"\n",a.createElement(t.p,null,"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."),"\n",a.createElement(t.p,null,"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."),"\n",a.createElement(t.h2,{id:"using-airpods"},"Using Airpods"),"\n",a.createElement(t.p,null,"Regarding the Airpods, I should not have any surprises when using them. They should propose to act as microphone and speaker (earpiece)."),"\n",a.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<span\n class="gatsby-resp-image-wrapper"\n style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1140px; "\n >
1\n <span\n class="gatsby-resp-image-background-image"\n style="padding-bottom: 66.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url(\'data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwAE/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAZxGb2RQ/wD/xAAZEAEBAQADAAAAAAAAAAAAAAABAgARIUH/2gAIAQEAAQUCmUvzU9HKu//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAIBBQAAAAAAAAAAAAAAAAABEQIQITEy/9oACAEBAAY/Ak69sTiJMjOnb//EABoQAQACAwEAAAAAAAAAAAAAAAEAIRExQaH/2gAIAQEAAT8hvCb2Y23cnVqsZJjMtFUxo43P/9oADAMBAAIAAwAAABDb/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAARARD/2gAIAQMBAT8Qqsz/xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8QADJ//8QAHBABAQADAAMBAAAAAAAAAAAAAREAITFBYYGx/9oACAEBAAE/EJRbgWlGr9mF8HQq0eejHbArYnPB+YinjLUolQZ8wHRB1M//2Q==\'); background-size: cover; display: block;"\n ></span>\n <img\n class="gatsby-resp-image-image"\n alt="airpods"\n title=""\n src="/static/4792fdaabadbc3f28e7f33cf4cab9948/0470c/airpods.jpg"\n srcset="/static/4792fdaabadbc3f28e7f33cf4cab9948/6c669/airpods.jpg 285w,\n/static/4792fdaabadbc3f28e7f33cf4cab9948/882a4/airpods.jpg 570w,\n/static/4792fdaabadbc3f28e7f33cf4cab9948/0470c/airpods.jpg 1140w,\n/static/4792fdaabadbc3f28e7f33cf4cab9948/d165a/airpods.jpg 1400w"\n sizes="(max-width: 1140px) 100vw, 1140px"\n style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;"\n loading="lazy"\n decoding="async"\n />\n </span>'}}),"\n",a.createElement(t.h3,{id:"discovering-the-airpods"},"Discovering the Airpods"),"\n",a.createElement(t.p,null,"In order for the browser to detect the Airpods, they should be set in your ears."),"\n",a.createElement(t.p,null,"Once placed in your ears, they appear in the Mac Sound panel and can be listed by using the API ",a.createElement(t.code,null,"enumerateDevices"),"."),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"},"const devices = await navigator.mediaDevices.enumerateDevices();\n\n// InputDeviceInfo {deviceId: 'default', kind: 'audioinput', label: 'AirPods', groupId: 'b067ddb7d3e0a051c5bc320a033ed934e2ab8166a8bda18f3a393e6a221ce862'}\n// InputDeviceInfo {deviceId: '23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d', kind: 'audioinput', label: 'AirPods', groupId: 'b067ddb7d3e0a051c5bc320a033ed934e2ab8166a8bda18f3a393e6a221ce862'}\n// MediaDeviceInfo {deviceId: 'default', kind: 'audiooutput', label: 'AirPods', groupId: '0eaa06962d3daf3ede1d2e2eed22b91901ed2b170b5b4be12c68d49ca4bb9c6a'}\n// MediaDeviceInfo {deviceId: '61b7d914c37b31ac931c57c137ffaee7225702cebe1539a1d7e42b4e227cee2a', kind: 'audiooutput', label: 'AirPods', groupId: '0eaa06962d3daf3ede1d2e2eed22b91901ed2b170b5b4be12c68d49ca4bb9c6a'}\n")),"\n",a.createElement(t.p,null,"This is the habit in Chrome, the system ",a.createElement(t.em,null,"default")," device is displayed twice in the list: one time with label equals to ",a.createElement(t.code,null,"default")," and a second time with its real ",a.createElement(t.code,null,"deviceId"),"."),"\n",a.createElement(t.p,null,"Unlike for the HomePod, this time, the Airpods are clearly identified: no doubt is possible."),"\n",a.createElement(t.p,null,"But something is strange in Chrome, the ",a.createElement(t.code,null,"groupId")," which should be the same when devices belong to the same physical equipment is different here: We have a ",a.createElement(t.code,null,"groupId")," for the microphone and a second one for the speakerâ¦"),"\n",a.createElement(t.p,null,"To be sure, I tested using Firefox (by activating the flag ",a.createElement(t.code,null,"setSinkId")," in ",a.createElement(t.em,null,"about:config"),") and Firefox groups the two devices by having a unique groupId. Well done Firefox!"),"\n",a.createElement(t.p,null,"Thatâs why, after checking that there is no existing issue opened in Chrome, ",a.createElement(t.del,null,"I created a new ",a.createElement(t.a,{href:"https://bugs.chromium.org/p/chromium/issues/detail?id=1329578"},"Chrome issue")," to check if there is a reason or to fix this bug"),"."),"\n",a.createElement(t.blockquote,null,"\n",a.createElement(t.p,null,"This bug was already detected since Chrome M99: ",a.createElement(t.a,{href:"https://bugs.chromium.org/p/chromium/issues/detail?id=1292367"},"https://bugs.chromium.org/p/chromium/issues/detail?id=1292367"),"."),"\n"),"\n",a.createElement(t.h3,{id:"detecting-the-airpods"},"Detecting the Airpods"),"\n",a.createElement(t.p,null,"I made a second test by using the event ",a.createElement(t.code,null,"devicechange")," to see if and when the Airpods are detected."),"\n",a.createElement(t.p,null,"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 ",a.createElement(t.code,null,"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."),"\n",a.createElement(t.p,null,"Not really developers friendly."),"\n",a.createElement(t.p,null,"Here is a little function I made to compare between the list of devices got before the event ",a.createElement(t.code,null,"devicechange")," and after."),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"},"let currentListOfDevices = []; // Current list of devices\nlet devicesChanged = false; // Devices just changed\n\nconst compare = (current, update) => {\n // Return the number of devices added (positive) or removed (negative) and the devices information\n let result = {\
1n count: 0,\n list: [],\n };\n\n // Same number of devices. We assume that there is no difference.\n if (current.length === update.length) {\n return result;\n }\n\n if (current.length > update.length) {\n // This is the case when devices have been plugged in\n let newDevices = current.filter((device) => {\n return !update.some((elt) => elt.deviceId === device.deviceId);\n });\n\n return {\n count: newDevices.length,\n list: newDevices,\n };\n }\n\n // Here, devices have been unplugged\n let removedDevices = update.filter((device) => {\n return !current.some((elt) => {\n return elt.deviceId === device.deviceId;\n });\n });\n\n return {\n count: 0 - removedDevices.length,\n list: removedDevices,\n };\n};\n\nnavigator.mediaDevices.ondevicechange = async (event) => {\n if(!devicesChanged) {\n devicesChanged = true;\n setTimeout(async () => {\n const devices = await navigator.mediaDevices.enumerateDevices();\n // diff contains the list of devices added or removed\n const diff = compare(currentListOfDevices, devices);\n // Reset\n devicesChanged = false;\n }, 500);\n }\n}\n")),"\n",a.createElement(t.p,null,"Using that code, I got the following result:"),"\n",a.createElement(t.ul,null,"\n",a.createElement(t.li,null,"\n",a.createElement(t.p,null,a.createElement(t.code,null,"devicechange")," is triggered only when the AirPods are put in your ears, not when they are moved out ot the box"),"\n"),"\n",a.createElement(t.li,null,"\n",a.createElement(t.p,null,a.createElement(t.code,null,"devicechange")," is triggered as soon as you remove the AirPods from your ears."),"\n"),"\n"),"\n",a.createElement(t.p,null,"To go further, if they are several devices added but with the same ",a.createElement(t.code,null,"groupId"),", you can deduce that the user has connected a single physical device (except for the AirPods at this timeâ¦)."),"\n",a.createElement(t.p,null,a.createElement(t.em,null,"Note"),": Using the ",a.createElement(t.code,null,"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â¦"),"\n",a.createElement(t.p,null,"Then, I observed a strange thing when connected my AirPods:"),"\n",a.createElement(t.ul,null,"\n",a.createElement(t.li,null,"\n",a.createElement(t.p,null,"Airpods are selected in the Mac sound panel"),"\n"),"\n",a.createElement(t.li,null,"\n",a.createElement(t.p,null,"Calling ",a.createElement(t.code,null,"getUserMedia")," without specifying the ",a.createElement(t.code,null,"deviceId")," of the AirPods leads to a track obtained from another deviceâ¦"),"\n"),"\n"),"\n",a.createElement(t.p,null,"So, I have to add a constraint on the ",a.createElement(t.code,null,"deviceId")," to obtain a track from the AirPods."),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"},"const constraints = { audio: { deviceId: { exact: '23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d' }} }; // deviceId of the AirPods got from enumerateDevices\nconst stream = await navigator.mediaDevices.getUserMedia(constraints);\n\nconst audioTrack = stream.getAudioTracks()[0];\n// MediaStreamTrack {kind: 'audio', id: 'd58e1f88-4835-4258-8e91-53c8b32d1fa5', label: 'AirPods', enabled: true, muted: false, â¦}\n")),"\n",a.createElement(t.h3,{id:"using-the-airpods-in-a-webrtc-call"},"Using the AirPods in a WebRTC call"),"\n",a.createElement(t.p,null,"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."),"\n",a.createElement(t.p,null,"I checked which constraints could be applied on the AirPods to see if we can send an audio stereo stream. Calling the API ",a.createElement(t.code,null,"getCapabilities")," on the ",a.createElement(t.strong,null,"track")," obtained will reveal the answer"),"\n",a.createElement(t.pre,null,a.createElement(t.code,{className:"language-js"},'// Target the Airpods\nconst constraints = { audio: { deviceId: { exact: \'23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d\'} }};\n// Get the stream\nconst stream = await navigator.mediaDevices.getUserMedia(constraints);\n// Get the audio track coming from the Airpods\nconst track = stream.getAudioTracks()[0];\n\n// Get the capabilities\ntrack.getCapabilities();\n\n// autoGainControl: (2) [true, false]\n// channelCount: {max: 1, min: 1}\n// deviceId: "23cb39500e37d5e5a9d0c5121d465c85a5016918f4be8023bc29ac6bd9d87e1d"\n// echoCancellation: (2) [true, false]\n// groupId: "ba15099a5a280fccb98205d558a61b1baec70be81b5d73b4d15323127c413310"\n// latency: {max: 0.170666, min: 0.005333}\n// noiseSuppression: (2) [true, false]\n// sampleRate: {max: 48000, min: 24000}\n// sampleSize: {max: 16, min: 16}\n')),"\n",a.createElement(t.p,null,"And the answer is no. AirPods microphone captures in mono. At home, I tested several microphones: Only my external ",a.createElement(t.strong,null,"Rode NT-USB")," microphone was able to supp
1ort capturing in stereo."),"\n",a.createElement(t.h2,{id:"conclusion"},"Conclusion"),"\n",a.createElement(t.p,null,"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."),"\n",a.createElement(t.p,null,"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 :-)"),"\n",a.createElement(t.p,null,"This let me doing conferencing comfortably!"))}var l=function(e){void 0===e&&(e={});const{wrapper:t}=Object.assign({},(0,i.RP)(),e.components);return t?a.createElement(t,e,a.createElement(o,e)):o(e)},r=n(2141);function s(e){return a.createElement(r.A,e,a.createElement(l,e))}r.A},982:function(e,t,n){n.d(t,{A:function(){return o}});n(3696);var a=n(8074),i=n(6474);var o=e=>{let{children:t}=e;return(0,i.Y)(a.mc,{variant:"sticky"},t)}},2141:function(e,t,n){n.d(t,{A:function(){return ce}});var a=n(8102),i=n(4300),o=n(9257),l=n(3696),r=n(8074),s=n(8240),c=n(8657),d=n(7564),A=n(982),u=n(5347),m=n(6885),h=n(9112),p=n(4626),g=n(4655),b=n(3175),f=n(6474);const v=["author","omitSocial"],E={wrapper:{textAlign:"center"},avatarWrapper:{mb:4},title:{color:"omegaDark"}};var w=e=>{let{author:t,omitSocial:n}=e,i=(0,o.A)(e,v);return t?(0,f.Y)(p.A,(0,a.A)({aside:!0,title:"The Author"},i),(0,f.Y)(r.Zp,{variant:"paper"},(0,f.Y)(r.az,{sx:E.wrapper},t.thumbnail&&(0,f.Y)(r.az,{sx:E.avatarWrapper},(0,f.Y)(r.N_,{as:m.N_,to:t.slug,"aria-label":t.name},(0,f.Y)(g.A,{avatar:t.thumbnail,alt:t.name,withPattern:!0}))),(0,f.Y)(r.N_,{as:m.N_,to:t.slug},(0,f.Y)(r.DZ,{variant:"h3"},t.name)),(0,f.Y)(r.DZ,{variant:"h4",sx:E.title},t.title),!n&&t.social&&(0,f.Y)(h.A,{variant:"horizontal",items:(0,b.A)(t.social),iconOnly:!0})))):""},y=n(6751);const x={item:{display:"block","& + &":{mt:3}},number:{color:"alpha",display:"flex",alignItems:"center",justifyContent:"center",bg:"omegaLighter",borderRadius:"full",size:25,mr:2,mb:0},text:{flex:"1",lineHeight:"heading",mb:0}};var Y=e=>{let{tableOfContents:{items:t=[]}}=e;return t.length>1?(0,f.Y)(p.A,{aside:!0,title:"Table Of Contents"},(0,f.Y)(r.Zp,{variant:"paper"},t.map((e,t)=>(0,f.Y)(r.N_,{key:"item-"+t,as:m.N_,to:e.url,variant:"vertical",sx:x.item},(0,f.Y)(r.so,{sx:{alignItems:"baseline"}},(0,f.Y)(r.DZ,{variant:"h5",as:"div",sx:x.number},t+1),(0,f.Y)(r.EY,{sx:x.text},e.title)))))):null},I=n(6549),k=n(4968);const P={item:{display:"inline-block"}},B=e=>{let{title:t,author:n,date:a,timeToRead:i,category:o}=e;const l=(0,f.Y)(I.A,null,n&&n.slug&&(0,f.Y)(r.EY,{sx:P.item},"By ",(0,f.Y)(r.N_,{variant:"mute",as:m.N_,to:n.slug},(0,f.Y)("strong",null,n.name))),o&&o.slug&&(0,f.Y)(r.EY,{sx:P.item},"Published in ",(0,f.Y)(r.N_,{variant:"mute",as:m.N_,to:o.slug},(0,f.Y)("strong",null,o.name))),a&&(0,f.Y)(r.EY,{sx:P.item},a),i&&(0,f.Y)(r.EY,{sx:Object.assign({},P.item,{color:"error"})},(0,f.Y)("strong",null,i," min read")));return(0,f.Y)(k.A,{header:t,running:l})};var D=n(8116),C=n(4203),j=n(5135);const Q={regular:{minHeight:"23rem",img:{borderRadius:"lg"}},wide:{img:{borderRadius:"lg"}},inCard:{mt:-4,mx:-4,img:{borderRadius:e=>e.radii.lg+" "+e.radii.lg+" 0 0"}},inCardLarge:{mt:[-4,-5],mx:[-4,-5],img:{borderRadius:e=>e.radii.lg+" "+e.radii.lg+" 0 0"}}},R=e=>{let{title:t,thumbnail:n,wide:a,full:i,inCard:o,inCardLarge:r}=e;if(!n)return null;const s=(a?"wide":i&&"full")||"regular",c=(0,j.A)(n,"hero");return(0,f.Y)(l.Fragment,null,(0,f.Y)(D.G,{image:c,alt:t,css:(0,C.A)(Object.assign({},Q[s],o&&Q.inCard,r&&Q.inCardLarge)),imgStyle:"wide"===s||"full"===s?Q.full:void 0}),(0,f.Y)(d.A,{space:3}))};var T=n(9916),N=n(9304);const S={heading:{svg:{visibility:"hidden",size:"icon.xs",position:"absolute",top:"50%",transform:"translate(0,-50%)",pl:2},":hover svg":{visibility:"visible"},pointerEvents:"painted"},link:{position:"relative"}},H=e=>t=>(0,f.Y)(e,(0,a.A)({},t,{css:(0,C.A)(S.heading)}),(0,f.Y)(r.N_,{href:"#"+t.id,variant:"text."+e,sx:S.link},t.children,(0,f.Y)(N.AnD,null)));var M={h1:H("h1"),h2:H("h2"),h3:H("h3")};var z=e=>(0,f.Y)("figure",(0,a.A)({},e,{css:(0,C.A)(e=>e.styles.figure)}),e.children);var W=e=>(0,f.Y)("figcaption",(0,a.A)({},e,{css:(0,C.A)(e=>e.styles.figcaption)}),e.children),F=n(3915);const _=["className","children"],O=l.lazy(()=>n.e(3079).then(n.bind(n,3079)));var U=e=>{let{className:t,children:n}=e,i=(0,o.A)(e,_);return t?(0,f.Y)(l.Suspense,{fallback:(0,f.Y)(F.WJ.pre,null,n)},(0,f.Y)(O,(0,a.A)({className:t},i),n)):(0,f.Y)(F.WJ.code,null,n)},G=Object.assign({figure:z,figcaption:W,pre:e=>e.children,code:U},M);const L=e=>{let{children:t}=e;return(0,f.Y)(T.xA,{components:G},t)},Z={wrapper:{alignItems:"center"},heading:{color:"omegaDark",mr:3,mb:0}},q=e=>{let{tags:t}=e;return t&&t.length>0?(0,f.Y)(r.so,{sx:Z.wrapper},(0,f.Y)(r.DZ,{variant:"h5",sx:Z.heading},"Tags"),(0,f.Y)(r.az,{variant:"lists.badges"},t.map(e=>{let{id:t,name:n,slug:a}=e;return(0,f.Y)(r.Ex,{variant:"tag",key:t,as:m.N_,to:a},n)}))):null},J=l.lazy(()=>Promise.all([n.e(6593),n.e(8652)]).then(n.bind(n,8652))),V={flex:{alignItems:["flex-start","center"],justifyContent:"space-between",flexDirection:["column","row"],"& > div + div":{mt:[3,0],flexBasis:"1/2",justifyContent:"flex-end"}}},X=e=>(0,f.Y)(r.az,null,(0,f.Y)(r.cG,null),(0,f.Y)(r.so,{sx:V.flex},(0,f.Y)(q,e),(0,f.Y)(l.Suspense,{fallback:null},(0,f.Y)(J,e)))),K=l.lazy(()=>n.e(7065).then(n.bind(n,7065))),$=()=>(0,f.Y)(l.Suspense,{fallback:null},(0,f.Y)(K,null)),ee=l.lazy(()=>n.e(4503).then(n.bind(n,4503))),te=()=>(0,f.Y)(l.Suspense,{fallback:null},(0,f.Y)(ee,null)),ne=l.lazy(()=>n.e(4667).then(n.bind(n,4667))),ae=()=>(0,f.Y)(l.Suspense,{fallback:null},(0,f.Y)(ne,null)),ie={wrapper:{bg:"omegaLight",borderRadius:"bottom",color:"omegaDark",borderStyle:"solid",borderWidth:"md",borderColor:"contentBg",mx:-4,mb:-4,mt:4},flex:{flexWrap:"wrap",justifyContent:"space-between",p:4},item:{flexBasis:"50%"},next:{textAlign:"right"},guide:{mb:2}},oe=e=>{let{title:t,post:n}=e;return(0,f.Y)(l.Fragment,null,(0,f.Y)(r.EY,{sx:ie.guide},t),(0,f.Y)(r.DZ,{variant:"h4",as:m.N_,to:n.slug},n.title))},le=e=>{let{previous:t,next:n}=e;
1return n||t?(0,f.Y)(r.az,{sx:ie.wrapper},(0,f.Y)(r.so,{sx:ie.flex},(0,f.Y)(r.az,{sx:ie.item},t&&(0,f.Y)(oe,{post:t,title:"Previous Article"})),(0,f.Y)(r.az,{sx:Object.assign({},ie.item,ie.next)},n&&(0,f.Y)(oe,{post:n,title:"Next Article"})))):null};var re=n(4909);const se=["data","children"];var ce=e=>{var t;let{data:{post:n,tagCategoryPosts:m,tagPosts:h,categoryPosts:p,previous:g,next:b},children:v}=e,E=(0,o.A)(e,se);const x=[].concat((0,i.A)(m?m.nodes:[]),(0,i.A)(h?h.nodes:[]),(0,i.A)(p?p.nodes:[])),{pageContext:{services:I={},siteUrl:k}={}}=E,P=(0,re.Wk)();return(0,f.Y)(s.PE,E,(0,f.Y)(u.A,(0,a.A)({},n,{siteUrl:k})),(0,f.Y)(d.A,null),(0,f.Y)(s.BJ,{effectProps:{effect:"fadeInDown"}},(0,f.Y)(B,n)),(0,f.Y)(d.A,null),(0,f.Y)(s.BJ,{effectProps:{fraction:0}},(0,f.Y)(s.gZ,null,(null===(t=n.tableOfContents)||void 0===t?void 0:t.items)&&(0,f.Y)(l.Fragment,null,(0,f.Y)(Y,n),(0,f.Y)(d.A,null)),(0,f.Y)(r.Zp,{variant:"paper"},(0,f.Y)(R,(0,a.A)({},n,{inCard:!0})),(0,f.Y)(L,n,v),(0,f.Y)(X,(0,a.A)({},n,{location:E.location})),I.disqus&&(0,f.Y)($,n),I.graphComment&&(0,f.Y)(ae,n),I.facebookComment&&(0,f.Y)(te,(0,a.A)({},n,{siteUrl:k})),(0,f.Y)(le,{previous:g,next:b}))),(0,f.Y)(s.Bx,null,(0,f.Y)(w,{author:n.author,omitTitle:!0}
1),(0,f.Y)(d.A,null),(0,f.Y)(y.A,{categories:P}),(0,f.Y)(d.A,null),n.category&&(0,f.Y)(A.A,null,(0,f.Y)(c.A,{title:"Related Posts",nodes:x,variant:"horizontal-aside",omitMedia:!0,omitCategory:!0,limit:6,distinct:!0,aside:!0})))))}},4655:function(e,t,n){n.d(t,{A:function(){return u}});n(3696);var a=n(8116),i=n(8074),o=n(4203),l=n(7409),r=n(5135),s=n(6474);const c=e=>.35*e+"rem",d={wrapper:{position:"relative",zIndex:2,textAlign:"center",mb:c(3)},pattern:{backgroundSize:"8rem",opacity:.15},circle:e=>{let{width:t}=e;return{width:[c(30),"full"],height:"full",maxWidth:t,borderRadius:"full",position:"absolute",transform:"translate(-50%) scale(0.98)",left:"50%",top:c(3),bg:"alpha"}},arc:e=>{let{width:t}=e;return{width:[c(30),"full"],height:"full",maxWidth:t,borderRadius:"full",position:"absolute",zIndex:2,left:"50%",transform:"translate(-50%)",mt:c(-1),ml:c(-2),boxShadow:e=>"\n\t\t\t"+c(2)+"\n\t\t\t"+c(4)+"\n\t\t\t"+e.colors.omegaLight+"\n\t\t"}},imageWrapper:{mx:"auto",img:{borderRadius:"0 0 9999px 9999px"}}},A=e=>{let{avatar:t,withPattern:n,patternStyles:c={},size:A,width:u,loading:m,alt:h}=e;const p=t&&(0,r.A)(t,A);return p?(u=u||p.width,(0,s.Y)(i.az,{sx:d.wrapper},(0,s.Y)(i.az,null,n&&(0,s.Y)(l.A,{sx:Object.assign({},d.pattern,c)}),(0,s.Y)(i.az,{sx:d.circle({width:u})}),(0,s.Y)(i.az,{sx:d.arc({width:u})}),(0,s.Y)(a.G,{image:p,alt:h,loading:m,css:(0,o.A)(d.imageWrapper)})))):null};var u=A;A.defaultProps={size:"regular",withPattern:!1}},4909:function(e,t,n){n.d(t,{YP:function(){return r},Wk:function(){return o},XZ:function(){return c}});var a=n(6885),i=n(5847);const o=()=>{const{allArticleCategory:e}=(0,a.GR)(l);return e.nodes?(0,i.A)(e.nodes,e=>e.slug):null},l="4235339838",r=()=>{const{allArticleAuthor:e}=(0,a.GR)(s);return e.nodes?(0,i.A)(e.nodes,e=>e.slug):null},s="4240507859",c=()=>{const{allArticleTag:e}=(0,a.GR)(d);return e.nodes||[]},d="2918496967"},4968:function(e,t,n){n.d(t,{A:function(){return l}});n(3696);var a=n(8074),i=n(6474);const o={count:{fontSize:4},subheader:{fontWeight:"body",color:"omegaDark"},runninghead:{fontWeight:"body",color:"omegaDark",mb:0}};var l=e=>{let{header:t,subheader:n,running:l,totalCount:r}=e;return(0,i.Y)("div",null,(0,i.Y)(a.DZ,{variant:"h1",as:"h1"},t," ",r&&(0,i.Y)(a.Ex,{variant:"tag-white",sx:o.count}," ",r)),n&&(0,i.Y)(a.EY,{variant:"h3",sx:o.subheader},n),l&&(0,i.Y)(a.EY,{variant:"h4",sx:o.runninghead},l))}},6751:function(e,t,n){n.d(t,{A:function(){return b}});var a=n(8102),i=n(9257),o=(n(3696),n(8074)),l=n(9304),r=n(6885),s=n(1575),c=n(6474);const d={button:{vertical:{variant:"cards.primary",display:"flex",alignItems:"center",textAlign:"initial",overflow:"hidden",mb:3,p:0,pr:2,svg:{color:"omegaDark",verticalAlign:"middle",size:"icon.xs"},":hover":{svg:{color:"white"},"div:first-of-type":{bg:"alpha"}}},horizontal:{variant:"cards.interactive",p:0,svg:{color:"alpha",size:"icon.sm"},":hover":{svg:{color:"omegaDark"}}}},icon:{vertical:{display:["flex","none","flex"],transition:"all 250ms ease",alignItems:"center",justifyContent:"center",alignSelf:"stretch",bg:"omegaLight",width:70},horizontal:{display:["block","none","block"],boxSizing:"content-box",transition:"all 250ms ease",borderRadius:"bottom",width:"1/3",height:"icon.sm",mx:"auto",pt:3}},text:{flex:"auto",color:"omegaDark",whiteSpace:"nowrap",p:3,m:0}},A=e=>{let{variant:t,name:n,Icon:a,iconPath:i,iconColor:l,to:A}=e;return(0,c.Y)(o.$n,{variant:"none",as:A&&r.N_,to:A,sx:d.button[t]},(a||i)&&(0,c.Y)(o.az,{sx:d.icon[t]},i&&(0,c.Y)(s.A,{src:i}),a&&(0,c.Y)(a,{color:l})),(0,c.Y)(o.DZ,{variant:"h4",as:"span",sx:d.text},n))};var u=A;A.defaultProps={variant:"horizontal",number:void 0};var m=n(4626);const h=["variant","categories"],p={horizontal:{display:"flex",flexWrap:"nowrap",overflowX:"auto",width:"auto",scrollBehavior:"smooth",m:-2,a:{flex:1,minWidth:["1/3","auto"],m:2}}},g=e=>{let{variant:t,categories:n}=e,r=(0,i.A)(e,h);return(0,c.Y)(m.A,(0,a.A)({aside:"vertical"===t,title:"Topics"},r),(0,c.Y)(o.az,{sx:p[t]},n&&n.map(e=>{let{id:n,name:a,slug:i,totalCount:o,icon:r}=e;const s={key:n,name:a,number:o,to:i,iconPath:r,Icon:!r&&l.Wlj,variant:t};return 0!==o&&(0,c.Y)(u,s)})))};var b=g;g.defaultProps={variant:"vertical"}}}]); 2//# sourceMappingURL=component---packages-blog-gatsby-blog-core-src-templates-post-js-content-file-path-content-posts-others-apple-ecosystem-with-webrtc-index-mdx-1874068ed2a37d5a6c63.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.