웹 애플리케이션에서 오디오 출력 대상 전환

14336 단어 SkyWayWebRTC

소개



음성 출력을 다루는 웹 응용 프로그램을 만들면 음성 출력 대상을 전환하고 싶지 않습니까?
이 기사에서는 Google 크롬 한정으로 기능을 구현하는 방법을 소개합니다.

전제 조건


  • 음성 출력을 처리하는 웹 응용 프로그램으로 SkyWay의 p2p-videochat 샘플을 사용합니다.
  • Google 크롬만 기능이 구현되어 있으므로 다른 브라우저에서는 작동하지 않습니다.
  • Chrome M67 Stable에서 작동 확인


  • 데모



    여기에서 동작을 확인할 수 있습니다.

    구현 방법



    음성 출력 장치의 정보 수집



    MediaDevices.enumerateDevices() 을 이용합니다.
    navigator.mediaDevices.enumerateDevices()
        .then(function (devices) { // success
        }).catch(function (error) { // error
        return;
    });
    

    실행할 때 사용할 수 있는 I/O 미디어 장치에 대한 정보가 있는 MediaDeviceInfo 개체가 배열에서 반환됩니다.
    내 환경에서 실행하면 다음과 같은 배열이 반환됩니다. 어떤 디스플레이를 사용하고 있든, 카메라를 사용하고 있다는 것도 알 수 있습니다 w



    kind에 주목하십시오. audiooutput이 되고 있는 디바이스가 음성 출력 디바이스입니다. 이 정보를 이용합니다.

    사용자가 기기를 선택하도록 합니다.



    SkyWay의 공식 샘플 코드에는 이미 오디오 및 비디오 입력 소스를 선택하는 코드가 들어 있습니다. 이번에는 거기에 음성 출력처를 전환하는 코드도 추기합니다.
    const audioSelect = $('#audioSource');
    const videoSelect = $('#videoSource');
    const audioDeviceSelect = $('#audioDevice');  // 追記
    selectors = [audioSelect, videoSelect, audioDeviceSelect];  // 修正
    navigator.mediaDevices.enumerateDevices()
    .then(deviceInfos => {
        const values = selectors.map(select => select.val() || '');
        selectors.forEach(select => {
        const children = select.children(':first');
        while (children.length) {
            select.remove(children);
        }
        });
    
        for (let i = 0; i !== deviceInfos.length; ++i) {
        const deviceInfo = deviceInfos[i];
        const option = $('<option>').val(deviceInfo.deviceId);
    
        if (deviceInfo.kind === 'audioinput') {
            option.text(deviceInfo.label ||
            'Microphone ' + (audioSelect.children().length + 1));
            audioSelect.append(option);
        } else if (deviceInfo.kind === 'videoinput') {
            option.text(deviceInfo.label ||
            'Camera ' + (videoSelect.children().length + 1));
            videoSelect.append(option);
        } else if (deviceInfo.kind === 'audiooutput') { // ここから追記
            option.text(deviceInfo.label ||
            'Output device ' + (audioDeviceSelect.children().length + 1));
            audioDeviceSelect.append(option);             
        } // ここまで追記
        }
    
        selectors.forEach((select, selectorIndex) => {
        if (Array.prototype.slice.call(select.children()).some(n => {
            return n.value === values[selectorIndex];
        })) {
            select.val(values[selectorIndex]);
        }
        });
    
        videoSelect.on('change', step1);
        audioSelect.on('change', step1);
        audioDeviceSelect.on('change', step1); // 追記
    });
    

    수정할 위치와 추가할 위치는 댓글과 같습니다.

    음성 출력 대상 전환



    HTMLMediaElement.setSinkId() 을 이용합니다.
    const audio = document.createElement('audio');
    audio.setSinkId(deviceId);
    

    MediaDevices.enumerateDevices()로 취득한 음성 출력 디바이스의 deviceId를 인수로서 주는 것으로, 음성 출력 디바이스를 전환할 수 있습니다.
    이번에는 이렇게 이용하고 있습니다.
    if(audioDevice){
        $('#their-video').get(0).setSinkId(audioDevice);
    }
    

    deviceId가 null의 경우는 에러가 나오므로, if문으로 미리 체크하고 있습니다.

    실행해보기



    이렇게 전환할 수 있습니다. 물론 화상 채팅 중에 동적으로 전환할 수도 있습니다.



    여담 MediaDevices.enumerateDevices() 실행 타이밍



    Chrome과 Firefox 모두 MediaDevices.getUserMedia()에서 사용자가 카메라와 마이크 사용을 허용하지 않으면 labe 값을 얻을 수 없습니다.
    이번에 다룬 음성 출력 디바이스의 정보에 대해서는, 마이크의 이용을 허가하지 않으면 다음과 같이 비워집니다.



    label의 값은 UI에 출력하고 싶네요. 그런 때는, MediaDevices.getUserMedia() → 유저의 액션 → MediaDevices.enumerateDevices() 라고 하는 차례로 실행하는 것으로, 해결할 수 있습니다. Firefox는 이전부터 이러한 거동이었지만, Chrome은 최근(동료에게 조사해 주었더니 아마 M66으로부터) 이런 거동이 되고 있는 것 같으므로, 주의해 주세요. 그 전에는 사용자의 허가 없이 label 정보를 취득할 수 있었습니다.

    또한 SkyWay의 공식 샘플은 사용자가 허가하기 전에 MediaDevices.enumerateDevices()를 실행하기 때문에 처음 액세스할 때는 label 정보를 얻을 수 없습니다. 이번 데모에서는 잠정적으로 그 부분을 수정하고 있습니다.

    좋은 웹페이지 즐겨찾기