diff --git a/openvidu-browser/src/OpenVidu/LocalRecorder.ts b/openvidu-browser/src/OpenVidu/LocalRecorder.ts index 78135c73..096b7129 100644 --- a/openvidu-browser/src/OpenVidu/LocalRecorder.ts +++ b/openvidu-browser/src/OpenVidu/LocalRecorder.ts @@ -202,7 +202,7 @@ export class LocalRecorder { this.videoPreview.id = this.id; this.videoPreview.autoplay = true; - if (platform.name === 'Safari' && platform.product === 'iPhone') { + if (platform.name === 'Safari') { this.videoPreview.setAttribute('playsinline', 'true'); } diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts index d047456c..9300bcbd 100644 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ b/openvidu-browser/src/OpenVidu/Publisher.ts @@ -293,7 +293,7 @@ export class Publisher extends StreamManager { this.videoReference = document.createElement('video'); - if (platform.name === 'Safari' && platform.product === 'iPhone') { + if (platform.name === 'Safari') { this.videoReference.setAttribute('playsinline', 'true'); } @@ -314,8 +314,8 @@ export class Publisher extends StreamManager { if (this.stream.isSendVideo()) { if (!this.stream.isSendScreen()) { - if (platform['isIonicIos']) { - // iOS Ionic. Limitation: cannot set videoDimensions directly, as the videoReference is not loaded + if (platform['isIonicIos'] || platform.name === 'Safari') { + // iOS Ionic or Safari. Limitation: cannot set videoDimensions directly, as the videoReference is not loaded // if not added to DOM. Must add it to DOM and wait for videoWidth and videoHeight properties to be defined this.videoReference.style.display = 'none'; diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts index 5da39e6e..ccc5be87 100644 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ b/openvidu-browser/src/OpenVidu/Session.ts @@ -77,6 +77,15 @@ export class Session implements EventDispatcher { */ remoteStreamsCreated: ObjMap = {}; + /** + * @hidden + */ + isFirstIonicIosSubscriber: boolean = true; + /** + * @hidden + */ + countDownForIonicIosSubscribers: boolean = true; + /** * @hidden */ @@ -658,6 +667,10 @@ export class Session implements EventDispatcher { streamEvent.callDefaultBehavior(); delete this.remoteStreamsCreated[stream.streamId]; + if (Object.keys(this.remoteStreamsCreated).length === 0) { + this.isFirstIonicIosSubscriber = true; + this.countDownForIonicIosSubscribers = true; + } } delete this.remoteConnections[connection.connectionId]; this.ee.emitEvent('connectionDestroyed', [new ConnectionEvent(false, this, 'connectionDestroyed', connection, msg.reason)]); @@ -727,6 +740,10 @@ export class Session implements EventDispatcher { // Deleting the remote stream const streamId: string = connection.stream.streamId; delete this.remoteStreamsCreated[streamId]; + if (Object.keys(this.remoteStreamsCreated).length === 0) { + this.isFirstIonicIosSubscriber = true; + this.countDownForIonicIosSubscribers = true; + } connection.removeStream(streamId); }) .catch(openViduError => { diff --git a/openvidu-browser/src/OpenVidu/Stream.ts b/openvidu-browser/src/OpenVidu/Stream.ts index 1e118cf1..21a08405 100644 --- a/openvidu-browser/src/OpenVidu/Stream.ts +++ b/openvidu-browser/src/OpenVidu/Stream.ts @@ -623,7 +623,7 @@ export class Stream implements EventDispatcher { reject('Error on publishVideo: ' + JSON.stringify(error)); } } else { - this.webRtcPeer.processAnswer(response.sdpAnswer) + this.webRtcPeer.processAnswer(response.sdpAnswer, false) .then(() => { this.streamId = response.id; this.isLocalStreamPublished = true; @@ -682,7 +682,16 @@ export class Stream implements EventDispatcher { if (error) { reject(new Error('Error on recvVideoFrom: ' + JSON.stringify(error))); } else { - this.webRtcPeer.processAnswer(response.sdpAnswer).then(() => { + // Ios Ionic. Limitation: some bug in iosrtc cordova plugin makes + // it necessary to add a timeout before processAnswer method + if (this.session.isFirstIonicIosSubscriber) { + this.session.isFirstIonicIosSubscriber = false; + this.session['iosInterval'] = setTimeout(() => { + this.session.countDownForIonicIosSubscribers = false; + }, 400); + } + const needsTimeoutOnProcessAswer = this.session.countDownForIonicIosSubscribers; + this.webRtcPeer.processAnswer(response.sdpAnswer, needsTimeoutOnProcessAswer).then(() => { this.remotePeerSuccessfullyEstablished(); this.initWebRtcStats(); resolve(); diff --git a/openvidu-browser/src/OpenVidu/StreamManager.ts b/openvidu-browser/src/OpenVidu/StreamManager.ts index c4078a67..f3e9debb 100644 --- a/openvidu-browser/src/OpenVidu/StreamManager.ts +++ b/openvidu-browser/src/OpenVidu/StreamManager.ts @@ -113,7 +113,7 @@ export class StreamManager implements EventDispatcher { video: document.createElement('video'), id: '' }; - if (platform.name === 'Safari' && platform.product === 'iPhone') { + if (platform.name === 'Safari') { this.firstVideoElement.video.setAttribute('playsinline', 'true'); } this.targetElement = targEl; @@ -334,7 +334,7 @@ export class StreamManager implements EventDispatcher { video.autoplay = true; video.controls = false; - if (platform.name === 'Safari' && platform.product === 'iPhone') { + if (platform.name === 'Safari') { video.setAttribute('playsinline', 'true'); } diff --git a/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts b/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts index fa8ead1b..9fb6e7d8 100644 --- a/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts +++ b/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts @@ -266,7 +266,7 @@ export class WebRtcPeer { * 3) Function invoked when a SDP answer is received. Final step in SDP negotiation, the peer * just needs to set the answer as its remote description */ - processAnswer(sdpAnswer: string): Promise { + processAnswer(sdpAnswer: string, needsTimeoutOnProcessAswer: boolean): Promise { return new Promise((resolve, reject) => { const answer: RTCSessionDescriptionInit = { @@ -279,8 +279,14 @@ export class WebRtcPeer { if (this.pc.signalingState === 'closed') { reject('RTCPeerConnection is closed'); } - - this.pc.setRemoteDescription(answer).then(() => resolve()).catch(error => reject(error)); + if (needsTimeoutOnProcessAswer && platform['isIonicIos']) { + setTimeout(() => { + console.info('setRemoteDescription run after timout for iOS device'); + this.pc.setRemoteDescription(answer).then(() => resolve()).catch(error => reject(error)); + }, 250); + } else { + this.pc.setRemoteDescription(answer).then(() => resolve()).catch(error => reject(error)); + } }); }