WebRTC issues - Safari and iOS

Discussion in 'Web Call Server 5' started by Srdjan, Oct 26, 2019.

  1. Srdjan

    Srdjan New Member

    Hi,

    I am having an issue with WebRTC streaming on iOS. All phones used for testing are iPhones (iPhone X, iOS v13, Safari) and on some, streaming is working while on others it's not. What I don't get it is that it was working for a few days on all tested devices and the stream just failed without changing any setting on the iPhone or updating it at all. Also low latency player on your website is working properly. Any advice? Here is the log from the one that is not working.

    Code:
    [Log] 17:22:46 INFO webrtc -  – "Initialized" (flashphoner.js, line 35347)
    [Log] 17:22:46 INFO websocket -  – "Initialized" (flashphoner.js, line 35347)
    [Log] 17:22:46 INFO core -  – "Initialized" (flashphoner.js, line 35347)
    [Log] 17:22:46 INFO webrtc -  – "FOUND WEBRTC CACHED INSTANCE, id 76b0b2c0-f804-11e9-8a0c-71e710a0b9fd-REMOTE_CACHED_VIDEO" (flashphoner.js, line 35347)
    [Error] 17:22:47 ERROR webrtc -  – NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. — flashphoner.js:35650
    NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. —flashphoner.js:35650play
  2. Max

    Max Administrator Staff Member

    The NotAllowedError is generally raised on mobile devices where user gesture is required to begin audio or video playback.
    If you take a look at our Player example you would see that we use two functions upon user's gesture to pre-initialize sound and video on iOS Safari browsers.
    playFirstSound
    playFirstVideo
    Code:
    function playBtnClick() {
        if (validateForm()) {
            $(this).prop('disabled', true);
            $('#url').prop('disabled', true);
            $("#streamName").prop('disabled', true);
            if (Flashphoner.getMediaProviders()[0] === "WSPlayer") {
                Flashphoner.playFirstSound();
            } else if (Browser.isSafariWebRTC() || Flashphoner.getMediaProviders()[0] === "MSE") {
                Flashphoner.playFirstVideo(remoteVideo, false, PRELOADER_URL).then(function() {
                    start();
                });
                return;
            }
            start();
        }
    }
    https://demo.flashphoner.com/client2/examples/demo/streaming/player/player.html
    https://demo.flashphoner.com/client2/examples/demo/streaming/player/player.js

    The same is true for audio and video publishing
    https://demo.flashphoner.com/client...ming/two_way_streaming/two_way_streaming.html
    https://demo.flashphoner.com/client2/examples/demo/streaming/two_way_streaming/two_way_streaming.js
  3. Srdjan

    Srdjan New Member

    Hi,

    Thank you for your reply. I am calling playVideoFirst if it is iOS Safari. Please take a look at the code used to integrate the player. In the example given I am not waiting for the user's click. However, the same code works on some iPhones while on others it doesn't (same model, iOS major version and Safari), which is weird.
    Code:
    function initPage() {
      //init api
      try {
        Flashphoner.init({
          receiverLocation: '/player/dependencies/websocket-player/WSReceiver2.js',
          decoderLocation: '/player/dependencies/websocket-player/video-worker2.js',
          preferredMediaProvider: mediaProvider
        });
      } catch(e) {
        console.log('Browser not supported.');
        return;
      }
      remoteVideo = document.getElementById("remoteVideo");
      start();
    }
    
    function start() {
      if (Browser.isSafariWebRTC()) {
        Flashphoner
          .playFirstVideo(remoteVideo, false)
          .then(() => createSession());
        return;
      }
      createSession();
    }
    
    function createSession() {
      //check if we already have session
      if (Flashphoner.getSessions().length > 0) {
        const session = Flashphoner.getSessions()[0];
        if (session.getServerUrl() == serverUrl) {
          playStream(session);
          return;
        } else {
          //remove session DISCONNECTED and FAILED callbacks
          session.on(SESSION_STATUS.DISCONNECTED, function(){});
          session.on(SESSION_STATUS.FAILED, function(){});
          session.disconnect();
        }
      }
      //create session
      Flashphoner.createSession({urlServer: serverUrl})
        .on(SESSION_STATUS.ESTABLISHED, function(session){
          setStatus(session.status());
          //session connected, start playback
          playStream(session);
        })
        .on(SESSION_STATUS.DISCONNECTED, function(){
          setStatus(SESSION_STATUS.DISCONNECTED);
          start();
        })
        .on(SESSION_STATUS.FAILED, function(){
          setStatus(SESSION_STATUS.FAILED);
          start();
        });
    }
    
    function playStream(session) {
      const streamName = getUrlParam('rtsp');
      if (!streamName) {
        console.error('provide stream url');
        return;
      }
      const options = {
        name: streamName,
        display: remoteVideo,
        constraints: {
          audio: false
        }
      };
      const stream = session
        .createStream(options)
        .on(STREAM_STATUS.PENDING, function(stream) {
          const video = document.getElementById(stream.id());
          if (!video.hasListeners) {
            video.hasListeners = true;
            //don't resize html5 video
            if (video.nodeName.toLowerCase() !== "video") {
              video.addEventListener('resize', function (event) {
                const streamResolution = stream.videoResolution();
                if (Object.keys(streamResolution).length === 0) {
                  resizeVideo(event.target);
                } else {
                  // Change aspect ratio to prevent video stretching
                  const ratio = streamResolution.width / streamResolution.height;
                  const newHeight = Math.floor(options.playWidth / ratio);
                  resizeVideo(event.target, options.playWidth, newHeight);
                }
              });
            }
          }
        })
        .on(STREAM_STATUS.PLAYING, function(stream) {
          setStatus(stream.status());
        })
        .on(STREAM_STATUS.STOPPED, function() {
          setStatus(STREAM_STATUS.STOPPED);
          stream.play();
        })
        .on(STREAM_STATUS.FAILED, function(stream) {
          setStatus(STREAM_STATUS.FAILED, stream);
          stream.play();
        })
        .on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
          console.log(`
            Not enough bandwidth, consider using lower video resolution or bitrate.
            Bandwidth: ${(Math.round(stream.getNetworkBandwidth() / 1000))}
            Bitrate ${(Math.round(stream.getRemoteBitrate() / 1000))}
          `);
        });
      stream.play();
    }
  4. Max

    Max Administrator Staff Member

    Good day.
    In your example, you first check the condition for playFirstVideo and then create session (createSession). In the example player.js, session has already been created and according to the condition isSafariWebRTC stream is playing.
  5. Srdjan

    Srdjan New Member

    Hi,

    Thank you for your reply. I don't think it's different. It is just poor naming. Your function is named play and mine createSession, but other than names everything is the same. The error still shows up on those iPhones while it works on others.
  6. Max

    Max Administrator Staff Member

    Good day.
    We looked your code again, you're right (different naming).

    Code:
    if (Browser.isSafariWebRTC()) {
        Flashphoner
          .playFirstVideo(remoteVideo, false)
          .then(() => createSession());
        return;
      }
    The parameter PRELOADER_URL is not passed in your code to the Flashphoner.playFirstVideo function. The correct example in the file player.js on Flashphoner WebSDK Github.

    Code:
    if (session.getServerUrl () == serverUrl) {
          playStream (session);
          return
    } else {
    ...
    }
    Do you fulfill this condition (the serverUrl variable is not defined in this code)?
    Last edited: Nov 5, 2019
  7. Srdjan

    Srdjan New Member

    I figured out what is the problem. When low power mode is enabled then webrtc does not work and the error not allowed is displayed. Once I turn off power mode everything works as it should.
  8. Max

    Max Administrator Staff Member

    Good day.
    Thanks for the information. We will check it.
    Low power mode throttles iPhone’s CPU slightly, lowers brightness, stops apps from refreshing in the background, but this does not affect the general functions.
    Besides, you must add parameter PRELOADER_URL in your code. This is an essential option for iOS.
  9. Srdjan

    Srdjan New Member

    The issue definitely occurs because of a few reasons. Your demo works just fine with "low power mode" enabled. I’m assuming it’s some combination of autoplay (playStream is called automatically) and low power mode.

    I’ve added PRELOADER as argument.
  10. Max

    Max Administrator Staff Member

    Good day.
    We tested WebRTC stream playing on iPhone with "low power mode" enabled and problem not found.
    Please send your code to support@flashphoner.com. We will check.

Share This Page