import AudioVideoControllerState from '../audiovideocontroller/AudioVideoControllerState' ; import DefaultBrowserBehavior from '../browserbehavior/DefaultBrowserBehavior' ; import DefaultSDP from '../sdp/DefaultSDP' ; import BaseTask from './BaseTask' ; export default class SetRemoteDescriptionTask extends BaseTask { protected taskName = 'SetRemoteDescriptionTask' ; private cancelICEPromise : ( ) => void ; constructor ( private context ) { super ( context . logger ) ; } cancel ( ) { if ( this . cancelICEPromise ) { this . cancelICEPromise ( ) ; } } async run ( ) { const peer = this . context . peer ; if ( ! peer ) { this . logAndThrow ( 'session does not have peer connection; bypass set remote description' ) ; } let sdp = this . context . sdpAnswer ; sdp = new DefaultSDP ( sdp ) . withoutServerReflexiveCandidates ( ) . sdp ; if ( this . context . audioProfile ) { sdp = new DefaultSDP ( sdp ) . withAudioMaxAverageBitrate ( this . context . audioProfile . audioBitrateBps ) . sdp ; if ( this . context . audioProfile . isStereo ( ) ) { sdp = new DefaultSDP ( sdp ) . withStereoAudio ( ) . sdp ; } } if ( ! this . context . browserBehavior . requiresUnifiedPlan ( ) ) { this . logger . info ( 'checking for no videos (plan-b)' ) ; if ( this . context . videosToReceive . empty ( ) && this . context . peer . remoteDescription ) { this . logger . info ( 'have no videos and have remote description (plan-b)' ) ; const sdpInactiveVideoOffer = this . context . peer . localDescription . sdp ; const sdpInactiveVideoAnswer = sdp ; let updatedAnswer = sdpInactiveVideoAnswer ; const offer = new DefaultSDP ( sdpInactiveVideoOffer ) ; if ( offer . hasVideo ( ) ) { this . logger . info ( `offer has video (plan-b): >>>${ offer . sdp }<<<` ) ; const answer = new DefaultSDP ( sdpInactiveVideoAnswer ) ; this . logger . info ( `existing answer (plan-b): >>>${ answer . sdp }<<<` ) ; if ( ! answer . hasVideo ( ) ) { this . logger . info ( `copying inactive video from offer into answer (plan-b); sdp answer before is >>>${ sdpInactiveVideoAnswer }<<<` ) ; updatedAnswer = answer . copyVideo ( sdpInactiveVideoOffer ) . sdp ; } } sdp = updatedAnswer ; } } if ( new DefaultBrowserBehavior ( ) . requiresSortCodecPreferencesForSdpAnswer ( ) ) { sdp = new DefaultSDP ( sdp ) . preferH264IfExists ( ) . sdp ; } this . logger . info ( `processed remote description is >>>${ sdp }<<<` ) ; const remoteDescription = { type : 'answer' , sdp : sdp , toJSON : null , } ; try { await this . createICEConnectionCompletedPromise ( remoteDescription ) ; } catch ( err ) { throw err ; } } private createICEConnectionCompletedPromise ( remoteDescription ) { return new Promise ( async ( resolve , reject ) => { const checkConnectionCompleted = ( ) : void => { if ( this . context . peer . iceConnectionState === 'connected' || this . context . peer . iceConnectionState === 'completed' ) { this . context . peer . removeEventListener ( 'iceconnectionstatechange' , checkConnectionCompleted ) ; resolve ( ) ; } } ; this . cancelICEPromise = ( ) => { if ( this . context . peer ) { this . context . peer . removeEventListener ( 'iceconnectionstatechange' , checkConnectionCompleted ) ; } reject ( new Error ( `${ this . name ( ) } got canceled while waiting for the ICE connection state` ) ) ; } ; this . context . peer . addEventListener ( 'iceconnectionstatechange' , checkConnectionCompleted ) ; try { await this . context . peer . setRemoteDescription ( remoteDescription ) ; this . logger . info ( 'set remote description, waiting for ICE connection' ) ; checkConnectionCompleted ( ) ; } catch ( err ) { reject ( err ) ; } } ) ; } }