【问题标题】:Twilio Programmable Video JS / IonicTwilio 可编程视频 JS / Ionic
【发布时间】:2017-06-20 19:20:00
【问题描述】:

我正在使用 Twilio 可编程视频 JS SDK,但遇到了一些问题。我已经获取了他们的示例代码,我能够创建一个房间并连接到它,它确实触发了我的相机/麦克风,但没有一个事件正在触发,这些事件处理诸如将视频绑定到 DOM、显示事件等。

这是基于 Angular 1 和 Ionic 框架构建的 Cordova 应用程序的一部分。这是我的控制器中的代码:

angular.module('smartlab.controllers').controller('SupportVideoCtrl', ['$scope', '$http', function($scope, $http) {

    // include Twilio Video library
    const Video = Twilio.Video;

    // call our "cross origin friendly" smartlab cloud server to get Twilio token (they can only be generated server-side)

    $http.get('TOKEN_URL', function(data) {

    }).then(function(data) {
        console.log(data);
        console.log("Token = " + data.data.token);

        Video.connect(data.data.token, { name: 'Support' }).then(room => {
            console.log('Connected to Room "%s"', room.name);

            // None of the events below fire
            room.participants.forEach(participantConnected);  
            room.on('participantConnected', participantConnected);
            room.on('participantDisconnected', participantDisconnected);
            room.once('disconnected', error => room.participants.forEach(participantDisconnected));

        });
    });

    function participantConnected(participant) {
        console.log('Participant "%s" connected', participant.identity);

        const div = document.createElement('div');
        div.id = participant.sid;
        div.innerText = participant.identity;

        participant.on('trackAdded', track => trackAdded(div, track));
        participant.tracks.forEach(track => trackAdded(div, track));
        participant.on('trackRemoved', trackRemoved);

        console.log("Participant Connected");
        console.dir(div);

        document.body.appendChild(div);
    }

    function participantDisconnected(participant) {
        console.log('Participant "%s" disconnected', participant.identity);

        participant.tracks.forEach(trackRemoved);

        document.getElementById(participant.sid).remove();
    }

    function trackAdded(div, track) {
        console.log("Track added");
        console.dir(div);
        console.dir(track);
        div.appendChild(track.attach());
    }

    function trackRemoved(track) {
        track.detach().forEach(element => element.remove());
    }

}]);

有没有人使用过这个库并且有一些示例代码可以从中提取或看到上面的代码有什么问题?我已经检查了他们的示例 NodeJS 应用程序,但它与我在这里的实现完全不同,所以它不是超级有用。谢谢!

【问题讨论】:

  • 你在这个过程中走了多远?例如,console.log('Connected to Room "%s"', room.name); 被调用并记录了吗?
  • 嘿菲尔!在 room.participants.forEach() 之后,我的代码中有一个日志(不在上面),我 确实 看到了该日志。之后什么都没有......如果我注销 room.participants 它没有任何成员,只是一个空数组。
  • 哦,你也是在哪个平台上构建的?
  • Phil:我目前在 Windows 上进行开发,但应用程序将用于 Android,可能还会用于 iOS。
  • 能否再试一次,但将视频 SDK 设置为调试日志记录模式,看看会发生什么? Video.connect('token', { name: 'Support', logLevel: 'debug' })。谢谢

标签: javascript angularjs video twilio twilio-api


【解决方案1】:

经过大量的试验和错误 + 一些与伟大的 Phil Nash 的反复试验后,我有了一个运行良好的解决方案。这现在是我们使用 Ionic Framework 构建的 Cordova 移动应用程序的一部分。

HTML:

<ion-view class="app-tab" hide-nav-bar="true" view-title="Support">
    <ion-content class="padding">
        <h3 class="tab-header-text">Live Video Support</h3>
        <div id="call-connected">Connected to Live Tech Support</div>

        <div id="controls">
            <div id="preview" style="float:left;">
                <div id="local-media"></div>
                <button id="button-preview" style="margin-left:40px;">Preview My Camera</button>
            </div>
            <div id="call-controls" class="call-button-div">
                <i id="button-call" class="icon ion-ios-telephone-outline call-buttons" style="color:green;"></i>
                <i id="button-call-end" class="icon ion-ios-telephone-outline call-buttons" style="color:red; display:none;"></i>
            </div>
        </div>
        <div id="spin-wrapper"><ion-spinner name="circles"></ion-spinner></div>

        <div id="remote-media">
            <div id="video-overlay">Nicholas Kreidberg</div>
        </div>

    </ion-content>
</ion-view>

JS:

angular.module('PROJECT_NAME.controllers').controller('SupportVideoCtrl', ['$rootScope', '$scope', '$http', function($rootScope, $scope, $http) {

    // instantiate Twilio Programmable Video library
    const Video = Twilio.Video;

    // setup some vars
    var activeRoom;
    var previewTracks;
    var identity;
    var roomName;

    // Attach the Tracks to the DOM.
    function attachTracks(tracks, container) {
        tracks.forEach(function(track) {
            container.appendChild(track.attach());
        });
    }

// Attach the Participant's Tracks to the DOM.
    function attachParticipantTracks(participant, container) {
        var tracks = Array.from(participant.tracks.values());
        attachTracks(tracks, container);
    }

// Detach the Tracks from the DOM.
    function detachTracks(tracks) {
        tracks.forEach(function(track) {
            track.detach().forEach(function(detachedElement) {
                detachedElement.remove();
            });
        });
    }

// Detach the Participant's Tracks from the DOM.
    function detachParticipantTracks(participant) {
        var tracks = Array.from(participant.tracks.values());
        detachTracks(tracks);
    }

    // When we are about to transition away from this page, disconnect
    // from the room, if joined.
    window.addEventListener('beforeunload', leaveRoomIfJoined);

    $rootScope.$on('$stateChangeSuccess',
        function(event, toState, toParams, fromState, fromParams) {
            leaveRoomIfJoined();
        }
    );

    $http.get('TOKEN_URL', function(data) {

    }).then(function(data) {
        console.log(data);
        console.log("Token = " + data.data.token);

        //document.getElementById('room-controls').style.display = 'block';

        // Bind click event and add token to data attribute
        document.getElementById('button-call').addEventListener('click', connect);
        document.getElementById('button-call').setAttribute('data-token', data.data.token);

        // Connect
        connect();

        // Bind button to leave Room.
        document.getElementById('button-call-end').onclick = function() {
            log('Disconnecting...');
            document.getElementById('call-connected').style.display = 'none';
            document.getElementById('spin-wrapper').style.display = 'none';
            document.getElementById('button-preview').style.display = 'block';
            document.getElementById('video-overlay').style.display = 'none';
            activeRoom.disconnect();
        };
    });

    function connect() {
        roomName = 'Support';

        log("Joining room '" + roomName + "'...");

        token = document.getElementById('button-call').getAttribute('data-token');

        console.log("Token: "+token);

        var connectOptions = {
            name: 'Support',
            logLevel: 'debug'
        };

        if (previewTracks) {
            connectOptions.tracks = previewTracks;
        }

        // Join the Room with the token from the server and the
        // LocalParticipant's Tracks.
        Video.connect(token, connectOptions).then(roomJoined, function(error) {
            log('Could not connect to Twilio: ' + error.message);
        });

        document.getElementById('call-connected').style.display = 'block';
        document.getElementById('spin-wrapper').style.display = 'inline-flex';
        document.getElementById('button-preview').style.display = 'none';
    }

// Successfully connected!
    function roomJoined(room) {
        window.room = activeRoom = room;

        log("Joined as '" + identity + "'");
        document.getElementById('button-call').style.display = 'none';
        document.getElementById('button-call-end').style.display = 'inline';

        // Attach LocalParticipant's Tracks, if not already attached.
        var previewContainer = document.getElementById('local-media');
        if (!previewContainer.querySelector('video')) {
            attachParticipantTracks(room.localParticipant, previewContainer);
        }

        // Attach the Tracks of the Room's Participants.
        room.participants.forEach(function(participant) {
            log("Already in Room: '" + participant.identity + "'");
            var previewContainer = document.getElementById('remote-media');
            attachParticipantTracks(participant, previewContainer);
        });

        // When a Participant joins the Room, log the event.
        room.on('participantConnected', function(participant) {
            //document.getElementById('remote-media').style.display = 'inline';
            log("Joining: '" + participant.identity + "'");
        });

        // When a Participant adds a Track, attach it to the DOM.
        room.on('trackAdded', function(track, participant) {
            log(participant.identity + " added track: " + track.kind);
            var previewContainer = document.getElementById('remote-media');
            document.getElementById('spin-wrapper').style.display = 'none';
            document.getElementById('video-overlay').style.display = 'flex';
            attachTracks([track], previewContainer);
        });

        // When a Participant removes a Track, detach it from the DOM.
        room.on('trackRemoved', function(track, participant) {
            log(participant.identity + " removed track: " + track.kind);
            detachTracks([track]);
        });

        // When a Participant leaves the Room, detach its Tracks.
        room.on('participantDisconnected', function(participant) {
            log("Participant '" + participant.identity + "' left the room");
            detachParticipantTracks(participant);
        });

        // Once the LocalParticipant leaves the room, detach the Tracks
        // of all Participants, including that of the LocalParticipant.
        room.on('disconnected', function() {
            log('Left');
            if (previewTracks) {
                previewTracks.forEach(function(track) {
                    track.stop();
                });
            }
            detachParticipantTracks(room.localParticipant);
            room.participants.forEach(detachParticipantTracks);
            activeRoom = null;
            document.getElementById('button-call').style.display = 'inline';
            document.getElementById('button-call-end').style.display = 'none';
            document.getElementById('spin-wrapper').style.display = 'none';
        });
    }

    // Preview LocalParticipant's Tracks.
    document.getElementById('button-preview').onclick = function() {
        var localTracksPromise = previewTracks
            ? Promise.resolve(previewTracks)
            : Video.createLocalTracks();

        localTracksPromise.then(function(tracks) {
            window.previewTracks = previewTracks = tracks;
            var previewContainer = document.getElementById('local-media');
            if (!previewContainer.querySelector('video')) {
                attachTracks(tracks, previewContainer);
            }
        }, function(error) {
            console.error('Unable to access local media', error);
            log('Unable to access Camera and Microphone');
        });
    };

    document.getElementById('mute').onclick = function() {
        console.dir(room.localParticipant);
        room.localParticipant.audioTracks.disable();
    };

    // Activity log.
    function log(message) {
        console.dir(message);
        return false;
        var logDiv = document.getElementById('log');
        logDiv.innerHTML += '<p>&gt;&nbsp;' + message + '</p>';
        logDiv.scrollTop = logDiv.scrollHeight;
    }

    // Leave Room.
    function leaveRoomIfJoined() {
        if (activeRoom) {
            activeRoom.disconnect();
        }
    }

}]);

我希望这可以帮助其他想要将 Twilio 视频与他们的项目集成的混合移动开发人员!

【讨论】:

  • 嗨,尼古拉斯,感谢您提供的信息。在 Android 上安装它后,当我单击 Ionic 2 应用程序 (Android) 中的预览按钮时,它什么也没有显示。单击加入房间按钮时,它显示“客户端无法创建或应用本地媒体描述”。但它适用于桌面浏览器。
  • @mohit 如果它在浏览器中运行而不是在 Android 设备上运行,我肯定会检查权限。我在开发早期遇到了很多问题,这些问题在浏览器中而不是在设备上运行,其中大部分都与权限相关。
  • 我已经访问了相机权限,但我仍然可以看到空的
  • @mohit 您是否在控制台日志中看到有关 Twilio 错误/警告的任何内容?
  • 我使用这样的 twilio 视频-import * as Video from 'twilio-video'; 我用其他设备检查过,现在var localTracksPromise = Video.createLocalTracks() 在 localTracksPromise.then() 中给出空白错误对象。
猜你喜欢
  • 2020-08-01
  • 2019-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多