Broadcasts updates

This commit is contained in:
Ali 2021-03-09 02:34:34 +04:00
parent dc038797b6
commit bc472b2126
8 changed files with 149 additions and 79 deletions

View File

@ -587,9 +587,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
if let strongSelf = self {
if value {
if let audioSessionControl = strongSelf.audioSessionControl {
let audioSessionActive: Signal<Bool, NoError>
//let audioSessionActive: Signal<Bool, NoError>
if let callKitIntegration = strongSelf.callKitIntegration {
audioSessionActive = callKitIntegration.audioSessionActive
_ = callKitIntegration.audioSessionActive
|> filter { $0 }
|> timeout(2.0, queue: Queue.mainQueue(), alternate: Signal { subscriber in
if let strongSelf = self, let _ = strongSelf.audioSessionControl {
@ -777,11 +777,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
}
let temporaryParticipantsContext = GroupCallParticipantsContext(account: self.account, peerId: self.peerId, myPeerId: myPeerId, id: sourceContext.id, accessHash: sourceContext.accessHash, state: initialState)
self.temporaryParticipantsContext = temporaryParticipantsContext
self.participantsContextStateDisposable.set(combineLatest(queue: .mainQueue(),
self.participantsContextStateDisposable.set((combineLatest(queue: .mainQueue(),
myPeer,
temporaryParticipantsContext.state,
temporaryParticipantsContext.activeSpeakers
).start(next: { [weak self] myPeerAndCachedData, state, activeSpeakers in
)
|> take(1)).start(next: { [weak self] myPeerAndCachedData, state, activeSpeakers in
guard let strongSelf = self else {
return
}
@ -853,7 +854,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
strongSelf.membersValue = members
strongSelf.stateValue.adminIds = state.adminIds
var stateValue = strongSelf.stateValue
stateValue.myPeerId = strongSelf.joinAsPeerId
stateValue.adminIds = state.adminIds
strongSelf.stateValue = stateValue
strongSelf.summaryParticipantsState.set(.single(SummaryParticipantsState(
participantCount: state.totalCount,
@ -911,13 +916,13 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
}
strongSelf.maybeRequestParticipants(ssrcs: ssrcs)
}
}, audioStreamData: OngoingGroupCallContext.AudioStreamData(account: self.accountContext.account, callId: callInfo.id, accessHash: callInfo.accessHash, datacenterId: callInfo.streamDcId.flatMap(Int.init)), rejoinNeeded: { [weak self] in
}, audioStreamData: OngoingGroupCallContext.AudioStreamData(account: self.accountContext.account, callId: callInfo.id, accessHash: callInfo.accessHash), rejoinNeeded: { [weak self] in
Queue.mainQueue().async {
guard let strongSelf = self else {
return
}
if case .established = strongSelf.internalState {
//strongSelf.requestCall()
strongSelf.requestCall()
}
}
})
@ -1478,10 +1483,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
let previousPeerId = strongSelf.joinAsPeerId
strongSelf.joinAsPeerId = peerId
strongSelf.stateValue.myPeerId = peerId
if let participantsContext = strongSelf.participantsContext, let immediateState = participantsContext.immediateState {
strongSelf.switchToTemporaryParticipantsContext(sourceContext: participantsContext, initialState: immediateState, oldMyPeerId: previousPeerId)
} else {
strongSelf.stateValue.myPeerId = peerId
}
strongSelf.requestCall()

View File

@ -325,7 +325,57 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
}
}
func rawRequest(_ data: (FunctionDescription, Buffer, (Buffer) -> Any?), automaticFloodWait: Bool = true) -> Signal<(Any, Double), (MTRpcError, Double)> {
func requestWithAdditionalData<T>(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse<T>), automaticFloodWait: Bool = true, failOnServerErrors: Bool = false) -> Signal<(T, Double), (MTRpcError, Double)> {
return Signal { subscriber in
let request = MTRequest()
request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(data.0)), responseParser: { response in
if let result = data.2.parse(Buffer(data: response)) {
return BoxedMessage(result)
}
return nil
})
request.dependsOnPasswordEntry = false
request.shouldContinueExecutionWithErrorContext = { errorContext in
guard let errorContext = errorContext else {
return true
}
if errorContext.floodWaitSeconds > 0 && !automaticFloodWait {
return false
}
if errorContext.internalServerErrorCount > 0 && failOnServerErrors {
return false
}
return true
}
request.completed = { (boxedResponse, timestamp, error) -> () in
if let error = error {
subscriber.putError((error, timestamp))
} else {
if let result = (boxedResponse as! BoxedMessage).body as? T {
subscriber.putNext((result, timestamp))
subscriber.putCompletion()
}
else {
subscriber.putError((MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR"), timestamp))
}
}
}
let internalId: Any! = request.internalId
self.requestService.add(request)
return ActionDisposable {
self.requestService.removeRequest(byInternalId: internalId)
}
}
}
func rawRequest(_ data: (FunctionDescription, Buffer, (Buffer) -> Any?), automaticFloodWait: Bool = true, failOnServerErrors: Bool = false) -> Signal<(Any, Double), (MTRpcError, Double)> {
let requestService = self.requestService
return Signal { subscriber in
let request = MTRequest()
@ -346,6 +396,9 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
if errorContext.floodWaitSeconds > 0 && !automaticFloodWait {
return false
}
if errorContext.internalServerErrorCount > 0 && failOnServerErrors {
return false
}
return true
}

View File

@ -516,7 +516,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal
state.adminIds = adminIds
switch result {
case let .groupCall(call, participants, _, chats, users):
case let .groupCall(call, _, _, chats, users):
guard let _ = GroupCallInfo(call) else {
return .fail(.generic)
}
@ -821,7 +821,7 @@ public final class GroupCallParticipantsContext {
for i in 0 ..< self.participants.count {
if let index = indexMap[self.participants[i].peer.id] {
self.participants[i].mergeActivity(from: other.participants[i])
self.participants[i].mergeActivity(from: other.participants[index])
}
}
@ -1900,19 +1900,34 @@ private func mergeAndSortParticipants(current currentParticipants: [GroupCallPar
return mergedParticipants
}
public func getAudioBroadcastDatacenter(account: Account, callId: Int64, accessHash: Int64) -> Signal<Int?, NoError> {
public final class AudioBroadcastDataSource {
fileprivate let download: Download
fileprivate init(download: Download) {
self.download = download
}
}
public func getAudioBroadcastDataSource(account: Account, callId: Int64, accessHash: Int64) -> Signal<AudioBroadcastDataSource?, NoError> {
return account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.phone.GroupCall?, NoError> in
return .single(nil)
}
|> map { result -> Int? in
|> mapToSignal { result -> Signal<AudioBroadcastDataSource?, NoError> in
guard let result = result else {
return nil
return .single(nil)
}
switch result {
case let .groupCall(call, _, _, _, _):
return GroupCallInfo(call)?.streamDcId.flatMap(Int.init)
if let datacenterId = GroupCallInfo(call)?.streamDcId.flatMap(Int.init) {
return account.network.download(datacenterId: datacenterId, isMedia: true, tag: nil)
|> map { download -> AudioBroadcastDataSource? in
return AudioBroadcastDataSource(download: download)
}
} else {
return .single(nil)
}
}
}
}
@ -1921,7 +1936,7 @@ public struct GetAudioBroadcastPartResult {
public enum Status {
case data(Data)
case notReady
case tooOld
case resyncNeeded
case rejoinNeeded
}
@ -1929,8 +1944,18 @@ public struct GetAudioBroadcastPartResult {
public var responseTimestamp: Double
}
public func getAudioBroadcastPart(account: Account, callId: Int64, accessHash: Int64, datacenterId: Int, timestampId: Int32) -> Signal<GetAudioBroadcastPartResult, NoError> {
return account.network.multiplexedRequestManager.requestWithAdditionalInfo(to: .main(datacenterId), consumerId: Int64.random(in: 0 ..< Int64.max), data: Api.functions.upload.getFile(flags: 0, location: .inputGroupCallStream(call: .inputGroupCall(id: callId, accessHash: accessHash), timeMs: Int64(timestampId) * 1000, scale: 0), offset: 0, limit: 128 * 1024), tag: nil, continueInBackground: false, automaticFloodWait: false)
public func getAudioBroadcastPart(dataSource: AudioBroadcastDataSource, callId: Int64, accessHash: Int64, timestampIdMilliseconds: Int64, durationMilliseconds: Int64) -> Signal<GetAudioBroadcastPartResult, NoError> {
let scale: Int32
switch durationMilliseconds {
case 1000:
scale = 0
case 500:
scale = 1
default:
return .single(GetAudioBroadcastPartResult(status: .notReady, responseTimestamp: Double(timestampIdMilliseconds) / 1000.0))
}
return dataSource.download.requestWithAdditionalData(Api.functions.upload.getFile(flags: 0, location: .inputGroupCallStream(call: .inputGroupCall(id: callId, accessHash: accessHash), timeMs: timestampIdMilliseconds, scale: scale), offset: 0, limit: 128 * 1024), automaticFloodWait: false, failOnServerErrors: true)
|> map { result, responseTimestamp -> GetAudioBroadcastPartResult in
switch result {
case let .file(_, _, bytes):
@ -1956,14 +1981,14 @@ public func getAudioBroadcastPart(account: Account, callId: Int64, accessHash: I
status: .notReady,
responseTimestamp: responseTimestamp
))
} else if error.errorDescription == "DATE_INVALID" {
} else if error.errorDescription == "TIME_INVALID" || error.errorDescription == "TIME_TOO_SMALL" || error.errorDescription == "TIME_TOO_BIG" {
return .single(GetAudioBroadcastPartResult(
status: .tooOld,
status: .resyncNeeded,
responseTimestamp: responseTimestamp
))
} else {
return .single(GetAudioBroadcastPartResult(
status: .notReady,
status: .resyncNeeded,
responseTimestamp: responseTimestamp
))
}

View File

@ -14,9 +14,6 @@ swift_library(
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/TgVoip:TgVoip",
"//submodules/TgVoipWebrtc:TgVoipWebrtc",
"//submodules/MediaPlayer:UniversalMediaPlayer",
"//submodules/AppBundle:AppBundle",
"//submodules/OpusBinding:OpusBinding",
],
visibility = [
"//visibility:public",

View File

@ -1,9 +1,6 @@
import Foundation
import SwiftSignalKit
import TgVoipWebrtc
//import UniversalMediaPlayer
//import AppBundle
import OpusBinding
import Postbox
import TelegramCore
@ -32,7 +29,7 @@ private final class ContextQueueImpl: NSObject, OngoingCallThreadLocalContextQue
}
private protocol BroadcastPartSource: class {
func requestPart(timestamp: Int32, completion: @escaping (OngoingGroupCallBroadcastPart) -> Void, rejoinNeeded: @escaping () -> Void) -> Disposable
func requestPart(timestampMilliseconds: Int64, durationMilliseconds: Int64, completion: @escaping (OngoingGroupCallBroadcastPart) -> Void, rejoinNeeded: @escaping () -> Void) -> Disposable
}
private final class NetworkBroadcastPartSource: BroadcastPartSource {
@ -40,29 +37,28 @@ private final class NetworkBroadcastPartSource: BroadcastPartSource {
private let account: Account
private let callId: Int64
private let accessHash: Int64
private var datacenterId: Int?
private var dataSource: AudioBroadcastDataSource?
private let dumpDir: TempBoxDirectory
init(queue: Queue, account: Account, callId: Int64, accessHash: Int64, datacenterId: Int?) {
init(queue: Queue, account: Account, callId: Int64, accessHash: Int64) {
self.queue = queue
self.account = account
self.callId = callId
self.accessHash = accessHash
self.datacenterId = datacenterId
self.dumpDir = TempBox.shared.tempDirectory()
print("dumpDir = \(self.dumpDir.path)")
}
func requestPart(timestamp: Int32, completion: @escaping (OngoingGroupCallBroadcastPart) -> Void, rejoinNeeded: @escaping () -> Void) -> Disposable {
let timestampId = timestamp == 0 ? Int32(Date().timeIntervalSince1970) : timestamp
let datacenterId: Signal<Int?, NoError>
if let datacenterIdValue = self.datacenterId {
datacenterId = .single(datacenterIdValue)
func requestPart(timestampMilliseconds: Int64, durationMilliseconds: Int64, completion: @escaping (OngoingGroupCallBroadcastPart) -> Void, rejoinNeeded: @escaping () -> Void) -> Disposable {
let timestampIdMilliseconds: Int64
if timestampMilliseconds != 0 {
timestampIdMilliseconds = timestampMilliseconds
} else {
datacenterId = getAudioBroadcastDatacenter(account: self.account, callId: self.callId, accessHash: self.accessHash)
timestampIdMilliseconds = (Int64(Date().timeIntervalSince1970 * 1000.0) / durationMilliseconds) * durationMilliseconds
}
let dataSource: Signal<AudioBroadcastDataSource?, NoError>
if let dataSourceValue = self.dataSource {
dataSource = .single(dataSourceValue)
} else {
dataSource = getAudioBroadcastDataSource(account: self.account, callId: self.callId, accessHash: self.accessHash)
}
let account = self.account
@ -70,12 +66,12 @@ private final class NetworkBroadcastPartSource: BroadcastPartSource {
let accessHash = self.accessHash
let queue = self.queue
let signal = datacenterId
let signal = dataSource
|> deliverOn(self.queue)
|> mapToSignal { [weak self] datacenterId -> Signal<GetAudioBroadcastPartResult?, NoError> in
if let datacenterId = datacenterId {
self?.datacenterId = datacenterId
return getAudioBroadcastPart(account: account, callId: callId, accessHash: accessHash, datacenterId: datacenterId, timestampId: timestampId)
|> mapToSignal { [weak self] dataSource -> Signal<GetAudioBroadcastPartResult?, NoError> in
if let dataSource = dataSource {
self?.dataSource = dataSource
return getAudioBroadcastPart(dataSource: dataSource, callId: callId, accessHash: accessHash, timestampIdMilliseconds: timestampIdMilliseconds, durationMilliseconds: durationMilliseconds)
|> map(Optional.init)
} else {
return .single(nil)
@ -83,25 +79,20 @@ private final class NetworkBroadcastPartSource: BroadcastPartSource {
}
}
|> deliverOn(self.queue)
let dumpDir = self.dumpDir
return signal.start(next: { result in
guard let result = result else {
completion(OngoingGroupCallBroadcastPart(timestamp: timestampId, responseTimestamp: Double(timestampId), status: .notReady, oggData: Data()))
completion(OngoingGroupCallBroadcastPart(timestampMilliseconds: timestampIdMilliseconds, responseTimestamp: Double(timestampIdMilliseconds), status: .notReady, oggData: Data()))
return
}
let part: OngoingGroupCallBroadcastPart
switch result.status {
case let .data(dataValue):
let filePath = dumpDir.path + "/\(timestampId).ogg"
let _ = try? dataValue.write(to: URL(fileURLWithPath: filePath))
part = OngoingGroupCallBroadcastPart(timestamp: timestampId, responseTimestamp: result.responseTimestamp, status: .success, oggData: dataValue)
part = OngoingGroupCallBroadcastPart(timestampMilliseconds: timestampIdMilliseconds, responseTimestamp: result.responseTimestamp, status: .success, oggData: dataValue)
case .notReady:
part = OngoingGroupCallBroadcastPart(timestamp: timestampId, responseTimestamp: result.responseTimestamp, status: .notReady, oggData: Data())
case .tooOld:
part = OngoingGroupCallBroadcastPart(timestamp: timestampId, responseTimestamp: result.responseTimestamp, status: .tooOld, oggData: Data())
part = OngoingGroupCallBroadcastPart(timestampMilliseconds: timestampIdMilliseconds, responseTimestamp: result.responseTimestamp, status: .notReady, oggData: Data())
case .resyncNeeded:
part = OngoingGroupCallBroadcastPart(timestampMilliseconds: timestampIdMilliseconds, responseTimestamp: result.responseTimestamp, status: .resyncNeeded, oggData: Data())
case .rejoinNeeded:
rejoinNeeded()
return
@ -129,13 +120,11 @@ public final class OngoingGroupCallContext {
public var account: Account
public var callId: Int64
public var accessHash: Int64
public var datacenterId: Int?
public init(account: Account, callId: Int64, accessHash: Int64, datacenterId: Int?) {
public init(account: Account, callId: Int64, accessHash: Int64) {
self.account = account
self.callId = callId
self.accessHash = accessHash
self.datacenterId = datacenterId
}
}
@ -177,7 +166,7 @@ public final class OngoingGroupCallContext {
var audioLevelsUpdatedImpl: (([NSNumber]) -> Void)?
if let audioStreamData = audioStreamData {
let broadcastPartsSource = NetworkBroadcastPartSource(queue: queue, account: audioStreamData.account, callId: audioStreamData.callId, accessHash: audioStreamData.accessHash, datacenterId: audioStreamData.datacenterId)
let broadcastPartsSource = NetworkBroadcastPartSource(queue: queue, account: audioStreamData.account, callId: audioStreamData.callId, accessHash: audioStreamData.accessHash)
self.broadcastPartsSource = broadcastPartsSource
}
@ -201,11 +190,11 @@ public final class OngoingGroupCallContext {
participantDescriptionsRequired: { ssrcs in
participantDescriptionsRequired(Set(ssrcs.map { $0.uint32Value }))
},
requestBroadcastPart: { timestamp, completion in
requestBroadcastPart: { timestampMilliseconds, durationMilliseconds, completion in
let disposable = MetaDisposable()
queue.async {
disposable.set(broadcastPartsSource?.requestPart(timestamp: timestamp, completion: completion, rejoinNeeded: {
disposable.set(broadcastPartsSource?.requestPart(timestampMilliseconds: timestampMilliseconds, durationMilliseconds: durationMilliseconds, completion: completion, rejoinNeeded: {
rejoinNeeded()
}))
}

View File

@ -180,23 +180,23 @@ typedef NS_ENUM(int32_t, OngoingCallConnectionMode) {
typedef NS_ENUM(int32_t, OngoingGroupCallBroadcastPartStatus) {
OngoingGroupCallBroadcastPartStatusSuccess,
OngoingGroupCallBroadcastPartStatusNotReady,
OngoingGroupCallBroadcastPartStatusTooOld
OngoingGroupCallBroadcastPartStatusResyncNeeded
};
@interface OngoingGroupCallBroadcastPart : NSObject
@property (nonatomic, readonly) int32_t timestamp;
@property (nonatomic, readonly) int64_t timestampMilliseconds;
@property (nonatomic, readonly) double responseTimestamp;
@property (nonatomic, readonly) OngoingGroupCallBroadcastPartStatus status;
@property (nonatomic, strong, readonly) NSData * _Nonnull oggData;
- (instancetype _Nonnull)initWithTimestamp:(int32_t)timestamp responseTimestamp:(double)responseTimestamp status:(OngoingGroupCallBroadcastPartStatus)status oggData:(NSData * _Nonnull)oggData;
- (instancetype _Nonnull)initWithTimestampMilliseconds:(int64_t)timestampMilliseconds responseTimestamp:(double)responseTimestamp status:(OngoingGroupCallBroadcastPartStatus)status oggData:(NSData * _Nonnull)oggData;
@end
@interface GroupCallThreadLocalContext : NSObject
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id<OngoingGroupCallBroadcastPartTask> _Nonnull (^ _Nonnull)(int32_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart;
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id<OngoingGroupCallBroadcastPartTask> _Nonnull (^ _Nonnull)(int64_t, int64_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart;
- (void)stop;

View File

@ -426,8 +426,8 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
.enableNS = true,
.enableAGC = true,
.enableCallUpgrade = false,
.logPath = logPath.length == 0 ? "" : std::string(logPath.UTF8String),
.statsLogPath = statsLogPath.length == 0 ? "" : std::string(statsLogPath.UTF8String),
.logPath = std::string(logPath.length == 0 ? "" : logPath.UTF8String),
.statsLogPath = std::string(statsLogPath.length == 0 ? "" : statsLogPath.UTF8String),
.maxApiLayer = [OngoingCallThreadLocalContextWebrtc maxLayer],
.enableHighBitrateVideo = true,
.preferredVideoCodecs = preferredVideoCodecs,
@ -853,7 +853,7 @@ private:
@implementation GroupCallThreadLocalContext
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id<OngoingGroupCallBroadcastPartTask> _Nonnull (^ _Nonnull)(int32_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart {
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray<NSNumber *> * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id<OngoingGroupCallBroadcastPartTask> _Nonnull (^ _Nonnull)(int64_t, int64_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart {
self = [super init];
if (self != nil) {
_queue = queue;
@ -898,10 +898,10 @@ private:
}
participantDescriptionsRequired(mappedSources);
},
.requestBroadcastPart = [requestBroadcastPart](int32_t timestamp, std::function<void(tgcalls::BroadcastPart &&)> completion) -> std::shared_ptr<tgcalls::BroadcastPartTask> {
id<OngoingGroupCallBroadcastPartTask> task = requestBroadcastPart(timestamp, ^(OngoingGroupCallBroadcastPart * _Nullable part) {
.requestBroadcastPart = [requestBroadcastPart](int64_t timestampMilliseconds, int64_t durationMilliseconds, std::function<void(tgcalls::BroadcastPart &&)> completion) -> std::shared_ptr<tgcalls::BroadcastPartTask> {
id<OngoingGroupCallBroadcastPartTask> task = requestBroadcastPart(timestampMilliseconds, durationMilliseconds, ^(OngoingGroupCallBroadcastPart * _Nullable part) {
tgcalls::BroadcastPart parsedPart;
parsedPart.timestamp = part.timestamp;
parsedPart.timestampMilliseconds = part.timestampMilliseconds;
parsedPart.responseTimestamp = part.responseTimestamp;
@ -915,8 +915,8 @@ private:
mappedStatus = tgcalls::BroadcastPart::Status::NotReady;
break;
}
case OngoingGroupCallBroadcastPartStatusTooOld: {
mappedStatus = tgcalls::BroadcastPart::Status::TooOld;
case OngoingGroupCallBroadcastPartStatusResyncNeeded: {
mappedStatus = tgcalls::BroadcastPart::Status::ResyncNeeded;
break;
}
default: {
@ -1495,10 +1495,10 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn
@implementation OngoingGroupCallBroadcastPart
- (instancetype _Nonnull)initWithTimestamp:(int32_t)timestamp responseTimestamp:(double)responseTimestamp status:(OngoingGroupCallBroadcastPartStatus)status oggData:(NSData * _Nonnull)oggData {
- (instancetype _Nonnull)initWithTimestampMilliseconds:(int64_t)timestampMilliseconds responseTimestamp:(double)responseTimestamp status:(OngoingGroupCallBroadcastPartStatus)status oggData:(NSData * _Nonnull)oggData {
self = [super init];
if (self != nil) {
_timestamp = timestamp;
_timestampMilliseconds = timestampMilliseconds;
_responseTimestamp = responseTimestamp;
_status = status;
_oggData = oggData;

@ -1 +1 @@
Subproject commit 43bd0ee8b629939e5bc05eae34b0f17e3263b3b3
Subproject commit 18ed939bf6818139f7147cde1c34cf22eb5080a2