This commit is contained in:
Ali 2020-11-09 14:41:27 +04:00
parent 518480564c
commit ec6a8877f5
7 changed files with 195 additions and 20 deletions

View File

@ -251,9 +251,9 @@ official_bundle_ids = [
"org.telegram.Telegram-iOS",
]
apple_pay_merchants = []#official_apple_pay_merchants if telegram_bundle_id == "ph.telegra.Telegraph" else ""
apple_pay_merchants = official_apple_pay_merchants if telegram_bundle_id == "ph.telegra.Telegraph" else []
apple_pay_merchants_fragment = "" if apple_pay_merchants == "" else """
apple_pay_merchants_fragment = "" if apple_pay_merchants == [] else """
<key>com.apple.developer.in-app-payments</key>
<array>
""" + "\n".join([
@ -1528,13 +1528,13 @@ ios_application(
":AppStringResources",
],
extensions = [
#":ShareExtension",
#":NotificationContentExtension",
#":NotificationServiceExtension",
#":IntentsExtension",
#":WidgetExtension",
":ShareExtension",
":NotificationContentExtension",
":NotificationServiceExtension",
":IntentsExtension",
":WidgetExtension",
],
#watch_application = ":TelegramWatchApp",
watch_application = ":TelegramWatchApp",
deps = [
":Main",
":Lib",

View File

@ -1 +1 @@
12.0.1
12.1

View File

@ -21,6 +21,9 @@ public final class GroupCallController: ViewController {
private var isMutedDisposable: Disposable?
private let audioSessionActive = Promise<Bool>(false)
private var incomingVideoStreamList: [String] = []
private var incomingVideoStreamListDisposable: Disposable?
private var memberCount: Int = 0
private let memberCountNode: ImmediateTextNode
@ -28,6 +31,8 @@ public final class GroupCallController: ViewController {
private let isMutedNode: ImmediateTextNode
private let muteButton: HighlightableButtonNode
private var videoViews: [OngoingCallContextPresentationCallVideoView] = []
private var validLayout: ContainerViewLayout?
init(context: AccountContext) {
@ -77,6 +82,34 @@ public final class GroupCallController: ViewController {
}
})
self.incomingVideoStreamListDisposable = (callContext.videoStreamList
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
}
var addedStreamIds: [String] = []
for id in value {
if !strongSelf.incomingVideoStreamList.contains(id) {
addedStreamIds.append(id)
}
}
strongSelf.incomingVideoStreamList = value
for id in addedStreamIds {
callContext.makeIncomingVideoView(id: id, completion: { videoView in
guard let strongSelf = self, let videoView = videoView else {
return
}
strongSelf.videoViews.append(videoView)
videoView.view.backgroundColor = .black
strongSelf.view.addSubview(videoView.view)
if let layout = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
}
})
}
})
self.isMutedDisposable = (callContext.isMuted
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
@ -94,6 +127,7 @@ public final class GroupCallController: ViewController {
deinit {
self.callDisposable?.dispose()
self.memberCountDisposable?.dispose()
self.incomingVideoStreamListDisposable?.dispose()
}
@objc private func muteButtonPressed() {
@ -116,6 +150,17 @@ public final class GroupCallController: ViewController {
let isMutedFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - isMutedSize.width) / 2.0), y: textFrame.maxY + 12.0), size: isMutedSize)
transition.updateFrame(node: self.muteButton, frame: isMutedFrame)
self.isMutedNode.frame = CGRect(origin: CGPoint(), size: isMutedFrame.size)
let videoSize = CGSize(width: 200.0, height: 360.0)
var nextVideoOrigin = CGPoint()
for videoView in self.videoViews {
videoView.view.frame = CGRect(origin: nextVideoOrigin, size: videoSize)
nextVideoOrigin.x += videoSize.width
if nextVideoOrigin.x + videoSize.width > layout.size.width {
nextVideoOrigin.x = 0.0
nextVideoOrigin.y += videoSize.height
}
}
}
}

View File

@ -501,9 +501,15 @@ private extension ConferenceDescription.Content.Channel.PayloadType {
[
"type": "transport-cc"
] as [String: Any],
/*[
[
"type": "ccm fir"
] as [String: Any],
[
"type": "nack"
] as [String: Any]*/
] as [String: Any],
[
"type": "nack pli"
] as [String: Any],
] as [Any]
if let parameters = self.parameters {
result["parameters"] = parameters
@ -782,7 +788,7 @@ private extension ConferenceDescription {
appendSdp("a=ssrc:\(stream.audioSsrc) label:audio\(stream.audioSsrc)")
}
appendSdp("m=video \(stream.isMain ? "1" : "0") RTP/SAVPF 100")
appendSdp("m=video 0 RTP/SAVPF 100")
appendSdp("a=mid:video\(stream.videoSsrc)")
if stream.isRemoved {
appendSdp("a=inactive")
@ -809,6 +815,11 @@ private extension ConferenceDescription {
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)")
@ -1026,9 +1037,6 @@ private extension ConferenceDescription {
[
"type": "transport-cc"
] as [String: Any],
/*[
"type": "nack"
] as [String: Any]*/
] as [Any]
]
),
@ -1075,9 +1083,15 @@ private extension ConferenceDescription {
[
"type": "transport-cc"
] as [String: Any],
[
"type": "ccm fir"
] as [String: Any],
[
"type": "nack"
] as [String: Any]
] as [String: Any],
[
"type": "nack pli"
] as [String: Any],
] as [Any]
]
)
@ -1263,6 +1277,7 @@ public final class GroupCallContext {
private var localTransport: ConferenceDescription.Transport?
let memberCount = ValuePromise<Int>(0, ignoreRepeated: true)
let videoStreamList = ValuePromise<[String]>([], ignoreRepeated: true)
private var isMutedValue: Bool = false
let isMuted = ValuePromise<Bool>(false, ignoreRepeated: true)
@ -1271,14 +1286,20 @@ public final class GroupCallContext {
self.queue = queue
self.sessionId = UInt32.random(in: 0 ..< UInt32(Int32.max))
self.colibriHost = "192.168.8.118"
self.colibriHost = "192.168.93.24"
var relaySdpAnswerImpl: ((String) -> Void)?
let videoStreamList = self.videoStreamList
self.context = GroupCallThreadLocalContext(queue: ContextQueueImpl(queue: queue), relaySdpAnswer: { sdpAnswer in
queue.async {
relaySdpAnswerImpl?(sdpAnswer)
}
}, incomingVideoStreamListUpdated: { streamList in
queue.async {
videoStreamList.set(streamList)
}
}, videoCapturer: video?.impl)
relaySdpAnswerImpl = { [weak self] sdpAnswer in
@ -1595,6 +1616,45 @@ public final class GroupCallContext {
self.isMuted.set(self.isMutedValue)
self.context.setIsMuted(self.isMutedValue)
}
func makeIncomingVideoView(id: String, completion: @escaping (OngoingCallContextPresentationCallVideoView?) -> Void) {
self.context.makeIncomingVideoView(withStreamId: id, completion: { view in
if let view = view {
completion(OngoingCallContextPresentationCallVideoView(
view: view,
setOnFirstFrameReceived: { [weak view] f in
view?.setOnFirstFrameReceived(f)
},
getOrientation: { [weak view] in
if let view = view {
return OngoingCallVideoOrientation(view.orientation)
} else {
return .rotation0
}
},
getAspect: { [weak view] in
if let view = view {
return view.aspect
} else {
return 0.0
}
},
setOnOrientationUpdated: { [weak view] f in
view?.setOnOrientationUpdated { value, aspect in
f?(OngoingCallVideoOrientation(value), aspect)
}
},
setOnIsMirroredUpdated: { [weak view] f in
view?.setOnIsMirroredUpdated { value in
f?(value)
}
}
))
} else {
completion(nil)
}
})
}
}
private let queue = Queue()
@ -1619,6 +1679,18 @@ public final class GroupCallContext {
}
}
public var videoStreamList: Signal<[String], NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.impl.with { impl in
disposable.set(impl.videoStreamList.get().start(next: { value in
subscriber.putNext(value)
}))
}
return disposable
}
}
public var isMuted: Signal<Bool, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
@ -1636,5 +1708,11 @@ public final class GroupCallContext {
impl.toggleIsMuted()
}
}
public func makeIncomingVideoView(id: String, completion: @escaping (OngoingCallContextPresentationCallVideoView?) -> Void) {
self.impl.with { impl in
impl.makeIncomingVideoView(id: id, completion: completion)
}
}
}

View File

@ -472,7 +472,7 @@ public enum OngoingCallVideoOrientation {
case rotation270
}
private extension OngoingCallVideoOrientation {
extension OngoingCallVideoOrientation {
init(_ orientation: OngoingCallVideoOrientationWebrtc) {
switch orientation {
case .orientation0:

View File

@ -154,11 +154,12 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
@interface GroupCallThreadLocalContext : NSObject
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue relaySdpAnswer:(void (^ _Nonnull)(NSString * _Nonnull))relaySdpAnswer 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)setOfferSdp:(NSString * _Nonnull)offerSdp isPartial:(bool)isPartial;
- (void)setIsMuted:(bool)isMuted;
- (void)makeIncomingVideoViewWithStreamId:(NSString * _Nonnull)streamId completion:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion;
@end

View File

@ -806,7 +806,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
@implementation GroupCallThreadLocalContext
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue relaySdpAnswer:(void (^ _Nonnull)(NSString * _Nonnull))relaySdpAnswer 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 {
self = [super init];
if (self != nil) {
_queue = queue;
@ -825,6 +825,19 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
relaySdpAnswer(string);
}];
},
.incomingVideoStreamListUpdated = [weakSelf, queue, incomingVideoStreamListUpdated](std::vector<std::string> const &incomingVideoStreamList) {
NSMutableArray<NSString *> *mappedList = [[NSMutableArray alloc] init];
for (auto &it : incomingVideoStreamList) {
[mappedList addObject:[NSString stringWithUTF8String:it.c_str()]];
}
[queue dispatch:^{
__strong GroupCallThreadLocalContext *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
incomingVideoStreamListUpdated(mappedList);
}];
},
.videoCapture = [_videoCapturer getInterface]
}));
}
@ -849,5 +862,43 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
}
}
- (void)makeIncomingVideoViewWithStreamId:(NSString * _Nonnull)streamId completion:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion {
if (_instance) {
__weak GroupCallThreadLocalContext *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if ([VideoMetalView isSupported]) {
VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectZero];
#if TARGET_OS_IPHONE
remoteRenderer.videoContentMode = UIViewContentModeScaleToFill;
#else
remoteRenderer.videoContentMode = UIViewContentModeScaleAspect;
#endif
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink = [remoteRenderer getSink];
__strong GroupCallThreadLocalContext *strongSelf = weakSelf;
if (strongSelf) {
//[remoteRenderer setOrientation:strongSelf->_remoteVideoOrientation];
//strongSelf->_currentRemoteVideoRenderer = remoteRenderer;
strongSelf->_instance->setIncomingVideoOutput([streamId UTF8String], sink);
}
completion(remoteRenderer);
} else {
GLVideoView *remoteRenderer = [[GLVideoView alloc] initWithFrame:CGRectZero];
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink = [remoteRenderer getSink];
__strong GroupCallThreadLocalContext *strongSelf = weakSelf;
if (strongSelf) {
//[remoteRenderer setOrientation:strongSelf->_remoteVideoOrientation];
//strongSelf->_currentRemoteVideoRenderer = remoteRenderer;
strongSelf->_instance->setIncomingVideoOutput([streamId UTF8String], sink);
}
completion(remoteRenderer);
}
});
}
}
@end