Skip to content

Commit 9f65374

Browse files
Fix black video in calls, fixes #1002
This introduces multiple hacks to make things work: 1.) Rewrite jingle from/to peer to only contain VP8 codec. In particular we don't want to include error correcting pseudo-codecs like red, rtx etc. 2.) Use the video transceiver's setCodecPreferences() method to restrict to VP8, too. Also no error-correcting pseudo-codecs. 3.) Use uuid as stream id (not sure if this made any difference, though)
1 parent ec8ab3f commit 9f65374

File tree

3 files changed

+46
-12
lines changed

3 files changed

+46
-12
lines changed

Monal/Classes/AVCallUI.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ struct AVCallUI: View {
7272
}
7373

7474
func maybeStartRenderer() {
75-
if !videoRenderingStarted && MLCallType(rawValue:call.callType) == .video && (MLCallState(rawValue:call.state) == .connecting || MLCallState(rawValue:call.state) == .connected) {
75+
if !videoRenderingStarted && MLCallType(rawValue:call.callType) == .video && MLCallState(rawValue:call.state) == .connected {
7676
DDLogInfo("Starting local and remote video renderers...")
7777
//local video should be displayed as "mirrored", if front camera is used
7878
self.localRenderer.transform = CGAffineTransformMakeScale(cameraPosition == .front ? -1.0 : 1.0, 1.0)

Monal/Classes/MLCall.m

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -948,10 +948,10 @@ -(void) offerSDP
948948
self.encryptionState = MLCallEncryptionStateClear;
949949

950950
XMPPIQ* sdpIQ = [[XMPPIQ alloc] initWithType:kiqSetType to:self.fullRemoteJid];
951-
[sdpIQ addChildNode:[[MLXMLNode alloc] initWithElement:@"jingle" andNamespace:@"urn:xmpp:jingle:1" withAttributes:@{
951+
[sdpIQ addChildNode:[self sanitizeJingleNode:[[MLXMLNode alloc] initWithElement:@"jingle" andNamespace:@"urn:xmpp:jingle:1" withAttributes:@{
952952
@"action": @"session-initiate",
953953
@"sid": self.jmiid,
954-
} andChildren:children andData:nil]];
954+
} andChildren:children andData:nil]]];
955955
@synchronized(self.candidateQueueLock) {
956956
self.localSDP = sdpIQ;
957957
}
@@ -1639,12 +1639,12 @@ -(void) processIncomingSDP:(NSNotification*) notification
16391639
if([iqNode check:@"{urn:xmpp:jingle:1}jingle<action=session-accept>"])
16401640
{
16411641
type = @"answer";
1642-
rawSDP = [HelperTools xml2sdp:[iqNode findFirst:@"{urn:xmpp:jingle:1}jingle"] withInitiator:NO];
1642+
rawSDP = [HelperTools xml2sdp:[self sanitizeJingleNode:[iqNode findFirst:@"{urn:xmpp:jingle:1}jingle"]] withInitiator:NO];
16431643
}
16441644
else if([iqNode check:@"{urn:xmpp:jingle:1}jingle<action=session-initiate>"])
16451645
{
16461646
type = @"offer";
1647-
rawSDP = [HelperTools xml2sdp:[iqNode findFirst:@"{urn:xmpp:jingle:1}jingle"] withInitiator:YES];
1647+
rawSDP = [HelperTools xml2sdp:[self sanitizeJingleNode:[iqNode findFirst:@"{urn:xmpp:jingle:1}jingle"]] withInitiator:YES];
16481648
}
16491649
}
16501650
//handle session-terminate: fake jmi finish message and handle it
@@ -1758,10 +1758,10 @@ -(void) processIncomingSDP:(NSNotification*) notification
17581758
[self.account send:[[XMPPIQ alloc] initAsResponseTo:iqNode]];
17591759

17601760
XMPPIQ* sdpIQ = [[XMPPIQ alloc] initWithType:kiqSetType to:self.fullRemoteJid];
1761-
[sdpIQ addChildNode:[[MLXMLNode alloc] initWithElement:@"jingle" andNamespace:@"urn:xmpp:jingle:1" withAttributes:@{
1761+
[sdpIQ addChildNode:[self sanitizeJingleNode:[[MLXMLNode alloc] initWithElement:@"jingle" andNamespace:@"urn:xmpp:jingle:1" withAttributes:@{
17621762
@"action": @"session-accept",
17631763
@"sid": self.jmiid,
1764-
} andChildren:children andData:nil]];
1764+
} andChildren:children andData:nil]]];
17651765
[self.account send:sdpIQ];
17661766

17671767
@synchronized(self.candidateQueueLock) {
@@ -1884,4 +1884,17 @@ -(BOOL) decryptFingerprintsInIqNode:(XMPPIQ*) iqNode
18841884
return retval;
18851885
}
18861886

1887+
-(MLXMLNode*) sanitizeJingleNode:(MLXMLNode*) jingleNode
1888+
{
1889+
//modify jingle to only include VP8, VP9 and H264 codecs
1890+
//in particular this means: not having any error correction codecs: these cause black video streams
1891+
NSArray* allowedCodecs = @[@"VP8"];//, @"VP9", @"H264"];
1892+
MLXMLNode* sanitizedNode = [jingleNode copy];
1893+
for(MLXMLNode* videoNode in [sanitizedNode find:@"content/{urn:xmpp:jingle:apps:rtp:1}description<media=video>"])
1894+
for(MLXMLNode* payloadNode in [videoNode find:@"payload-type"])
1895+
if(![allowedCodecs containsObject:[payloadNode findFirst:@"/@name"]])
1896+
[videoNode removeChildNode:payloadNode];
1897+
return sanitizedNode;
1898+
}
1899+
18871900
@end

Monal/Classes/WebRTCClient.swift

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ final class WebRTCClient: NSObject {
3232
@objc public let peerConnection: RTCPeerConnection
3333
private let rtcAudioSession = RTCAudioSession.sharedInstance()
3434
private let audioQueue = DispatchQueue(label: "audio")
35-
private let streamId = "-"
3635
private var mediaConstrains: [String:String] = [:]
3736
private var videoCapturer: RTCVideoCapturer?
3837
private var localVideoTrack: RTCVideoTrack?
@@ -110,8 +109,8 @@ final class WebRTCClient: NSObject {
110109
self.peerConnection = peerConnection!
111110
super.init()
112111

113-
self.createMediaSenders(audioOnly: audioOnly)
114112
self.peerConnection.delegate = self
113+
self.createMediaSenders(audioOnly: audioOnly)
115114

116115
// see https://stackoverflow.com/a/43765394
117116
if audioOnly {
@@ -207,15 +206,30 @@ final class WebRTCClient: NSObject {
207206

208207
@objc
209208
func renderRemoteVideo(to renderer: RTCVideoRenderer) {
209+
DDLogInfo("Now rendering remote video to RTCVideoRenderer view...")
210210
self.remoteVideoTrack?.add(renderer)
211211
}
212212

213213
@objc
214214
func addVideo() {
215215
let videoTrack = self.createVideoTrack()
216216
self.localVideoTrack = videoTrack
217-
self.peerConnection.add(videoTrack, streamIds: [self.streamId])
218-
self.remoteVideoTrack = self.peerConnection.transceivers.first { $0.mediaType == .video }?.receiver.track as? RTCVideoTrack
217+
218+
self.peerConnection.add(videoTrack, streamIds: [UUID().uuidString])
219+
let videoTransceiver = self.peerConnection.transceivers.first { $0.mediaType == .video }!
220+
// let videoTransceiver = self.peerConnection.addTransceiver(of:.video, init:RTCRtpTransceiverInit())!
221+
// videoTransceiver.sender.track = videoTrack
222+
223+
let capabilities = WebRTCClient.factory.rtpSenderCapabilities(forKind: kRTCMediaStreamTrackKindVideo)
224+
let codecs = capabilities.codecs
225+
let preferredCodecs = codecs.filter { $0.name=="VP8" }
226+
do {
227+
try videoTransceiver.setCodecPreferences(preferredCodecs)
228+
} catch {
229+
DDLogError("Error setting codec preferences: \(String(describing:error))")
230+
}
231+
232+
self.remoteVideoTrack = videoTransceiver.receiver.track as? RTCVideoTrack
219233
}
220234

221235
@objc
@@ -236,7 +250,10 @@ final class WebRTCClient: NSObject {
236250
private func createMediaSenders(audioOnly: Bool) {
237251
//Audio
238252
let audioTrack = self.createAudioTrack()
239-
self.peerConnection.add(audioTrack, streamIds: [self.streamId])
253+
254+
// let audioTransceiver = self.peerConnection.addTransceiver(of:.audio, init:RTCRtpTransceiverInit())
255+
// audioTransceiver?.sender.track = audioTrack
256+
self.peerConnection.add(audioTrack, streamIds: [UUID().uuidString])
240257

241258
//Video
242259
if !audioOnly {
@@ -313,10 +330,14 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
313330

314331
func peerConnection(_ peerConnection: RTCPeerConnection, didAdd stream: RTCMediaStream) {
315332
DDLogDebug("peerConnection did add stream")
333+
// self.remoteVideoTrack = stream.videoTracks.first(where: { $0 is RTCVideoTrack }) as? RTCVideoTrack
316334
}
317335

318336
func peerConnection(_ peerConnection: RTCPeerConnection, didRemove stream: RTCMediaStream) {
319337
DDLogDebug("peerConnection did remove stream")
338+
// if stream.videoTracks.first(where: { $0.trackId == self.remoteVideoTrack?.trackId }) != nil {
339+
// self.remoteVideoTrack = nil
340+
// }
320341
}
321342

322343
func peerConnectionShouldNegotiate(_ peerConnection: RTCPeerConnection) {

0 commit comments

Comments
 (0)