@@ -69,6 +69,9 @@ export default class DeviceRenderer {
6969 // Event callbacks
7070 this . callbacks = { } ;
7171
72+ // Plugins/Widgets registry
73+ this . widgets = [ ] ;
74+
7275 // Event listeners
7376 this . allListeners = [ ] ;
7477
@@ -77,10 +80,6 @@ export default class DeviceRenderer {
7780 this . signalingDataChannel = null ;
7881 this . cameraSender = null ;
7982 this . microphoneSender = null ;
80- this . sdpConstraints = {
81- offerToReceiveAudio : true ,
82- offerToReceiveVideo : true ,
83- } ;
8483
8584 // last accessed x/y position
8685 this . x = 0 ;
@@ -435,7 +434,8 @@ export default class DeviceRenderer {
435434 }
436435 // creating SDP offer
437436 try {
438- const description = await this . peerConnection . createOffer ( this . sdpConstraints ) ;
437+ const description = await this . peerConnection . createOffer ( ) ;
438+ log . debug ( 'Generated SDP Offer:' , description . sdp ) ;
439439 this . setLocalDescription ( description ) ;
440440 } catch ( error ) {
441441 this . onWebRTCConnectionError ( error ) ;
@@ -470,6 +470,7 @@ export default class DeviceRenderer {
470470
471471 const config = {
472472 iceServers : iceServers ,
473+ bundlePolicy : 'max-compat' ,
473474 } ;
474475
475476 if ( ! this . peerConnection ) {
@@ -488,6 +489,13 @@ export default class DeviceRenderer {
488489 this . useWebsocketAsDataChannel = true ;
489490 }
490491
492+ /*
493+ * Add transceivers to receive audio and video (VM screen/audio)
494+ * This replaces the legacy offerToReceiveAudio/Video constraints
495+ */
496+ this . peerConnection . addTransceiver ( 'audio' , { direction : 'recvonly' } ) ;
497+ this . peerConnection . addTransceiver ( 'video' , { direction : 'recvonly' } ) ;
498+
491499 this . peerConnection . onicecandidate = ( event ) => {
492500 if ( typeof event . candidate === 'undefined' ) {
493501 // Nothing we can do
@@ -971,6 +979,24 @@ export default class DeviceRenderer {
971979 return ;
972980 }
973981
982+ // Cleanup specific widget resources dynamically
983+ this . widgets . forEach ( ( widget ) => {
984+ if ( widget && typeof widget . destroy === 'function' ) {
985+ widget . destroy ( ) ;
986+ }
987+ } ) ;
988+
989+ if ( this . store && this . store . destroy ) {
990+ this . store . destroy ( ) ;
991+ }
992+
993+ if ( this . fileUploaderWorkerBlobSRC ) {
994+ URL . revokeObjectURL ( this . fileUploaderWorkerBlobSRC ) ;
995+ this . fileUploaderWorkerBlobSRC = null ;
996+ }
997+
998+ this . emit ( 'destroyed' ) ;
999+
9741000 this . removeAllListeners ( ) ;
9751001 this . disconnect ( ) ;
9761002 this . peerConnectionStats ?. destroy ( ) ;
0 commit comments