This commit is contained in:
Ali 2020-11-12 20:56:44 +04:00
parent 8081430ad2
commit 1f41873ff2
6 changed files with 323 additions and 92 deletions

View File

@ -741,7 +741,11 @@ private enum DebugControllerEntry: ItemListNodeEntry {
guard let context = arguments.context else { guard let context = arguments.context else {
return return
} }
let _ = (resolvePeerByName(account: context.account, name: "tgbetachat") let controller = GroupCallController(context: context)
controller.navigationPresentation = .modal
arguments.pushController(controller)
/*let _ = (resolvePeerByName(account: context.account, name: "tgbetachat")
|> deliverOnMainQueue).start(next: { peerId in |> deliverOnMainQueue).start(next: { peerId in
guard let peerId = peerId else { guard let peerId = peerId else {
return return
@ -749,7 +753,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
let controller = VoiceChatController(context: context, peerId: peerId) let controller = VoiceChatController(context: context, peerId: peerId)
arguments.presentController(controller, nil) arguments.presentController(controller, nil)
}) })*/
}) })
case let .preferredVideoCodec(_, title, value, isSelected): case let .preferredVideoCodec(_, title, value, isSelected):
return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .right, checked: isSelected, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .right, checked: isSelected, zeroSeparatorInsets: false, sectionId: self.section, action: {

View File

@ -65,8 +65,8 @@ public final class GroupCallController: ViewController {
}, availableOutputsChanged: { _, _ in }, availableOutputsChanged: { _, _ in
}) })
let videoCapturer = OngoingCallVideoCapturer() //let videoCapturer = OngoingCallVideoCapturer()
self.videoCapturer = videoCapturer //self.videoCapturer = videoCapturer
let callContext = GroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: videoCapturer) let callContext = GroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: videoCapturer)
self.callContext = callContext self.callContext = callContext

View File

@ -653,8 +653,9 @@ private extension ConferenceDescription.ChannelBundle {
private struct RemoteOffer { private struct RemoteOffer {
struct State: Equatable { struct State: Equatable {
struct Item: Equatable { struct Item: Equatable {
var isMain: Bool
var audioSsrc: Int var audioSsrc: Int
var videoSsrc: Int var videoSsrc: Int?
var isRemoved: Bool var isRemoved: Bool
} }
@ -676,11 +677,11 @@ private extension ConferenceDescription {
return result return result
} }
func offerSdp(sessionId: UInt32, bundleId: String, bridgeHost: String, transport: ConferenceDescription.Transport, currentState: RemoteOffer.State?) -> RemoteOffer? { func offerSdp(sessionId: UInt32, bundleId: String, bridgeHost: String, transport: ConferenceDescription.Transport, currentState: RemoteOffer.State?, isAnswer: Bool) -> RemoteOffer? {
struct StreamSpec { struct StreamSpec {
var isMain: Bool var isMain: Bool
var audioSsrc: Int var audioSsrc: Int
var videoSsrc: Int var videoSsrc: Int?
var isRemoved: Bool var isRemoved: Bool
} }
@ -698,15 +699,58 @@ private extension ConferenceDescription {
appendSdp("s=-") appendSdp("s=-")
appendSdp("t=0 0") appendSdp("t=0 0")
appendSdp("a=group:BUNDLE \(bundleStreams.map({ "audio\($0.audioSsrc) video\($0.videoSsrc)" }).joined(separator: " "))") var bundleString = "a=group:BUNDLE"
for stream in bundleStreams {
bundleString.append(" ")
if let videoSsrc = stream.videoSsrc {
let audioMid: String
let videoMid: String
if stream.isMain {
audioMid = "0"
videoMid = "1"
} else {
audioMid = "audio\(stream.audioSsrc)"
videoMid = "video\(videoSsrc)"
}
bundleString.append("\(audioMid) \(videoMid)")
} else {
let audioMid: String
if stream.isMain {
audioMid = "0"
} else {
audioMid = "audio\(stream.audioSsrc)"
}
bundleString.append("\(audioMid)")
}
}
appendSdp(bundleString)
appendSdp("a=ice-lite") appendSdp("a=ice-lite")
for stream in bundleStreams { for stream in bundleStreams {
let audioMid: String
let videoMid: String?
if stream.isMain {
audioMid = "0"
if let videoSsrc = stream.videoSsrc {
videoMid = "1"
} else {
videoMid = nil
}
} else {
audioMid = "audio\(stream.audioSsrc)"
if let videoSsrc = stream.videoSsrc {
videoMid = "video\(stream.videoSsrc)"
} else {
videoMid = nil
}
}
appendSdp("m=audio \(stream.isMain ? "1" : "0") RTP/SAVPF 111 126") appendSdp("m=audio \(stream.isMain ? "1" : "0") RTP/SAVPF 111 126")
if stream.isMain { if stream.isMain {
appendSdp("c=IN IP4 0.0.0.0") appendSdp("c=IN IP4 0.0.0.0")
} }
appendSdp("a=mid:audio\(stream.audioSsrc)") appendSdp("a=mid:\(audioMid)")
if stream.isRemoved { if stream.isRemoved {
appendSdp("a=inactive") appendSdp("a=inactive")
} else { } else {
@ -716,7 +760,9 @@ private extension ConferenceDescription {
for fingerprint in transport.fingerprints { for fingerprint in transport.fingerprints {
appendSdp("a=fingerprint:\(fingerprint.hashType) \(fingerprint.fingerprint)") appendSdp("a=fingerprint:\(fingerprint.hashType) \(fingerprint.fingerprint)")
appendSdp("a=setup:\(fingerprint.setup)") //appendSdp("a=setup:\(fingerprint.setup)")
//appendSdp("a=setup:active")
appendSdp("a=setup:passive")
} }
for candidate in transport.candidates { for candidate in transport.candidates {
@ -733,6 +779,8 @@ private extension ConferenceDescription {
var ip = candidate.ip var ip = candidate.ip
if ip.hasPrefix("192.") { if ip.hasPrefix("192.") {
ip = bridgeHost ip = bridgeHost
} else {
continue
} }
candidateString.append("\(ip) ") candidateString.append("\(ip) ")
candidateString.append("\(candidate.port) ") candidateString.append("\(candidate.port) ")
@ -771,62 +819,58 @@ private extension ConferenceDescription {
appendSdp("a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time") appendSdp("a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")
appendSdp("a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01") appendSdp("a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")
appendSdp("a=rtcp-fb:111 transport-cc") appendSdp("a=rtcp-fb:111 transport-cc")
//appendSdp("a=rtcp-fb:111 ccm fir")
//appendSdp("a=rtcp-fb:111 nack")
if stream.isMain { if isAnswer {
appendSdp("a=sendrecv") appendSdp("a=recvonly")
} else { } else {
appendSdp("a=sendonly") if stream.isMain {
appendSdp("a=bundle-only") appendSdp("a=sendrecv")
} else {
appendSdp("a=sendonly")
appendSdp("a=bundle-only")
}
appendSdp("a=ssrc-group:FID \(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) cname:stream\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) msid:stream\(stream.audioSsrc) audio\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) mslabel:audio\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) label:audio\(stream.audioSsrc)")
} }
appendSdp("a=ssrc-group:FID \(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) cname:stream\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) msid:stream\(stream.audioSsrc) audio\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) mslabel:audio\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.audioSsrc) label:audio\(stream.audioSsrc)")
} }
appendSdp("m=video 0 RTP/SAVPF 100") if let videoMid = videoMid {
appendSdp("a=mid:video\(stream.videoSsrc)") appendSdp("m=video 0 RTP/SAVPF 100")
if stream.isRemoved { appendSdp("a=mid:\(videoMid)")
appendSdp("a=inactive") if stream.isRemoved {
continue appendSdp("a=inactive")
} else { continue
/*a=rtpmap:100 VP8/90000
a=fmtp:100 x-google-start-bitrate=800
a=rtcp:1 IN IP4 0.0.0.0
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 goog-remb*/
appendSdp("a=rtpmap:100 VP8/90000")
appendSdp("a=fmtp:100 x-google-start-bitrate=800")
appendSdp("a=rtcp:1 IN IP4 0.0.0.0")
appendSdp("a=rtcp-mux")
appendSdp("a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")
appendSdp("a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")
appendSdp("a=rtcp-fb:100 transport-cc")
appendSdp("a=rtcp-fb:100 ccm fir")
appendSdp("a=rtcp-fb:100 nack")
appendSdp("a=rtcp-fb:100 nack pli")
if stream.isMain {
appendSdp("a=sendrecv")
} else { } else {
appendSdp("a=sendonly") appendSdp("a=rtpmap:100 VP8/90000")
appendSdp("a=fmtp:100 x-google-start-bitrate=800")
appendSdp("a=rtcp:1 IN IP4 0.0.0.0")
appendSdp("a=rtcp-mux")
appendSdp("a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")
appendSdp("a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")
appendSdp("a=rtcp-fb:100 transport-cc")
appendSdp("a=rtcp-fb:100 ccm fir")
appendSdp("a=rtcp-fb:100 nack")
appendSdp("a=rtcp-fb:100 nack pli")
if stream.isMain {
appendSdp("a=sendrecv")
} else {
appendSdp("a=sendonly")
}
appendSdp("a=bundle-only")
appendSdp("a=ssrc-group:FID \(stream.videoSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) cname:stream\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) msid:stream\(stream.audioSsrc) video\(stream.videoSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) mslabel:video\(stream.videoSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) label:video\(stream.videoSsrc)")
} }
appendSdp("a=bundle-only")
appendSdp("a=ssrc-group:FID \(stream.videoSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) cname:stream\(stream.audioSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) msid:stream\(stream.audioSsrc) video\(stream.videoSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) mslabel:video\(stream.videoSsrc)")
appendSdp("a=ssrc:\(stream.videoSsrc) label:video\(stream.videoSsrc)")
} }
} }
@ -843,7 +887,39 @@ private extension ConferenceDescription {
continue continue
} }
for audioChannel in audioContent.channels { for audioChannel in audioContent.channels {
for videoContent in self.contents { if audioChannel.channelBundleId == bundleId {
precondition(audioChannel.sources.count == 1)
streams.append(StreamSpec(
isMain: true,
audioSsrc: audioChannel.sources[0],
videoSsrc: nil,
isRemoved: false
))
maybeMainStreamAudioSsrc = audioChannel.sources[0]
if false && isAnswer {
precondition(audioChannel.ssrcs.count <= 1)
if audioChannel.ssrcs.count == 1 {
streams.append(StreamSpec(
isMain: false,
audioSsrc: audioChannel.ssrcs[0],
videoSsrc: nil,
isRemoved: false
))
}
}
} else {
precondition(audioChannel.ssrcs.count <= 1)
if audioChannel.ssrcs.count == 1 {
streams.append(StreamSpec(
isMain: false,
audioSsrc: audioChannel.ssrcs[0],
videoSsrc: nil,
isRemoved: false
))
}
}
/*for videoContent in self.contents {
if videoContent.name != "video" { if videoContent.name != "video" {
continue continue
} }
@ -861,8 +937,8 @@ private extension ConferenceDescription {
maybeMainStreamAudioSsrc = audioChannel.sources[0] maybeMainStreamAudioSsrc = audioChannel.sources[0]
} else { } else {
precondition(audioChannel.ssrcs.count <= 1) precondition(audioChannel.ssrcs.count <= 1)
precondition(videoChannel.ssrcs.count <= 1) precondition(videoChannel.ssrcs.count <= 2)
if audioChannel.ssrcs.count == 1 && videoChannel.ssrcs.count == 1 { if audioChannel.ssrcs.count == 1 && videoChannel.ssrcs.count <= 2 {
streams.append(StreamSpec( streams.append(StreamSpec(
isMain: false, isMain: false,
audioSsrc: audioChannel.ssrcs[0], audioSsrc: audioChannel.ssrcs[0],
@ -873,7 +949,7 @@ private extension ConferenceDescription {
} }
} }
} }
} }*/
} }
} }
@ -910,6 +986,7 @@ private extension ConferenceDescription {
state: RemoteOffer.State( state: RemoteOffer.State(
items: bundleStreams.map { stream in items: bundleStreams.map { stream in
RemoteOffer.State.Item( RemoteOffer.State.Item(
isMain: stream.isMain,
audioSsrc: stream.audioSsrc, audioSsrc: stream.audioSsrc,
videoSsrc: stream.videoSsrc, videoSsrc: stream.videoSsrc,
isRemoved: stream.isRemoved isRemoved: stream.isRemoved
@ -921,14 +998,14 @@ private extension ConferenceDescription {
mutating func updateLocalChannelFromSdpAnswer(bundleId: String, sdpAnswer: String) { mutating func updateLocalChannelFromSdpAnswer(bundleId: String, sdpAnswer: String) {
var maybeAudioChannel: ConferenceDescription.Content.Channel? var maybeAudioChannel: ConferenceDescription.Content.Channel?
var maybeVideoChannel: ConferenceDescription.Content.Channel? var videoChannel: ConferenceDescription.Content.Channel?
for content in self.contents { for content in self.contents {
for channel in content.channels { for channel in content.channels {
if channel.endpoint == bundleId { if channel.endpoint == bundleId {
if content.name == "audio" { if content.name == "audio" {
maybeAudioChannel = channel maybeAudioChannel = channel
} else if content.name == "video" { } else if content.name == "video" {
maybeVideoChannel = channel videoChannel = channel
} }
break break
} }
@ -939,10 +1016,6 @@ private extension ConferenceDescription {
assert(false) assert(false)
return return
} }
guard var videoChannel = maybeVideoChannel else {
assert(false)
return
}
let lines = sdpAnswer.components(separatedBy: "\n") let lines = sdpAnswer.components(separatedBy: "\n")
@ -1018,10 +1091,6 @@ private extension ConferenceDescription {
} }
audioChannel.sources = audioSources audioChannel.sources = audioSources
/*audioChannel.ssrcGroups = [ConferenceDescription.Content.Channel.SsrcGroup(
sources: audioSources,
semantics: "SIM"
)]*/
audioChannel.payloadTypes = [ audioChannel.payloadTypes = [
ConferenceDescription.Content.Channel.PayloadType( ConferenceDescription.Content.Channel.PayloadType(
@ -1063,13 +1132,13 @@ private extension ConferenceDescription {
), ),
] ]
videoChannel.sources = videoSources videoChannel?.sources = videoSources
/*audioChannel.ssrcGroups = [ConferenceDescription.Content.Channel.SsrcGroup( /*audioChannel.ssrcGroups = [ConferenceDescription.Content.Channel.SsrcGroup(
sources: audioSources, sources: audioSources,
semantics: "SIM" semantics: "SIM"
)]*/ )]*/
videoChannel.payloadTypes = [ videoChannel?.payloadTypes = [
ConferenceDescription.Content.Channel.PayloadType( ConferenceDescription.Content.Channel.PayloadType(
id: 100, id: 100,
name: "VP8", name: "VP8",
@ -1135,7 +1204,7 @@ private extension ConferenceDescription {
if self.contents[i].channels[j].endpoint == bundleId { if self.contents[i].channels[j].endpoint == bundleId {
if self.contents[i].name == "audio" { if self.contents[i].name == "audio" {
self.contents[i].channels[j] = audioChannel self.contents[i].channels[j] = audioChannel
} else if self.contents[i].name == "video" { } else if self.contents[i].name == "video", let videoChannel = videoChannel {
self.contents[i].channels[j] = videoChannel self.contents[i].channels[j] = videoChannel
} }
} }
@ -1380,7 +1449,7 @@ public final class GroupCallContext {
payloadTypes: [], payloadTypes: [],
rtpHdrExts: [] rtpHdrExts: []
) )
let videoChannel = ConferenceDescription.Content.Channel( let videoChannel: ConferenceDescription.Content.Channel? = nil /*ConferenceDescription.Content.Channel(
id: nil, id: nil,
endpoint: bundleId, endpoint: bundleId,
channelBundleId: bundleId, channelBundleId: bundleId,
@ -1393,7 +1462,7 @@ public final class GroupCallContext {
ssrcGroups: [], ssrcGroups: [],
payloadTypes: [], payloadTypes: [],
rtpHdrExts: [] rtpHdrExts: []
) )*/
var foundAudioContent = false var foundAudioContent = false
var foundVideoContent = false var foundVideoContent = false
@ -1419,7 +1488,7 @@ public final class GroupCallContext {
conference.contents[i].channels.append(audioChannel) conference.contents[i].channels.append(audioChannel)
foundAudioContent = true foundAudioContent = true
break break
} else if conference.contents[i].name == "video" { } else if conference.contents[i].name == "video", let videoChannel = videoChannel {
for j in 0 ..< conference.contents[i].channels.count { for j in 0 ..< conference.contents[i].channels.count {
let channel = conference.contents[i].channels[j] let channel = conference.contents[i].channels[j]
conference.contents[i].channels[j] = ConferenceDescription.Content.Channel( conference.contents[i].channels[j] = ConferenceDescription.Content.Channel(
@ -1448,7 +1517,7 @@ public final class GroupCallContext {
channels: [audioChannel] channels: [audioChannel]
)) ))
} }
if !foundVideoContent { if !foundVideoContent, let videoChannel = videoChannel {
conference.contents.append(ConferenceDescription.Content( conference.contents.append(ConferenceDescription.Content(
name: "video", name: "video",
channels: [videoChannel] channels: [videoChannel]
@ -1510,9 +1579,19 @@ public final class GroupCallContext {
strongSelf.localBundleId = bundleId strongSelf.localBundleId = bundleId
strongSelf.localTransport = transport strongSelf.localTransport = transport
//strongSelf.context.emitOffer() let queue = strongSelf.queue
strongSelf.context.emitOffer(adjustSdp: { sdp in
return sdp
}, completion: { offerSdp in
queue.async {
guard let strongSelf = self else {
return
}
strongSelf.relaySdpAnswer(sdpAnswer: offerSdp)
}
})
guard let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: bundleId, bridgeHost: strongSelf.colibriHost, transport: transport, currentState: strongSelf.currentOfferState) else { /*guard let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: bundleId, bridgeHost: strongSelf.colibriHost, transport: transport, currentState: strongSelf.currentOfferState) else {
return return
} }
strongSelf.currentOfferState = offer.state strongSelf.currentOfferState = offer.state
@ -1521,7 +1600,7 @@ public final class GroupCallContext {
for sdp in offer.sdpList { for sdp in offer.sdpList {
strongSelf.context.setOfferSdp(sdp, isPartial: false) strongSelf.context.setOfferSdp(sdp, isPartial: false)
} }*/
})) }))
} }
@ -1530,6 +1609,10 @@ public final class GroupCallContext {
return return
} }
print("===== relaySdpAnswer =====")
print(sdpAnswer)
print("===== -------------- =====")
self.disposable.set((httpJsonRequest(url: "http://\(self.colibriHost):8080/colibri/conferences/\(conferenceId)", method: .get, resultType: [String: Any].self) self.disposable.set((httpJsonRequest(url: "http://\(self.colibriHost):8080/colibri/conferences/\(conferenceId)", method: .get, resultType: [String: Any].self)
|> deliverOn(self.queue)).start(next: { [weak self] result in |> deliverOn(self.queue)).start(next: { [weak self] result in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -1571,8 +1654,24 @@ public final class GroupCallContext {
return return
} }
guard let localTransport = strongSelf.localTransport else {
return
}
if conference.id == strongSelf.conferenceId { if conference.id == strongSelf.conferenceId {
strongSelf.pollOnceDelayed() if let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: localBundleId, bridgeHost: strongSelf.colibriHost, transport: localTransport, currentState: strongSelf.currentOfferState, isAnswer: true) {
//strongSelf.currentOfferState = offer.state
strongSelf.memberCount.set(offer.state.items.filter({ !$0.isRemoved }).count)
for sdp in offer.sdpList {
strongSelf.context.setOfferSdp(sdp, isPartial: true)
}
}
strongSelf.queue.after(2.0, {
self?.pollOnceDelayed()
})
} }
})) }))
})) }))
@ -1597,17 +1696,138 @@ public final class GroupCallContext {
return return
} }
if let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: localBundleId, bridgeHost: strongSelf.colibriHost, transport: localTransport, currentState: strongSelf.currentOfferState) { if let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: localBundleId, bridgeHost: strongSelf.colibriHost, transport: localTransport, currentState: strongSelf.currentOfferState, isAnswer: false) {
strongSelf.currentOfferState = offer.state strongSelf.currentOfferState = offer.state
let queue = strongSelf.queue
strongSelf.memberCount.set(offer.state.items.filter({ !$0.isRemoved }).count) strongSelf.memberCount.set(offer.state.items.filter({ !$0.isRemoved }).count)
for sdp in offer.sdpList { for sdp in offer.sdpList {
strongSelf.context.setOfferSdp(sdp, isPartial: false) strongSelf.context.setOfferSdp(sdp, isPartial: false)
} }
strongSelf.pollOnceDelayed()
/*strongSelf.context.emitOffer(adjustSdp: { sdp in
var resultLines: [String] = []
func appendSdp(_ line: String) {
resultLines.append(line)
}
var sharedPort = "0"
let lines = sdp.components(separatedBy: "\n")
for line in lines {
var cleanLine = line
if cleanLine.hasSuffix("\r") {
cleanLine.removeLast()
}
if cleanLine.isEmpty {
continue
}
if cleanLine.hasPrefix("a=group:BUNDLE 0 1") {
cleanLine = "a=group:BUNDLE 0 1"
for item in offer.state.items {
if item.isMain {
continue
}
cleanLine.append(" audio\(item.audioSsrc) video\(item.videoSsrc)")
}
} else if cleanLine.hasPrefix("m=audio ") {
let scanner = Scanner(string: cleanLine)
if #available(iOS 13.0, *) {
if let _ = scanner.scanString("m=audio "), let value = scanner.scanInt() {
sharedPort = "\(value)"
}
}
}
appendSdp(cleanLine)
}
for item in offer.state.items {
if item.isMain {
continue
}
let audioSsrc = item.audioSsrc
let videoSsrc = item.videoSsrc
appendSdp("m=audio \(sharedPort) RTP/SAVPF 111 126")
appendSdp("a=mid:audio\(audioSsrc)")
appendSdp("a=rtpmap:111 opus/48000/2")
appendSdp("a=rtpmap:126 telephone-event/8000")
appendSdp("a=fmtp:111 minptime=10; useinbandfec=1; usedtx=1")
appendSdp("a=rtcp:1 IN IP4 0.0.0.0")
appendSdp("a=rtcp-mux")
appendSdp("a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level")
appendSdp("a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")
appendSdp("a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")
appendSdp("a=rtcp-fb:111 transport-cc")
appendSdp("a=recvonly")
appendSdp("a=bundle-only")
appendSdp("a=ssrc-group:FID \(audioSsrc)")
appendSdp("a=ssrc:\(audioSsrc) cname:stream\(audioSsrc)")
appendSdp("a=ssrc:\(audioSsrc) msid:stream\(audioSsrc) audio\(audioSsrc)")
appendSdp("a=ssrc:\(audioSsrc) mslabel:audio\(audioSsrc)")
appendSdp("a=ssrc:\(audioSsrc) label:audio\(audioSsrc)")
appendSdp("m=video \(sharedPort) RTP/SAVPF 100")
appendSdp("a=mid:video\(videoSsrc)")
appendSdp("a=rtpmap:100 VP8/90000")
appendSdp("a=fmtp:100 x-google-start-bitrate=800")
appendSdp("a=rtcp:1 IN IP4 0.0.0.0")
appendSdp("a=rtcp-mux")
appendSdp("a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")
appendSdp("a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")
appendSdp("a=rtcp-fb:100 transport-cc")
appendSdp("a=rtcp-fb:100 ccm fir")
appendSdp("a=rtcp-fb:100 nack")
appendSdp("a=rtcp-fb:100 nack pli")
appendSdp("a=recvonly")
appendSdp("a=bundle-only")
appendSdp("a=ssrc-group:FID \(videoSsrc)")
appendSdp("a=ssrc:\(videoSsrc) cname:stream\(audioSsrc)")
appendSdp("a=ssrc:\(videoSsrc) msid:stream\(audioSsrc) video\(videoSsrc)")
appendSdp("a=ssrc:\(videoSsrc) mslabel:video\(videoSsrc)")
appendSdp("a=ssrc:\(videoSsrc) label:video\(videoSsrc)")
}
let resultSdp = resultLines.joined(separator: "\n")
print("------ modified local sdp ------")
print(resultSdp)
print("------")
return resultSdp
}, completion: { _ in
queue.async {
guard let strongSelf = self else {
return
}
strongSelf.memberCount.set(offer.state.items.filter({ !$0.isRemoved }).count)
for sdp in offer.sdpList {
print("===== setOffer polled =====")
print(sdp)
print("===== -------------- =====")
strongSelf.context.setOfferSdp(sdp, isPartial: false)
}
strongSelf.pollOnceDelayed()
}
})*/
} }
strongSelf.pollOnceDelayed()
})) }))
} }

View File

@ -156,7 +156,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue relaySdpAnswer:(void (^ _Nonnull)(NSString * _Nonnull))relaySdpAnswer incomingVideoStreamListUpdated:(void (^ _Nonnull)(NSArray<NSString *> * _Nonnull))incomingVideoStreamListUpdated videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer; - (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue relaySdpAnswer:(void (^ _Nonnull)(NSString * _Nonnull))relaySdpAnswer incomingVideoStreamListUpdated:(void (^ _Nonnull)(NSArray<NSString *> * _Nonnull))incomingVideoStreamListUpdated videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer;
- (void)emitOffer; - (void)emitOfferWithAdjustSdp:(NSString * _Nonnull (^ _Nonnull)(NSString * _Nonnull))adjustSdp completion:(void (^ _Nonnull)(NSString * _Nonnull))completion;
- (void)setOfferSdp:(NSString * _Nonnull)offerSdp isPartial:(bool)isPartial; - (void)setOfferSdp:(NSString * _Nonnull)offerSdp isPartial:(bool)isPartial;
- (void)setIsMuted:(bool)isMuted; - (void)setIsMuted:(bool)isMuted;
- (void)makeIncomingVideoViewWithStreamId:(NSString * _Nonnull)streamId completion:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion; - (void)makeIncomingVideoViewWithStreamId:(NSString * _Nonnull)streamId completion:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion;

View File

@ -844,9 +844,16 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
return self; return self;
} }
- (void)emitOffer { - (void)emitOfferWithAdjustSdp:(NSString * _Nonnull (^ _Nonnull)(NSString * _Nonnull))adjustSdp completion:(void (^ _Nonnull)(NSString * _Nonnull))completion {
if (_instance) { if (_instance) {
_instance->emitOffer(); _instance->emitOffer([adjustSdp](std::string const &sdp) {
NSString *string = [NSString stringWithUTF8String:sdp.c_str()];
NSString *result = adjustSdp(string);
return result.UTF8String;
}, [completion](std::string const &sdp) {
NSString *string = [NSString stringWithUTF8String:sdp.c_str()];
completion(string);
});
} }
} }

@ -1 +1 @@
Subproject commit 76de07f885c43ea2b5275c050c00a6a7296f1444 Subproject commit 5b60ad7708d0a5d29bc0857fbabc91514a07f252