|
2 | 2 | Copyright 2015, 2016 OpenMarket Ltd
|
3 | 3 | Copyright 2017 New Vector Ltd
|
4 | 4 | Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
| 5 | +Copyright 2021 - 2022 Šimon Brandner <[email protected]> |
5 | 6 |
|
6 | 7 | Licensed under the Apache License, Version 2.0 (the "License");
|
7 | 8 | you may not use this file except in compliance with the License.
|
@@ -950,29 +951,13 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
|
950 | 951 | if (!this.opponentSupportsSDPStreamMetadata()) return;
|
951 | 952 |
|
952 | 953 | try {
|
953 |
| - const upgradeAudio = audio && !this.hasLocalUserMediaAudioTrack; |
954 |
| - const upgradeVideo = video && !this.hasLocalUserMediaVideoTrack; |
955 |
| - logger.debug(`Upgrading call: audio?=${upgradeAudio} video?=${upgradeVideo}`); |
956 |
| - |
957 |
| - const stream = await this.client.getMediaHandler().getUserMediaStream(upgradeAudio, upgradeVideo, false); |
958 |
| - if (upgradeAudio && upgradeVideo) { |
959 |
| - if (this.hasLocalUserMediaAudioTrack) return; |
960 |
| - if (this.hasLocalUserMediaVideoTrack) return; |
961 |
| - |
962 |
| - this.pushNewLocalFeed(stream, SDPStreamMetadataPurpose.Usermedia); |
963 |
| - } else if (upgradeAudio) { |
964 |
| - if (this.hasLocalUserMediaAudioTrack) return; |
965 |
| - |
966 |
| - const audioTrack = stream.getAudioTracks()[0]; |
967 |
| - this.localUsermediaStream.addTrack(audioTrack); |
968 |
| - this.peerConn.addTrack(audioTrack, this.localUsermediaStream); |
969 |
| - } else if (upgradeVideo) { |
970 |
| - if (this.hasLocalUserMediaVideoTrack) return; |
971 |
| - |
972 |
| - const videoTrack = stream.getVideoTracks()[0]; |
973 |
| - this.localUsermediaStream.addTrack(videoTrack); |
974 |
| - this.peerConn.addTrack(videoTrack, this.localUsermediaStream); |
975 |
| - } |
| 954 | + const getAudio = audio || this.hasLocalUserMediaAudioTrack; |
| 955 | + const getVideo = video || this.hasLocalUserMediaVideoTrack; |
| 956 | + |
| 957 | + // updateLocalUsermediaStream() will take the tracks, use them as |
| 958 | + // replacement and throw the stream away, so it isn't reusable |
| 959 | + const stream = await this.client.getMediaHandler().getUserMediaStream(getAudio, getVideo, false); |
| 960 | + await this.updateLocalUsermediaStream(stream, audio, video); |
976 | 961 | } catch (error) {
|
977 | 962 | logger.error("Failed to upgrade the call", error);
|
978 | 963 | this.emit(CallEvent.Error,
|
@@ -1088,6 +1073,63 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
|
1088 | 1073 | }
|
1089 | 1074 | }
|
1090 | 1075 |
|
| 1076 | + /** |
| 1077 | + * Replaces/adds the tracks from the passed stream to the localUsermediaStream |
| 1078 | + * @param {MediaStream} stream to use a replacement for the local usermedia stream |
| 1079 | + */ |
| 1080 | + public async updateLocalUsermediaStream( |
| 1081 | + stream: MediaStream, forceAudio = false, forceVideo = false, |
| 1082 | + ): Promise<void> { |
| 1083 | + const callFeed = this.localUsermediaFeed; |
| 1084 | + const audioEnabled = forceAudio || (!callFeed.isAudioMuted() && !this.remoteOnHold); |
| 1085 | + const videoEnabled = forceVideo || (!callFeed.isVideoMuted() && !this.remoteOnHold); |
| 1086 | + setTracksEnabled(stream.getAudioTracks(), audioEnabled); |
| 1087 | + setTracksEnabled(stream.getVideoTracks(), videoEnabled); |
| 1088 | + |
| 1089 | + // We want to keep the same stream id, so we replace the tracks rather than the whole stream |
| 1090 | + for (const track of this.localUsermediaStream.getTracks()) { |
| 1091 | + this.localUsermediaStream.removeTrack(track); |
| 1092 | + track.stop(); |
| 1093 | + } |
| 1094 | + for (const track of stream.getTracks()) { |
| 1095 | + this.localUsermediaStream.addTrack(track); |
| 1096 | + } |
| 1097 | + |
| 1098 | + const newSenders = []; |
| 1099 | + |
| 1100 | + for (const track of stream.getTracks()) { |
| 1101 | + const oldSender = this.usermediaSenders.find((sender) => sender.track?.kind === track.kind); |
| 1102 | + let newSender: RTCRtpSender; |
| 1103 | + |
| 1104 | + if (oldSender) { |
| 1105 | + logger.info( |
| 1106 | + `Replacing track (` + |
| 1107 | + `id="${track.id}", ` + |
| 1108 | + `kind="${track.kind}", ` + |
| 1109 | + `streamId="${stream.id}", ` + |
| 1110 | + `streamPurpose="${callFeed.purpose}"` + |
| 1111 | + `) to peer connection`, |
| 1112 | + ); |
| 1113 | + await oldSender.replaceTrack(track); |
| 1114 | + newSender = oldSender; |
| 1115 | + } else { |
| 1116 | + logger.info( |
| 1117 | + `Adding track (` + |
| 1118 | + `id="${track.id}", ` + |
| 1119 | + `kind="${track.kind}", ` + |
| 1120 | + `streamId="${stream.id}", ` + |
| 1121 | + `streamPurpose="${callFeed.purpose}"` + |
| 1122 | + `) to peer connection`, |
| 1123 | + ); |
| 1124 | + newSender = this.peerConn.addTrack(track, this.localUsermediaStream); |
| 1125 | + } |
| 1126 | + |
| 1127 | + newSenders.push(newSender); |
| 1128 | + } |
| 1129 | + |
| 1130 | + this.usermediaSenders = newSenders; |
| 1131 | + } |
| 1132 | + |
1091 | 1133 | /**
|
1092 | 1134 | * Set whether our outbound video should be muted or not.
|
1093 | 1135 | * @param {boolean} muted True to mute the outbound video.
|
@@ -1216,8 +1258,8 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
|
1216 | 1258 | [SDPStreamMetadataKey]: this.getLocalSDPStreamMetadata(),
|
1217 | 1259 | });
|
1218 | 1260 |
|
1219 |
| - const micShouldBeMuted = this.localUsermediaFeed?.isAudioMuted() || this.remoteOnHold; |
1220 |
| - const vidShouldBeMuted = this.localUsermediaFeed?.isVideoMuted() || this.remoteOnHold; |
| 1261 | + const micShouldBeMuted = this.isMicrophoneMuted() || this.remoteOnHold; |
| 1262 | + const vidShouldBeMuted = this.isLocalVideoMuted() || this.remoteOnHold; |
1221 | 1263 |
|
1222 | 1264 | setTracksEnabled(this.localUsermediaStream.getAudioTracks(), !micShouldBeMuted);
|
1223 | 1265 | setTracksEnabled(this.localUsermediaStream.getVideoTracks(), !vidShouldBeMuted);
|
|
0 commit comments