title: Failed to set remote offer sdp: Session error code: ERROR_CONTENT
body: <p>I have a problem connecting peer-to-peer video from native android browser to safari 11 desktop (vice versa), here is the error:</p>
  
  <p>Unhandled Promise Rejection: OperationError (DOM Exception 34): Failed to set remote offer sdp: Session error code: ERROR_CONTENT. Session error description: Failed to set remote video description send parameters..</p>
  
  <p>I'm currently stuck in this issue</p>
  
  <p>and here is my whole client videochat code, thanks.</p>
  
  <pre><code>import app from '../../../config';
  
  const videoChatService = app.service('participants/video-chat');
  
  let localVid;
  let remoteVid;
  let localstream;
  let rtcPeerConn;
  let conversationId;
  let userId;
  let isSdpSent = false;
  let hasAddTrack;
  
  const configuration = {
    iceServers: [{
      urls: 'stun:stun.l.google.com:19302',
    },
    {
      urls: 'stun:stun.services.mozilla.com',
      username: 'louis@mozilla.com',
      credential: 'webrtcdemo',
    },
    // {
    //   urls: 'turn:mdn-samples.mozilla.org',
    //   username: 'webrtc',
    //   credential: 'turnserver' }
    ] };
  
  function closeVideoCall() {
    if (rtcPeerConn) {
      rtcPeerConn.onaddstream = null;
      rtcPeerConn.ontrack = null;
      rtcPeerConn.onremovestream = null;
      rtcPeerConn.onicecandidate = null;
  
      if (remoteVid.srcObject) {
        remoteVid.srcObject.getTracks().forEach(track =&gt; track.stop());
        remoteVid.srcObject = null;
      }
  
      if (localVid.srcObject) {
        localVid.srcObject.getTracks().forEach(track =&gt; track.stop());
        localVid.srcObject = null;
      }
  
      rtcPeerConn.close();
      rtcPeerConn = null;
    }
  }
  
  // set local sdp
  function setLocalSDP(desc) {
    console.log('&gt;&gt;&gt; setLocalSDP', rtcPeerConn);
    return rtcPeerConn.setLocalDescription(desc);
  }
  
  function logError(error) {
    console.log(`&gt;&gt;&gt;&gt;logError, ${error.name}: ${error.message}`);
  }
  
  function handleNegotiatedNeededEvent() {
    console.log('&gt;&gt;&gt;&gt;&gt; on negotiation called');
    console.log('query &gt;&gt;&gt;', conversationId, userId);
    if (!isSdpSent) {
      rtcPeerConn.createOffer()
        .then(setLocalSDP)
        .then(() =&gt; {
          isSdpSent = true;
          videoChatService.patch(null, {
            data: {
              type: 'video-offer',
              message: JSON.stringify(rtcPeerConn.localDescription),
            },
          }, {
            query: {
              conversation_id: conversationId,
              user_id: userId,
            },
          }).then().catch(e =&gt; { console.log('patch error', e); });
        })
        .catch(logError);
    }
  }
  
  function handleRemoveStreamEvent() {
    closeVideoCall();
  }
  
  function handleTrackEvent (evt) {
    console.log('&gt;&gt;&gt;&gt;&gt; going to add their stream...', evt);
    remoteVid = document.getElementById('remoteStream');
    if (!remoteVid.srcObject) {
      remoteVid.srcObject = evt.streams[0];
    }
  }
  
  function handleAddStreamEvent(evt) {
    console.log('&gt;&gt;&gt;&gt;&gt; stream added');
    remoteVid = document.getElementById('remoteStream');
    remoteVid.srcObject = event.stream;
  }
  
  function handleICECandidateEvent(evt) {
    console.log('&gt;&gt;&gt;&gt; onicecandidate', evt);
    console.log('query &gt;&gt;&gt;', conversationId, userId);
    if (evt.candidate) {
      videoChatService.patch(null, {
        data: {
          type: 'new-ice-candidate',
          message: JSON.stringify(evt.candidate),
        },
      }, {
        query: {
          conversation_id: conversationId,
          user_id: userId,
        },
      });
    }
  }
  
  function handleICEConnectionStateChangeEvent() {
    console.log(`&gt;&gt;&gt;&gt;&gt; ICE connection state changed to ${rtcPeerConn.iceConnectionState}`);
  
    switch (rtcPeerConn.iceConnectionState) {
      case 'closed':
      case 'failed':
      case 'disconnected':
        console.log('&gt;&gt;&gt;&gt; disconnected');
        closeVideoCall();
        break;
    }
  }
  
  function handleSignalingStateChangeEvent() {
    console.log(`&gt;&gt;&gt;&gt;&gt; WebRTC signaling state changed to: ${rtcPeerConn.signalingState}`);
    switch (rtcPeerConn.signalingState) {
      case 'closed':
      console.log('&gt;&gt;&gt;&gt; closed');
        closeVideoCall();
        break;
    }
  }
  
  function createPeerConnection() {
    rtcPeerConn = new RTCPeerConnection(configuration);
    console.log('&gt;&gt;&gt;&gt;&gt; create peer connection', rtcPeerConn);
  
    hasAddTrack = (rtcPeerConn.addTrack !== undefined);
  
    rtcPeerConn.onicecandidate = handleICECandidateEvent;
    rtcPeerConn.onnegotiationneeded = handleNegotiatedNeededEvent;
    rtcPeerConn.oniceconnectionstatechange = handleICEConnectionStateChangeEvent;
    rtcPeerConn.onsignalingstatechange = handleSignalingStateChangeEvent;
    rtcPeerConn.onremovestream = handleRemoveStreamEvent;
  
    if (hasAddTrack) {
      rtcPeerConn.ontrack = handleTrackEvent;
    } else {
      rtcPeerConn.onaddstream = handleAddStreamEvent;
    }
  }
  
  function handleGetUSerMediaError(e) {
    switch (e.name) {
      case 'NotFoundError':
        alert('Unable to open your call because no camera and/or microphone were found.');
        break;
      case 'SecurityError':
      case 'PermissionDeniedError':
        // Do nothing; this is the same as the user canceling the call.
        break;
      default:
        alert(`Error opening your camera and/or microphone: ${e.message}`);
        break;
    }
  }
  
  // add video to local and add to track
  function gotStream(stream) {
    console.log('&gt;&gt;&gt;&gt; gotStream', stream);
    localVid.srcObject = stream;
    localstream = stream;
  
    if (hasAddTrack) {
      stream.getTracks().forEach(track =&gt; rtcPeerConn.addTrack(track, localstream));
    } else {
      rtcPeerConn.addStream(localstream);
    }
  }
  
  // start signaling
  export function startSignaling(conversation_id, user_id) {
    localVid = document.getElementById('localStream');
    remoteVid = document.getElementById('remoteStream');
    console.log('&gt;&gt;&gt;&gt;&gt; startSignaling');
  
    conversationId = conversation_id;
    userId = user_id;
  
    return () =&gt; {
      if (!rtcPeerConn) {
        createPeerConnection();
        navigator.mediaDevices.getUserMedia({
          audio: true,
          video: {
            facingMode: 'user',
          },
        })
          .then(gotStream)
          .catch(handleGetUSerMediaError);
      }
    };
  }
  
  export function handleVideoOfferMsg(conversation_id, user_id, message) {
    console.log('&gt;&gt;&gt;&gt;&gt; handleVideoOfferMsg');
    localstream = null;
    conversationId = conversation_id;
    userId = user_id;
    localVid = document.getElementById('localStream');
    remoteVid = document.getElementById('remoteStream');
    return () =&gt; {
      createPeerConnection();
      console.log('query &gt;&gt;&gt;', conversationId, userId);
      const sdp = new RTCSessionDescription(message);
      // sdp.sdp = sdp.replace('a=setup:active', 'a=setup:passive');
      rtcPeerConn.setRemoteDescription(sdp)
        .then(() =&gt; (
          navigator.mediaDevices.getUserMedia({
            audio: true,
            video: {
              facingMode: 'user',
            },
          })
        ))
        .then(gotStream)
        .then(() =&gt; (
          rtcPeerConn.createAnswer()
        ))
        .then(setLocalSDP)
        .then(() =&gt; {
          videoChatService.patch(null, {
            data: {
              type: 'video-answer',
              message: JSON.stringify(rtcPeerConn.localDescription),
            },
          }, {
            query: {
              conversation_id: conversationId,
              user_id: userId,
            },
          }).then().catch(e =&gt; { console.log('patch error', e); });
        });
    };
  }
  
  export function handleVideoAnswerMsg(message) {
    console.log('&gt;&gt;&gt;&gt;&gt; handle video answer message', message);
    return () =&gt; {
      const sdp = new RTCSessionDescription(message);
      rtcPeerConn.setRemoteDescription(sdp)
        .catch(logError);
    };
  }
  
  // Adding ice candidate
  export function addIceCandidate(message) {
    console.log('&gt;&gt;&gt;&gt; addIceCandidate', message);
    return () =&gt; {
      const candidate = new RTCIceCandidate(message);
      rtcPeerConn.addIceCandidate(candidate)
      .then(() =&gt; {
        console.log('&gt;&gt;&gt; candidate added ');
      })
      .catch(e =&gt; {
        console.log('Error candidate', e);
      });
    };
  }
  </code></pre>