이로

WebRtc MediaStream 본문

컴퓨터/자바스크립트

WebRtc MediaStream

利路 2020. 9. 3. 17:28
반응형

MediaStream 사용 후 기록

 

MediaStream은 WebRtc에서 사용하는 MediaStreams API 이다. 이 API 는 미디어 스트림과 스트림을 구성하는 트랙, 데이터 형식과 관련된 제한인자, 데이터를 비동기적으로 사용할 때 성공과 오류콜백 그리고 이 과정에서 발생하는 이벤트에 대한 인터페이스 및 메서드를 제공한다.

 

 MediaStream 은 0개 이상의 MediaStreamTrack으로 구성되어 있으며, MediaStreamTrack은 오디오, 비디오 트랙을 받을 수 있다. MediaStreamTrack은 하나 이상의 채널을 가질 수 있다. 여기서 채널이란 오디오로 예를 들면 오디오 트랙에서 왼쪽과 오른쪽 처럼 미디어 스트림의 제일 작은 단위를 나타낸다.

 

MediaStream 객체는 하나의 입력과 출력을 가진다. 입력은 getUserMedia()로 MediaStream 을 가져오고, 출력은 연결된 피어에게 MediaStream을 전달한다.

  • getUserMedia()로 MediaStream을 호출할 때 Promise객체로 들고온다. 2개 이상의 객체를 호출할 때 주의해야한다. 비동기적으로 작동하다보니 두 스트림을 동시에 다루는 것에 주의가 필요하다. 문서에서는 아래와 같은 방법으로 다루는걸 예시로 보여주고 있다.
async function getMedia(constraints) {
  let stream = null;

  try {
    stream = await navigator.mediaDevices.getUserMedia(constraints);
    /* 스트림 사용 */
  } catch(err) {
    /* 오류 처리 */
  }
}
  • WebRtcMultiConnection 에서는 스트림 두개를 가져 올 때 addStream으로 가져올 수 있게 되어있다. 하지만 이렇게 가져오면 채널(room)에 입장하기 전에 내 입맛대로 media stream 을 다룰 수 있는지 다시 한번 체크 해봐야한다. 문서에서는 서로 다른 기종의 카메라일 경우 카메라 2대를 동시 호출하여 전송할 수 있고, 카메라 2대 + 스크린까지 3개의 스트림도 전송할 수 있다고 한다.

MediaStream 으로 피어에 연결되서 입 출력 통로가 만들어졌을 때, 제공하는 트랙을 변경해야 할 경우가 생긴다.

  • MediaStream자체를 교체하려면 피어간의 연결을 다시해야 했다. (채널 재접속)
  • onStream으로 소비자가 영상을 받아 화면에 출력할 때, streamid로 모든 미디어를 관리하고 있는데 MediaStream 자체를 교체하면 화면에 송출되는 영상 영역이 지웠다가 다시 생기는 경우도 생겼다.
  • 이런 불편함을 극복하기위해 MediaStream을 교체하는것이 아니라, MediaStream은 그대로 놔두고 그 안의 MediaStreamTrack만 교체한다. 이 것을 교체 후 각 피어에게 트랙 교체했어! 라고 알리면 기존 송출되는 영상에서는 스무스하게 화면이 전환되거나 오디오가 전환되는것을 볼 수 있었다.
/* 출력하는 스트림 변경하, 기존 스트림은 계속 출력되며 트랙만 교체된다. 교체할 트랙의 스트림을 인자값으로 갖는다. */
            changeTracksInStreamAndRenegotiatePeers: function (stream) {
                var self = this;

                if (stream == null || stream == 'undefined') {
                    alert('해당 Stream 정보가 없습니다.');
                }

                /* 기존 streamEvents에 등록된 스트림의 트랙 교체 */
                // self.switchTrack(connection.streamEvents.selectAll('local')[0].stream, stream.getTracks());
                // self.switchTrack(connection.attachStreams[0].stream, stream.getTracks());

                var newTracks = {
                    video: null,
                    audio: null
                }

                stream.getTracks().forEach(function (track) {
                    if (track.kind == 'video') newTracks.video = track;
                    if (track.kind == 'audio') newTracks.audio = track;
                });

                /* 각 피어마다 바뀐 트랙으로 스트림 갱신 */
                connection.peers.getAllParticipants().forEach(function (pid) {
                    var peer = connection.peers[pid].peer;
                    peer.getSenders().forEach(function (sender) {
                        if (!sender || !sender.track) return;

                        if (sender.track.kind === 'video' && newTracks.video) {
                            sender.replaceTrack(newTracks.video);
                        } else if (sender.track.kind === 'audio' && newTracks.audio) {
                            sender.replaceTrack(newTracks.audio);
                        }
                    });
                });
                newTracks.video = null;
                newTracks.audio = null;
                newTracks = null;
                return;
            },

+ [덧] 위 함수는 단일책임원칙에 위배된다. 분리하는것이 좋을 듯하다.

+ [덧] self.switchTrack 은 기존 스트림의 트랙을 새로운 스트림의 트랙으로 교체하는 함수이다.

 

참고문서

반응형
Comments