What are the best ways to conceptualize the benefits of WebRTC?

I encountered a peculiar issue with the abstraction of the WebRTC offer generation process. It appears that the incoming ice candidates fail to reach the null candidate. While I have been able to generate offers successfully using similar code in the past, my abstracted version only reaches 12 candidates compared to the original 20. This discrepancy is baffling, as the code seems nearly identical but the abstracted version fails even on the same browser.

Here is the original working code:

    var localConn = new webkitRTCPeerConnection({'iceServers':[{...}]});
    var remoteConn = new webkitRTCPeerConnection({'iceServers':[{...}]});

    function initMedia(localView, callback){
        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        var constraints = {audio:true,video:true};
        navigator.getUserMedia(constraints, successStream, errorStream);
        //onSuccess and Error functions
        function successStream(stream){
            window.stream = stream;
            if(window.URL){
                $('#'+localView).attr('src',window.URL.createObjectURL(stream));
            } else {
                $('#'+localView).attr('src',stream);
            }
            localConn.addStream(stream);
            remoteConn.addStream(stream);
            console.log('local Stream: '+ stream.id);
            callback();     //-> goes on to create new offer
        }
        function errorStream(error){
            console.log('navigator.getUserMedia error: ', error);
        }
    }

    //function that generates offer and sends it out to a callback
    function newOffer(callback){
        console.log('creating new offer');

        localConn.createOffer(function (sessionDescription){
            localConn.setLocalDescription(sessionDescription);
        }, function(error){
            console.log('Error setting local description: '+error);
        });
        createOffer();
        //gather ICE with a callback to handle/send generated offer
        function createOffer(){
            localConn.onicecandidate = function(iceEvent){
                console.log('gathering local ice');        //ice events fired (20 total)
                //upon gathering all local ice
                if(iceEvent.candidate === null){
                    console.log('local ice gathered');    //success
                    var offer = {'type': localConn.localDescription.type,
                                 'sdp': localConn.localDescription.sdp};
                    offer = JSON.stringify(offer);
                    console.log('offer created');
                    callback(offer);
                }  
            }
        }
    }

Here is the updated version with functions for abstraction (not receiving null ice candidate):

//general rtc vars
var localConn = new webkitRTCPeerConnection({'iceServers':[{'url':'stun:stun.1.google.com:19302'}]});
var remoteConn = new webkitRTCPeerConnection({'iceServers':[{'url':'stun:stun.1.google.com:19302'}]});
//var mediaStream;
var channel;

//creates a stream from webcam
//@params function streamHandle(stream)
function initStream(streamHandle){
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
    var constraints = {audio:true,video:true};
    navigator.getUserMedia(constraints, successStream, errorStream);
    //onSuccess and Error functions
    function successStream(stream){
        window.stream = stream;
        console.log('TreRTC: Local Stream-'+ stream.id);
        //mediaStream = stream;
        localConn.addStream(stream);    
        remoteConn.addStream(stream);   
        streamHandle(stream);    
    }
    function errorStream(error){
        console.log('navigator.getUserMedia error: ', error);
    }
}

//creates an offer to be sent
//@params Stream stream (from getusermedia)
//@return string offer
function createOffer(stream){
    console.log('TreRTC: Creating Offer');
    
    localConn.createOffer(function (sessionDescription){
        localConn.setLocalDescription(sessionDescription);
    }, function(error){
        console.log('Error setting local description: '+error);
    });

    localConn.onicecandidate = function(iceEvt){
        console.log('TreRTC: ICE in');            
        if(iceEvt.candidate === null){
            console.log('TreRTC: ICE gathered');    
            var offer = {'type': localConn.localDescription.type,
                         'sdp': localConn.localDescription.sdp};
            offer = JSON.stringify(offer);
            console.log('TreRTC: Offer initialized');
            return offer;    
        }    
    }
}

Answer №1

streamHandle(stream);    //included in createOffer function

There may be a timing issue between your createOffer and initStream functions finishing, as they are asynchronous processes (although it's hard to confirm without seeing more of the code).

If you're looking to streamline WebRTC usage, consider moving away from the old legacy API and opting for RTCPeerConnection's new promise-based methods. Promises offer better control over handling race conditions like this compared to callbacks.

Another option is to utilize the onnegotiationneeded callback to trigger negotiation, potentially resolving this issue (however, be cautious of a bug in Chrome).

Below is an example of a local connection setup (try it out on JSFiddle using Chrome):

var pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();

navigator.mediaDevices.getUserMedia({video: true, audio: true})
  .then(stream => pc1.addStream(video1.srcObject = stream))
  .catch(e => console.log(e));

pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);

pc2.ontrack = e => video2.srcObject = e.streams[0];
pc1.oniceconnectionstatechange = e => console.log(pc1.iceConnectionState);
pc1.onnegotiationneeded = e =>
  pc1.createOffer().then(d => pc1.setLocalDescription(d))
  .then(() => pc2.setRemoteDescription(pc1.localDescription))
  .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
  .then(() => pc1.setRemoteDescription(pc2.localDescription))
  .catch(e => console.log(e));
<video id="video1" width="160" height="120" autoplay muted></video>
<video id="video2" width="160" height="120" autoplay></video>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with vue-cli3 eslint and compiler arising from conflicting vue/script-indent settings

Whenever my .eslint.js file includes this rule: "vue/script-indent": [ "error", 4, { "baseIndent": 1, "switchCase": 1, } ] and I save it, an error pops up: Error: Expected indentation of 32 spaces but only found 24 spaces ...

The input field in Angular dynamically populates values into multiple instances of the same text

I am facing an issue with my comment inputs where whatever I type in one input is automatically populated in all other inputs. How can I ensure that the text input value only appears in the input box that I am typing into? Below is a snippet of the templa ...

What is the best way to display jQuery/AJAX response in a table cell?

I am struggling with a script that retrieves data from a SQL database query and need help placing the result in a specific table cell. Here is the query: <script type="text/javascript"> $(document).ready(function(){ $('.typeval').change(f ...

How to Monitor Store Changes within a Vue File Using Vue.js

I am working with 2 vue files, header.vue and sidebar.vue. Both components are imported into layout.vue. Here are the steps I am following: 1. Initially, when the page loads, I update the store in header.vue with some values inside the created hook. 2. ...

Ways to prevent prop changes from passing up the chain?

After some experimentation, I discovered that the props I passed to a component can actually be changed within the component and affect the parent. This behavior is discussed in the official documentation. While objects and arrays cannot be directly modi ...

What are the steps to create a shared online drawing board with WebRTC or WebSocket?

I have successfully developed a video chat application using WebRTC and MERN stack. However, I am looking to enhance the user experience by integrating a collaborative whiteboard feature. This means that any drawing made on one user's canvas should be ...

Adding a JSON array to HTML using JavaScript

Looking to incorporate JSON Array data into an HTML list with Headings/Subheadings using JavaScript. I experimented with two methods - one involving jQuery and the other mostly vanilla JS. The initial attempt (link here: http://jsfiddle.net/myu3jwcn/6/) b ...

Return to the initial stage of a multistep process in its simplest form following a setTimeout delay

I recently customized the stepsForm.js by Copdrops and made some modifications. Although everything works well, I'm struggling to navigate back to the initial step (first question) after submitting the form due to my limited knowledge of JavaScript. ...

Is there a way to calculate the height of a component that is only rendered conditionally?

I have a scenario where I need to dynamically adjust the height of a component that is conditionally rendered without explicitly setting it. The height should automatically match the size of its content. To achieve this, I am using a reference to determin ...

Integrate React tags with Redux form to ensure the values are transmitted as an array within the payload

I am currently working on a redux-form that contains a component for tags. I am struggling to figure out how to retrieve the tag values in an array as a payload. Any help would be greatly appreciated. Below is the code snippet for the tags component: ...

What could be causing the unexpected behavior in my NgMessages form validation?

I have developed a code that incorporates Angular JS form validation methods. There are two separate forms within the codebase, The initial form utilizes basic form validation while the second form employs ng-messages, However, an issue has arisen wher ...

Is it possible to customize the close icons on the autocomplete feature in Material UI?

Is there a solution to change the icon while keeping its function when clicked? I am looking to replace this Icon <Autocomplete multiple id="checkboxes-tags-demo" options={top100Films} disableCloseOnSelect getOpt ...

Guide on creating dynamic datasets and multiple dynamic yAxes

To enhance my chart, I am interested in adding multiple Y Axes based on the examples provided below: script 1 script 2 Although I attempted to modify the code as shown below, it seems to not be functioning properly. function rdnum() { return Math.flo ...

Limit the elements in an array within a specified range of dates

Currently, I am working on implementing a filter functionality for a data array used in a LineChart within my Angular application using TypeScript. The structure of the data array is as follows: var multi = [ { "name": "test1", "series": [ ...

Why is Node.js unable to locate my files?

I'm currently utilizing Node.js as my server, and I'm encountering some difficulties in serving my JS and CSS files. For some reason, index.html is unable to locate them. Whenever I try to load up my browser, I encounter the following error: htt ...

What is the best way to retrieve recently inserted data using Sequelize in PostgreSql?

Is there a way to retrieve updated table values after adding a user to the "WOD" table without making an additional query? Currently, when I add a third user to my WOD table, I can only return the first two users because I am unable to access the updated ...

What is the best method for gathering information from multiple input fields?

I'm currently working on developing a Polymer application that includes a search button with multiple input boxes. I want the search operation to consider all the inputs from these boxes when performing a search. Here is an image depicting the scenar ...

Quiz timer using JavaScript

In my HTML and JavaScript project, I am creating a quiz game where players have 15 seconds to answer each question. To implement this timer feature, I used the following code snippet: <body onload="setTimeout(Timer,15000)"> Implemented in JavaScrip ...

An item was shown on the HTML page

Having some trouble displaying the graph generated by my R function on the opencpu server. Instead of the desired plot, all I see is [object Object] in the HTML page. Below is the snippet of code from my AngularJS controller: var req = ocpu.rpc("plotGraph ...

Is there a way to alter the text color using JavaScript on the client side?

Is there a way to change the color of a list item in a ul based on whether it is a palindrome or not? Here is the JavaScript file I am working with: function isPalindrome(text){ return text == text.split('').reverse().join(''); } c ...