@@ -567,51 +567,69 @@ export class MatrixCall extends EventEmitter {
567567 logger . info ( `Pushed remote stream (id="${ stream . id } ", active="${ stream . active } ")` ) ;
568568 }
569569
570- private pushLocalFeed ( stream : MediaStream , purpose : SDPStreamMetadataPurpose , addToPeerConnection = true ) : void {
570+ private pushNewLocalFeed ( stream : MediaStream , purpose : SDPStreamMetadataPurpose , addToPeerConnection = true ) : void {
571571 const userId = this . client . getUserId ( ) ;
572572
573+ // TODO: Find out what is going on here
574+ // why do we enable audio (and only audio) tracks here? -- matthew
575+ setTracksEnabled ( stream . getAudioTracks ( ) , true ) ;
576+
573577 // We try to replace an existing feed if there already is one with the same purpose
574578 const existingFeed = this . getLocalFeeds ( ) . find ( ( feed ) => feed . purpose === purpose ) ;
575579 if ( existingFeed ) {
576580 existingFeed . setNewStream ( stream ) ;
577581 } else {
578- this . feeds . push ( new CallFeed ( {
579- client : this . client ,
580- roomId : this . roomId ,
581- audioMuted : stream . getAudioTracks ( ) . length === 0 ,
582- videoMuted : stream . getVideoTracks ( ) . length === 0 ,
583- userId,
584- stream,
585- purpose,
586- } ) ) ;
582+ this . pushLocalFeed (
583+ new CallFeed ( {
584+ client : this . client ,
585+ roomId : this . roomId ,
586+ audioMuted : stream . getAudioTracks ( ) . length === 0 ,
587+ videoMuted : stream . getVideoTracks ( ) . length === 0 ,
588+ userId,
589+ stream,
590+ purpose,
591+ } ) ,
592+ addToPeerConnection ,
593+ ) ;
587594 this . emit ( CallEvent . FeedsChanged , this . feeds ) ;
588595 }
596+ }
589597
590- // TODO: Find out what is going on here
591- // why do we enable audio (and only audio) tracks here? -- matthew
592- setTracksEnabled ( stream . getAudioTracks ( ) , true ) ;
598+ /**
599+ * Pushes supplied feed to the call
600+ * @param {CallFeed } callFeed to push
601+ * @param {boolean } addToPeerConnection whether to add the tracks to the peer connection
602+ */
603+ public pushLocalFeed ( callFeed : CallFeed , addToPeerConnection = true ) : void {
604+ this . feeds . push ( callFeed ) ;
593605
594606 if ( addToPeerConnection ) {
595- const senderArray = purpose === SDPStreamMetadataPurpose . Usermedia ?
607+ const senderArray = callFeed . purpose === SDPStreamMetadataPurpose . Usermedia ?
596608 this . usermediaSenders : this . screensharingSenders ;
597609 // Empty the array
598610 senderArray . splice ( 0 , senderArray . length ) ;
599611
600- this . emit ( CallEvent . FeedsChanged , this . feeds ) ;
601- for ( const track of stream . getTracks ( ) ) {
612+ for ( const track of callFeed . stream . getTracks ( ) ) {
602613 logger . info (
603614 `Adding track (` +
604615 `id="${ track . id } ", ` +
605616 `kind="${ track . kind } ", ` +
606- `streamId="${ stream . id } ", ` +
607- `streamPurpose="${ purpose } "` +
617+ `streamId="${ callFeed . stream } ", ` +
618+ `streamPurpose="${ callFeed . purpose } "` +
608619 `) to peer connection` ,
609620 ) ;
610- senderArray . push ( this . peerConn . addTrack ( track , stream ) ) ;
621+ senderArray . push ( this . peerConn . addTrack ( track , callFeed . stream ) ) ;
611622 }
612623 }
613624
614- logger . info ( `Pushed local stream (id="${ stream . id } ", active="${ stream . active } ", purpose="${ purpose } ")` ) ;
625+ logger . info (
626+ `Pushed local stream ` +
627+ `(id="${ callFeed . stream . id } ", ` +
628+ `active="${ callFeed . stream . active } ", ` +
629+ `purpose="${ callFeed . purpose } ")` ,
630+ ) ;
631+
632+ this . emit ( CallEvent . FeedsChanged , this . feeds ) ;
615633 }
616634
617635 /**
@@ -794,11 +812,27 @@ export class MatrixCall extends EventEmitter {
794812 this . waitForLocalAVStream = true ;
795813
796814 try {
797- const mediaStream = await this . client . getMediaHandler ( ) . getUserMediaStream (
815+ const stream = await this . client . getMediaHandler ( ) . getUserMediaStream (
798816 answerWithAudio , answerWithVideo ,
799817 ) ;
800818 this . waitForLocalAVStream = false ;
801- this . gotUserMediaForAnswer ( mediaStream ) ;
819+ const usermediaFeed = new CallFeed ( {
820+ client : this . client ,
821+ roomId : this . roomId ,
822+ userId : this . client . getUserId ( ) ,
823+ stream,
824+ purpose : SDPStreamMetadataPurpose . Usermedia ,
825+ audioMuted : stream . getAudioTracks ( ) . length === 0 ,
826+ videoMuted : stream . getVideoTracks ( ) . length === 0 ,
827+ } ) ;
828+
829+ const feeds = [ usermediaFeed ] ;
830+
831+ if ( this . localScreensharingFeed ) {
832+ feeds . push ( this . localScreensharingFeed ) ;
833+ }
834+
835+ this . answerWithCallFeeds ( feeds ) ;
802836 } catch ( e ) {
803837 if ( answerWithVideo ) {
804838 // Try to answer without video
@@ -816,6 +850,14 @@ export class MatrixCall extends EventEmitter {
816850 }
817851 }
818852
853+ public answerWithCallFeeds ( callFeeds : CallFeed [ ] ) : void {
854+ if ( this . inviteOrAnswerSent ) return ;
855+
856+ logger . debug ( `Answering call ${ this . callId } ` ) ;
857+
858+ this . gotCallFeedsForAnswer ( callFeeds ) ;
859+ }
860+
819861 /**
820862 * Replace this call with a new call, e.g. for glare resolution. Used by
821863 * MatrixClient.
@@ -827,7 +869,7 @@ export class MatrixCall extends EventEmitter {
827869 newCall . waitForLocalAVStream = true ;
828870 } else if ( [ CallState . CreateOffer , CallState . InviteSent ] . includes ( this . state ) ) {
829871 logger . debug ( "Handing local stream to new call" ) ;
830- newCall . gotUserMediaForAnswer ( this . localUsermediaStream ) ;
872+ newCall . gotCallFeedsForAnswer ( this . getLocalFeeds ( ) ) ;
831873 }
832874 this . successor = newCall ;
833875 this . emit ( CallEvent . Replaced , newCall ) ;
@@ -899,7 +941,7 @@ export class MatrixCall extends EventEmitter {
899941 if ( this . hasLocalUserMediaAudioTrack ) return ;
900942 if ( this . hasLocalUserMediaVideoTrack ) return ;
901943
902- this . pushLocalFeed ( stream , SDPStreamMetadataPurpose . Usermedia ) ;
944+ this . pushNewLocalFeed ( stream , SDPStreamMetadataPurpose . Usermedia ) ;
903945 } else if ( upgradeAudio ) {
904946 if ( this . hasLocalUserMediaAudioTrack ) return ;
905947
@@ -965,7 +1007,7 @@ export class MatrixCall extends EventEmitter {
9651007 try {
9661008 const stream = await this . client . getMediaHandler ( ) . getScreensharingStream ( desktopCapturerSourceId ) ;
9671009 if ( ! stream ) return false ;
968- this . pushLocalFeed ( stream , SDPStreamMetadataPurpose . Screenshare ) ;
1010+ this . pushNewLocalFeed ( stream , SDPStreamMetadataPurpose . Screenshare ) ;
9691011 return true ;
9701012 } catch ( err ) {
9711013 this . emit ( CallEvent . Error ,
@@ -1007,7 +1049,7 @@ export class MatrixCall extends EventEmitter {
10071049 } ) ;
10081050 sender . replaceTrack ( track ) ;
10091051
1010- this . pushLocalFeed ( stream , SDPStreamMetadataPurpose . Screenshare , false ) ;
1052+ this . pushNewLocalFeed ( stream , SDPStreamMetadataPurpose . Screenshare , false ) ;
10111053
10121054 return true ;
10131055 } catch ( err ) {
@@ -1167,26 +1209,25 @@ export class MatrixCall extends EventEmitter {
11671209 setTracksEnabled ( this . localUsermediaStream . getVideoTracks ( ) , ! vidShouldBeMuted ) ;
11681210 }
11691211
1170- /**
1171- * Internal
1172- * @param {Object } stream
1173- */
1174- private gotUserMediaForInvite = async ( stream : MediaStream ) : Promise < void > => {
1212+ private gotCallFeedsForInvite ( callFeeds : CallFeed [ ] , requestScreenshareFeed = false ) : void {
11751213 if ( this . successor ) {
1176- this . successor . gotUserMediaForAnswer ( stream ) ;
1214+ this . successor . gotCallFeedsForAnswer ( callFeeds ) ;
11771215 return ;
11781216 }
11791217 if ( this . callHasEnded ( ) ) {
11801218 this . stopAllMedia ( ) ;
11811219 return ;
11821220 }
11831221
1184- this . pushLocalFeed ( stream , SDPStreamMetadataPurpose . Usermedia ) ;
1222+ for ( const feed of callFeeds ) {
1223+ this . pushLocalFeed ( feed ) ;
1224+ }
1225+
11851226 this . setState ( CallState . CreateOffer ) ;
11861227
11871228 logger . debug ( "gotUserMediaForInvite" ) ;
11881229 // Now we wait for the negotiationneeded event
1189- } ;
1230+ }
11901231
11911232 private async sendAnswer ( ) : Promise < void > {
11921233 const answerContent = {
@@ -1235,12 +1276,15 @@ export class MatrixCall extends EventEmitter {
12351276 this . sendCandidateQueue ( ) ;
12361277 }
12371278
1238- private gotUserMediaForAnswer = async ( stream : MediaStream ) : Promise < void > => {
1239- if ( this . callHasEnded ( ) ) {
1240- return ;
1279+ private async gotCallFeedsForAnswer ( callFeeds : CallFeed [ ] ) : Promise < void > {
1280+ if ( this . callHasEnded ( ) ) return ;
1281+
1282+ this . waitForLocalAVStream = false ;
1283+
1284+ for ( const feed of callFeeds ) {
1285+ this . pushLocalFeed ( feed ) ;
12411286 }
12421287
1243- this . pushLocalFeed ( stream , SDPStreamMetadataPurpose . Usermedia ) ;
12441288 this . setState ( CallState . CreateAnswer ) ;
12451289
12461290 let myAnswer ;
@@ -1268,7 +1312,7 @@ export class MatrixCall extends EventEmitter {
12681312 this . terminate ( CallParty . Local , CallErrorCode . SetLocalDescription , true ) ;
12691313 return ;
12701314 }
1271- } ;
1315+ }
12721316
12731317 /**
12741318 * Internal
@@ -2010,15 +2054,41 @@ export class MatrixCall extends EventEmitter {
20102054 * @throws if have passed audio=false.
20112055 */
20122056 public async placeCall ( audio : boolean , video : boolean ) : Promise < void > {
2013- logger . debug ( `placeCall audio=${ audio } video=${ video } ` ) ;
20142057 if ( ! audio ) {
20152058 throw new Error ( "You CANNOT start a call without audio" ) ;
20162059 }
2060+ this . setState ( CallState . WaitLocalMedia ) ;
2061+
2062+ try {
2063+ const stream = await this . client . getMediaHandler ( ) . getUserMediaStream ( audio , video ) ;
2064+ const callFeed = new CallFeed ( {
2065+ client : this . client ,
2066+ roomId : this . roomId ,
2067+ userId : this . client . getUserId ( ) ,
2068+ stream,
2069+ purpose : SDPStreamMetadataPurpose . Usermedia ,
2070+ audioMuted : stream . getAudioTracks ( ) . length === 0 ,
2071+ videoMuted : stream . getVideoTracks ( ) . length === 0 ,
2072+ } ) ;
2073+ await this . placeCallWithCallFeeds ( [ callFeed ] ) ;
2074+ } catch ( e ) {
2075+ this . getUserMediaFailed ( e ) ;
2076+ return ;
2077+ }
2078+ }
2079+
2080+ /**
2081+ * Place a call to this room with call feed.
2082+ * @param {CallFeed[] } callFeeds to use
2083+ * @throws if you have not specified a listener for 'error' events.
2084+ * @throws if have passed audio=false.
2085+ */
2086+ public async placeCallWithCallFeeds ( callFeeds : CallFeed [ ] , requestScreenshareFeed = false ) : Promise < void > {
20172087 this . checkForErrorListener ( ) ;
2088+ this . direction = CallDirection . Outbound ;
2089+
20182090 // XXX Find a better way to do this
20192091 this . client . callEventHandler . calls . set ( this . callId , this ) ;
2020- this . setState ( CallState . WaitLocalMedia ) ;
2021- this . direction = CallDirection . Outbound ;
20222092
20232093 // make sure we have valid turn creds. Unless something's gone wrong, it should
20242094 // poll and keep the credentials valid so this should be instant.
@@ -2030,14 +2100,7 @@ export class MatrixCall extends EventEmitter {
20302100 // create the peer connection now so it can be gathering candidates while we get user
20312101 // media (assuming a candidate pool size is configured)
20322102 this . peerConn = this . createPeerConnection ( ) ;
2033-
2034- try {
2035- const mediaStream = await this . client . getMediaHandler ( ) . getUserMediaStream ( audio , video ) ;
2036- this . gotUserMediaForInvite ( mediaStream ) ;
2037- } catch ( e ) {
2038- this . getUserMediaFailed ( e ) ;
2039- return ;
2040- }
2103+ this . gotCallFeedsForInvite ( callFeeds , requestScreenshareFeed ) ;
20412104 }
20422105
20432106 private createPeerConnection ( ) : RTCPeerConnection {
0 commit comments