mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
WIP
This commit is contained in:
parent
518480564c
commit
ec6a8877f5
@ -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",
|
||||
|
@ -1 +1 @@
|
||||
12.0.1
|
||||
12.1
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,7 +472,7 @@ public enum OngoingCallVideoOrientation {
|
||||
case rotation270
|
||||
}
|
||||
|
||||
private extension OngoingCallVideoOrientation {
|
||||
extension OngoingCallVideoOrientation {
|
||||
init(_ orientation: OngoingCallVideoOrientationWebrtc) {
|
||||
switch orientation {
|
||||
case .orientation0:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user