diff --git a/Telegram/BUILD b/Telegram/BUILD index 56527eec83..8080e9225a 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -1746,6 +1746,7 @@ ios_extension( ":SwiftSignalKitFramework", ":PostboxFramework", ":TelegramCoreFramework", + ":TelegramUIFramework", ], ) diff --git a/Telegram/NotificationService/BUILD b/Telegram/NotificationService/BUILD index 5564908392..d49222329e 100644 --- a/Telegram/NotificationService/BUILD +++ b/Telegram/NotificationService/BUILD @@ -22,6 +22,7 @@ swift_library( "//submodules/GZip:GZip", "//submodules/PersistentStringHash:PersistentStringHash", "//submodules/Utils/RangeSet", + "//submodules/Media/ConvertOpusToAAC", ], visibility = [ diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index acaec01c00..e90e36c73e 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -16,6 +16,7 @@ import CallKit import AppLockState import NotificationsPresentationData import RangeSet +import ConvertOpusToAAC private let queue = Queue() @@ -1249,7 +1250,7 @@ private final class NotificationServiceHandler { if let stateManager = strongSelf.stateManager { let shouldKeepConnection = stateManager.network.shouldKeepConnection - let pollCompletion: (NotificationContent) -> Void = { content in + let pollCompletion: (NotificationContent, Media?) -> Void = { content, customMedia in var content = content queue.async { @@ -1259,6 +1260,8 @@ private final class NotificationServiceHandler { completed() return } + + let mediaAttachment = mediaAttachment ?? customMedia var fetchMediaSignal: Signal = .single(nil) if let mediaAttachment = mediaAttachment { @@ -1538,8 +1541,17 @@ private final class NotificationServiceHandler { if let mediaData = mediaData { stateManager.postbox.mediaBox.storeResourceData(file.resource.id, data: mediaData, synchronous: true) } - if let storedPath = stateManager.postbox.mediaBox.completedResourcePath(file.resource, pathExtension: "ogg") { - if let attachment = try? UNNotificationAttachment(identifier: "audio", url: URL(fileURLWithPath: storedPath), options: nil) { + if let storedPath = stateManager.postbox.mediaBox.completedResourcePath(file.resource, pathExtension: nil) { + let semaphore = DispatchSemaphore(value: 0) + let tempFile = TempBox.shared.tempFile(fileName: "audio.m4a") + let _ = (convertOpusToAAC(sourcePath: storedPath, allocateTempFile: { + return tempFile.path + }) + |> timeout(5.0, queue: .concurrentDefaultQueue(), alternate: .single(nil))).startStandalone(next: { _ in + semaphore.signal() + }) + semaphore.wait() + if let attachment = try? UNNotificationAttachment(identifier: "audio", url: URL(fileURLWithPath: tempFile.path), options: nil) { content.attachments.append(attachment) } } @@ -1601,9 +1613,9 @@ private final class NotificationServiceHandler { } } - let pollWithUpdatedContent: Signal + let pollWithUpdatedContent: Signal<(NotificationContent, Media?), NoError> if interactionAuthorId != nil || messageId != nil { - pollWithUpdatedContent = stateManager.postbox.transaction { transaction -> NotificationContent in + pollWithUpdatedContent = stateManager.postbox.transaction { transaction -> (NotificationContent, Media?) in var content = initialContent if let interactionAuthorId = interactionAuthorId { @@ -1648,22 +1660,37 @@ private final class NotificationServiceHandler { } } - return content + return (content, nil) } |> then( pollSignal - |> map { _ -> NotificationContent in } + |> map { _ -> (NotificationContent, Media?) in } ) + |> takeLast + |> mapToSignal { content, _ -> Signal<(NotificationContent, Media?), NoError> in + return stateManager.postbox.transaction { transaction -> (NotificationContent, Media?) in + var parsedMedia: Media? + if let messageId, let message = transaction.getMessage(messageId) { + if let media = message.media.first { + parsedMedia = media + } + } + + return (content, parsedMedia) + } + } } else { pollWithUpdatedContent = pollSignal - |> map { _ -> NotificationContent in } + |> map { _ -> (NotificationContent, Media?) in } } var updatedContent = initialContent - strongSelf.pollDisposable.set(pollWithUpdatedContent.start(next: { content in + var updatedMedia: Media? + strongSelf.pollDisposable.set(pollWithUpdatedContent.start(next: { content, media in updatedContent = content + updatedMedia = media }, completed: { - pollCompletion(updatedContent) + pollCompletion(updatedContent, updatedMedia) })) } else { completed() diff --git a/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Take.swift b/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Take.swift index 99ac5bbce1..dcad112296 100644 --- a/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Take.swift +++ b/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Take.swift @@ -28,6 +28,22 @@ public func take(_ count: Int) -> (Signal) -> Signal { } } +public func takeLast(_ signal: Signal) -> Signal { + return Signal { subscriber in + let lastValue = Atomic(value: nil) + return signal.start(next: { next in + let _ = lastValue.swap(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + if let value = lastValue.with({ $0 }) { + subscriber.putNext(value) + } + subscriber.putCompletion() + }) + } +} + public struct SignalTakeAction { public let passthrough: Bool public let complete: Bool