mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
WIP
This commit is contained in:
parent
8081430ad2
commit
1f41873ff2
@ -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: {
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user