Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/439.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript webRTC音频仅以一种方式工作_Javascript_Webrtc - Fatal编程技术网

Javascript webRTC音频仅以一种方式工作

Javascript webRTC音频仅以一种方式工作,javascript,webrtc,Javascript,Webrtc,我正在尝试使用浏览器中提供的API实现webRTC。我将本教程用作指南: 以下是我目前正在做的事情。首先,我在页面中获取音频元素。我还有一个audioStream变量,用于存储发起用户单击呼叫按钮或接收用户单击应答按钮时从navigator.webkitGetUserMedia获取的流。然后是一个用于存储当前调用的变量 var audio = document.querySelector('audio'); var audioStream; var call = {}; 然后我有以下设置:

我正在尝试使用浏览器中提供的API实现webRTC。我将本教程用作指南:

以下是我目前正在做的事情。首先,我在页面中获取音频元素。我还有一个
audioStream
变量,用于存储发起用户单击呼叫按钮或接收用户单击应答按钮时从
navigator.webkitGetUserMedia
获取的流。然后是一个用于存储当前调用的变量

var audio = document.querySelector('audio');
var audioStream;
var call = {}; 
然后我有以下设置:

var iceServers = [
    { url: 'stun:stun1.l.google.com:19302' },
    { url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: 'webrtc@live.com' }
];

var sdpConstraints = {
    optional: [],
    mandatory: {
        OfferToReceiveAudio: true,
        OfferToReceiveVideo: false
    }
};

var DtlsSrtpKeyAgreement = {
   DtlsSrtpKeyAgreement: true
};
在页面加载时,我创建一个新的对等点:

var peer = new webkitRTCPeerConnection({
    'iceServers': iceServers
});
在addstream事件中,我只是将事件分配给call变量

peer.onaddstream = function(event){
    call = event;
};
在ice候选事件中,我将候选发送给对等方

peer.onicecandidate = function(event){

    var candidate = event.candidate;

    if(candidate){
        SocketService.emit('message', {
            'conversation_id': me.conversation_id,
            'targetUser': to,
            'candidate': candidate
        });
    }

    if(typeof candidate == 'undefined'){
        send_SDP();
    }

};
function send_SDP(){
    SocketService.emit('message', {
        'conversation_id': me.conversation_id,
        'targetUser': to,
        'sdp': peer.localDescription
    });
}
一旦收集状态完成,我将发送SDP

peer.ongatheringchange = function(e){

    if(e.currentTarget && e.currentTarget.iceGatheringState === 'complete'){

        send_SDP();
    }
};
send\u SDP
方法所做的是将本地描述发送给对等方

peer.onicecandidate = function(event){

    var candidate = event.candidate;

    if(candidate){
        SocketService.emit('message', {
            'conversation_id': me.conversation_id,
            'targetUser': to,
            'candidate': candidate
        });
    }

    if(typeof candidate == 'undefined'){
        send_SDP();
    }

};
function send_SDP(){
    SocketService.emit('message', {
        'conversation_id': me.conversation_id,
        'targetUser': to,
        'sdp': peer.localDescription
    });
}
下面是我在事件侦听器中为调用按钮准备的内容。 因此,它首先获取音频,然后将流分配给当前的对等对象。然后它创建一个新的报价,如果成功,则设置本地描述,一旦完成,它将向另一个对等方发送报价

getAudio(
    function(stream){
        peer.addStream(stream);
        audioStream = stream;
        peer.createOffer(function(offerSDP){
            peer.setLocalDescription(offerSDP, function(){

                    SocketService.emit('message', {
                        'conversation_id': me.conversation_id,
                        'targetUser': to,
                        'offerSDP': offerSDP
                    });
                },
                function(){});
            }, 
            function(){}, 
            sdpConstraints
        );
    },
    function(err){}); 
在接收端,要约被捕获,因此它显示有人在呼叫的模式。然后,接收对等方可以单击应答按钮。但在这里,我甚至在单击“应答”按钮之前就使用“提供”设置会话描述

SocketService.on('message', function(msg){
    if(msg.offerSDP){
        //show calling modal on the receiving peer
        var remoteDescription = new RTCSessionDescription(msg.offerSDP);
        peer.setRemoteDescription(remoteDescription, function(){
        createAnswer(msg.offerSDP);
        },
        function(){});

    }
});
设置远程描述后,将创建答案。首先获取音频,然后将流添加到本地对等对象。接下来,使用
offerSDP
创建远程会话描述,然后将该远程会话描述设置为本地对等对象。然后,创建应答,在本地对等方上设置本地描述,然后将应答SDP发送给发起呼叫的对等方

function createAnswer(offerSDP) {
    getAudio(
        function(stream){
            peer.addStream(stream);
            audioStream = stream;

            var remoteDescription = new RTCSessionDescription(offerSDP);
            peer.setRemoteDescription(remoteDescription);

            peer.createAnswer(function(answerSDP) {

                peer.setLocalDescription(answerSDP, function(){

                    SocketService.emit('message', {
                        'conversation_id': me.conversation_id,
                        'targetUser': to,
                        'answerSDP': answerSDP
                    });
                },
                function(){});
            }, function(err){}, sdpConstraints);

        },
        function(err){
        }
    );
};
发起呼叫的对等方收到
应答sdp
。一旦它这样做了,它将使用
应答器sdp
创建远程描述,并使用它为本地对等对象设置远程描述

if(msg.answerSDP){

        var remoteDescription = new RTCSessionDescription(msg.answerSDP);
        peer.setRemoteDescription(remoteDescription, function(){
        },
        function(){});
}
在那之后,我不确定接下来会发生什么。据我所知,onicecandidate事件是在发起对等方(调用者)上触发的,它向接收对等方发送候选对象。然后执行以下代码:

if(msg.candidate){

    var candidate = msg.candidate.candidate;
    var sdpMLineIndex = msg.candidate.sdpMLineIndex;

    peer.addIceCandidate(new RTCIceCandidate({
        sdpMLineIndex: sdpMLineIndex,
        candidate: candidate
    }));
} 
现在,单击“应答”按钮后,将向发起方发送一条消息,由接收方接收。它使用调用流作为音频元素的源,一旦加载了所有元数据,它就会播放音频

SocketService.emit('message', {
    'answerCall': true,
    'conversation_id': me.conversation_id,
    'targetUser': to
});

audio.src = window.URL.createObjectURL(call.stream);
audio.onloadedmetadata = function(e){
    audio.play();
}
这里可能有问题。这就是为什么音频是单向的。只有发起呼叫的用户才能听到接收用户的输入。启动用户发出的声音也能被听到,所以这就像是在重复你说的话。有什么想法吗


如果您知道任何教程或书籍,说明如何使用本机API调用实现webRTC,这也会有所帮助。提前感谢。

我可以推荐的最简单的示例是用于基本对等连接的webrtc示例


至于回音,您可以在本地对等方的音频元素上设置
audio.mute
,以防止播放和引起回音(用户不需要听到自己的音频,因此您可以使该元素静音)

在这里,您正在使用过时的API硬编码到特定的浏览器(Chrome),而不是使用。我可以建议使用跨浏览器polyfill吗?