no message

This commit is contained in:
Ilya Laktyushin 2018-10-21 00:19:43 +03:00
parent 4ce620f5da
commit 9f407fd1f0
6 changed files with 412 additions and 54 deletions

View File

@ -323,7 +323,7 @@ final class CallListControllerNode: ASDisplayNode {
}
}
return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: state.disableAnimations, account: account, scrollPosition: update.scrollPosition)
return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: false, account: account, scrollPosition: update.scrollPosition)
|> map({ mappedCallListNodeViewListTransition(account: account, showSettings: showSettings, nodeInteraction: nodeInteraction, transition: $0) })
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
}

View File

@ -111,12 +111,12 @@ public func chatListItemStrings(strings: PresentationStrings, message: Message?,
let incoming = message.flags.contains(.Incoming)
if let discardReason = discardReason {
switch discardReason {
case .busy, .disconnect:
messageText = strings.Notification_CallCanceled
case .missed:
messageText = incoming ? strings.Notification_CallMissed : strings.Notification_CallCanceled
case .hangup:
break
case .busy, .disconnect:
messageText = strings.Notification_CallCanceled
case .missed:
messageText = incoming ? strings.Notification_CallMissed : strings.Notification_CallCanceled
case .hangup:
break
}
}

View File

@ -14,11 +14,11 @@ public func legacyDecodeOpusAudio(path: String, outputPath: String) -> Signal<St
}
}
public func legacyEncodeOpusAudio(path: String) -> Signal<(Data?, Int32), NoError> {
public func legacyEncodeOpusAudio(path: String) -> Signal<(String?, Int32), NoError> {
return Signal { subscriber in
let encoder = TGBridgeAudioEncoder(url: URL(fileURLWithPath: path))
encoder?.start(completion: { (dataItem, duration) in
subscriber.putNext((dataItem?.data(), duration))
encoder?.start(completion: { (path, duration) in
subscriber.putNext((path, duration))
subscriber.putCompletion()
})
return EmptyDisposable

View File

@ -226,9 +226,11 @@ public func chatMessageSticker(account: Account, file: TelegramMediaFile, small:
context.withFlippedContext { c in
if let color = arguments.emptyColor {
c.setBlendMode(.normal)
c.setFillColor(color.cgColor)
c.fill(drawingRect)
} else {
c.setBlendMode(.copy)
}
c.setBlendMode(.copy)
if let blurredThumbnailImage = blurredThumbnailImage {
c.interpolationQuality = .low

View File

@ -6,6 +6,6 @@
@interface TGBridgeAudioEncoder : NSObject
- (instancetype)initWithURL:(NSURL *)url;
- (void)startWithCompletion:(void (^)(TGDataItem *, int32_t))completion;
- (void)startWithCompletion:(void (^)(NSString *, int32_t))completion;
@end

View File

@ -1,23 +1,61 @@
#import "TGBridgeAudioEncoder.h"
#import <AVFoundation/AVFoundation.h>
#import <SSignalKit/SSignalKit.h>
#import "opus.h"
#import "opusenc.h"
#import "TGDataItem.h"
static const char *AMQueueSpecific = "AMQueueSpecific";
const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
typedef enum {
ATQueuePriorityLow,
ATQueuePriorityDefault,
ATQueuePriorityHigh
} ATQueuePriority;
@interface ATQueue : NSObject
+ (ATQueue *)mainQueue;
+ (ATQueue *)concurrentDefaultQueue;
+ (ATQueue *)concurrentBackgroundQueue;
- (instancetype)init;
- (instancetype)initWithName:(NSString *)name;
- (instancetype)initWithPriority:(ATQueuePriority)priority;
- (void)dispatch:(dispatch_block_t)block;
- (void)dispatch:(dispatch_block_t)block synchronous:(bool)synchronous;
- (void)dispatchAfter:(NSTimeInterval)seconds block:(dispatch_block_t)block;
- (dispatch_queue_t)nativeQueue;
@end
@interface TGFileDataItem : TGDataItem
- (instancetype)initWithTempFile;
- (void)appendData:(NSData *)data;
- (NSData *)readDataAtOffset:(NSUInteger)offset length:(NSUInteger)length;
- (NSUInteger)length;
- (NSString *)path;
@end
@interface TGBridgeAudioEncoder ()
{
AVAssetReader *_assetReader;
AVAssetReaderOutput *_readerOutput;
NSMutableData *_audioBuffer;
TGDataItem *_tempFileItem;
TGFileDataItem *_tempFileItem;
TGOggOpusWriter *_oggWriter;
int _tailLength;
}
@end
@ -31,7 +69,6 @@ const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
if (asset == nil || asset.tracks.count == 0)
{
//TGLog(@"Asset create fail");
return nil;
}
@ -53,7 +90,7 @@ const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
[_assetReader addOutput:_readerOutput];
_tempFileItem = [[TGDataItem alloc] init];
_tempFileItem = [[TGFileDataItem alloc] initWithTempFile];
}
return self;
}
@ -68,30 +105,27 @@ const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
_oggWriter = nil;
}
+ (SQueue *)processingQueue
+ (ATQueue *)processingQueue
{
static SQueue *queue = nil;
static ATQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
static const char *queueSpecific = "org.telegram.opusAudioEncoderQueue";
dispatch_queue_t dispatchQueue = dispatch_queue_create("org.telegram.opusAudioEncoderQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_set_specific(dispatchQueue, queueSpecific, (void *)queueSpecific, NULL);
queue = [SQueue wrapConcurrentNativeQueue:dispatchQueue];
});
{
queue = [[ATQueue alloc] initWithName:@"org.telegram.opusAudioEncoderQueue"];
});
return queue;
}
- (void)startWithCompletion:(void (^)(TGDataItem *, int32_t))completion
{
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 1000 * 60 * 2;
- (void)startWithCompletion:(void (^)(NSString *, int32_t))completion
{
[[TGBridgeAudioEncoder processingQueue] dispatch:^
{
_oggWriter = [[TGOggOpusWriter alloc] init];
if (![_oggWriter beginWithDataItem:_tempFileItem])
{
//TGLog(@"[TGBridgeAudioEncoder#%x error initializing ogg opus writer]", self);
[self cleanup];
return;
}
@ -119,32 +153,42 @@ const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
}
else
{
[[TGBridgeAudioEncoder processingQueue] dispatch:^
{
if (_tailLength > 0) {
[_oggWriter writeFrame:(uint8_t *)_audioBuffer.bytes frameByteCount:(NSUInteger)_tailLength];
}
}];
break;
}
}
}
TGDataItem *dataItemResult = nil;
NSTimeInterval durationResult = 0.0;
NSUInteger totalBytes = 0;
if (_assetReader.status == AVAssetReaderStatusCompleted)
[[TGBridgeAudioEncoder processingQueue] dispatch:^
{
if (_oggWriter != nil && [_oggWriter writeFrame:NULL frameByteCount:0])
TGFileDataItem *dataItemResult = nil;
NSTimeInterval durationResult = 0.0;
NSUInteger totalBytes = 0;
if (_assetReader.status == AVAssetReaderStatusCompleted)
{
dataItemResult = _tempFileItem;
durationResult = [_oggWriter encodedDuration];
totalBytes = [_oggWriter encodedBytes];
NSLog(@"finished");
if (_oggWriter != nil && [_oggWriter writeFrame:NULL frameByteCount:0])
{
dataItemResult = _tempFileItem;
durationResult = [_oggWriter encodedDuration];
totalBytes = [_oggWriter encodedBytes];
}
[self cleanup];
}
[self cleanup];
}
//TGLog(@"[TGBridgeAudioEncoder#%x convert time: %f ms]", self, (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0);
if (completion != nil)
completion(dataItemResult, (int32_t)durationResult);
//TGLog(@"[TGBridgeAudioEncoder#%x convert time: %f ms]", self, (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0);
if (completion != nil)
completion(dataItemResult.path, (int32_t)durationResult);
}];
}];
}
@ -155,9 +199,6 @@ const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
if (_oggWriter == nil)
return;
static const int millisecondsPerPacket = 60;
static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 1000 * millisecondsPerPacket * 2;
unsigned char currentEncoderPacket[encoderPacketSizeInBytes];
int bufferOffset = 0;
@ -188,24 +229,339 @@ const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
currentEncoderPacketSize += takenBytes;
}
}
else
else {
break;
}
}
_tailLength = currentEncoderPacketSize;
if (currentEncoderPacketSize < encoderPacketSizeInBytes)
{
if (_audioBuffer == nil)
_audioBuffer = [[NSMutableData alloc] initWithCapacity:encoderPacketSizeInBytes];
[_audioBuffer appendBytes:currentEncoderPacket length:currentEncoderPacketSize];
break;
}
else
{
[_oggWriter writeFrame:currentEncoderPacket frameByteCount:(NSUInteger)currentEncoderPacketSize];
_tailLength = 0;
}
}
}
}
@end
@interface TGFileDataItem ()
{
NSUInteger _length;
NSString *_fileName;
bool _fileExists;
NSMutableData *_data;
}
@end
@implementation TGFileDataItem
{
ATQueue *_queue;
}
- (void)_commonInit
{
_queue = [[ATQueue alloc] initWithPriority:ATQueuePriorityLow];
_data = [[NSMutableData alloc] init];
}
- (instancetype)initWithTempFile
{
self = [super init];
if (self != nil)
{
[self _commonInit];
[_queue dispatch:^
{
int64_t randomId = 0;
arc4random_buf(&randomId, 8);
_fileName = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSString alloc] initWithFormat:@"%" PRIx64 "", randomId]];
_fileExists = false;
}];
}
return self;
}
- (instancetype)initWithFilePath:(NSString *)filePath
{
self = [super init];
if (self != nil)
{
[self _commonInit];
[_queue dispatch:^
{
_fileName = filePath;
_length = [[[NSFileManager defaultManager] attributesOfItemAtPath:_fileName error:nil][NSFileSize] unsignedIntegerValue];
_fileExists = [[NSFileManager defaultManager] fileExistsAtPath:_fileName];
}];
}
return self;
}
- (void)noop
{
}
- (void)moveToPath:(NSString *)path
{
[_queue dispatch:^
{
[[NSFileManager defaultManager] moveItemAtPath:_fileName toPath:path error:nil];
_fileName = path;
}];
}
- (void)remove
{
[_queue dispatch:^
{
[[NSFileManager defaultManager] removeItemAtPath:_fileName error:nil];
}];
}
- (void)appendData:(NSData *)data
{
[_queue dispatch:^
{
if (!_fileExists)
{
[[NSFileManager defaultManager] createFileAtPath:_fileName contents:nil attributes:nil];
_fileExists = true;
}
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:_fileName];
[file seekToEndOfFile];
[file writeData:data];
[file synchronizeFile];
[file closeFile];
_length += data.length;
[_data appendData:data];
}];
}
- (NSData *)readDataAtOffset:(NSUInteger)offset length:(NSUInteger)length
{
__block NSData *data = nil;
[_queue dispatch:^
{
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:_fileName];
[file seekToFileOffset:(unsigned long long)offset];
data = [file readDataOfLength:length];
if (data.length != length)
//TGLog(@"Read data length mismatch");
[file closeFile];
} synchronous:true];
return data;
}
- (NSUInteger)length
{
__block NSUInteger result = 0;
[_queue dispatch:^
{
result = _length;
} synchronous:true];
return result;
}
- (NSString *)path {
return _fileName;
}
@end
@interface ATQueue ()
{
dispatch_queue_t _nativeQueue;
bool _isMainQueue;
int32_t _noop;
}
@end
@implementation ATQueue
+ (NSString *)applicationPrefix
{
static NSString *prefix = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
prefix = [[NSBundle mainBundle] bundleIdentifier];
});
return prefix;
}
+ (ATQueue *)mainQueue
{
static ATQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
queue = [[ATQueue alloc] init];
queue->_nativeQueue = dispatch_get_main_queue();
queue->_isMainQueue = true;
});
return queue;
}
+ (ATQueue *)concurrentDefaultQueue
{
static ATQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
queue = [[ATQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
});
return queue;
}
+ (ATQueue *)concurrentBackgroundQueue
{
static ATQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
queue = [[ATQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];
});
return queue;
}
- (instancetype)init
{
return [self initWithName:[[ATQueue applicationPrefix] stringByAppendingFormat:@".%ld", lrand48()]];
}
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self != nil)
{
_nativeQueue = dispatch_queue_create([name UTF8String], DISPATCH_QUEUE_SERIAL);
dispatch_queue_set_specific(_nativeQueue, AMQueueSpecific, (__bridge void *)self, NULL);
}
return self;
}
- (instancetype)initWithPriority:(ATQueuePriority)priority
{
self = [super init];
if (self != nil)
{
_nativeQueue = dispatch_queue_create([[[ATQueue applicationPrefix] stringByAppendingFormat:@".%ld", lrand48()] UTF8String], DISPATCH_QUEUE_SERIAL);
long targetQueueIdentifier = DISPATCH_QUEUE_PRIORITY_DEFAULT;
switch (priority)
{
case ATQueuePriorityLow:
targetQueueIdentifier = DISPATCH_QUEUE_PRIORITY_LOW;
break;
case ATQueuePriorityDefault:
targetQueueIdentifier = DISPATCH_QUEUE_PRIORITY_DEFAULT;
break;
case ATQueuePriorityHigh:
targetQueueIdentifier = DISPATCH_QUEUE_PRIORITY_HIGH;
break;
}
dispatch_set_target_queue(_nativeQueue, dispatch_get_global_queue(targetQueueIdentifier, 0));
dispatch_queue_set_specific(_nativeQueue, AMQueueSpecific, (__bridge void *)self, NULL);
}
return self;
}
- (instancetype)initWithNativeQueue:(dispatch_queue_t)queue
{
self = [super init];
if (self != nil)
{
#if !OS_OBJECT_USE_OBJC
_nativeQueue = dispatch_retain(queue);
#else
_nativeQueue = queue;
#endif
}
return self;
}
- (void)dealloc
{
if (_nativeQueue != nil)
{
#if !OS_OBJECT_USE_OBJC
dispatch_release(_nativeQueue);
#endif
_nativeQueue = nil;
}
}
- (void)dispatch:(dispatch_block_t)block
{
[self dispatch:block synchronous:false];
}
- (void)dispatch:(dispatch_block_t)block synchronous:(bool)synchronous
{
__block ATQueue *strongSelf = self;
dispatch_block_t blockWithSelf = ^
{
block();
[strongSelf noop];
strongSelf = nil;
};
if (_isMainQueue)
{
if ([NSThread isMainThread])
blockWithSelf();
else if (synchronous)
dispatch_sync(_nativeQueue, blockWithSelf);
else
dispatch_async(_nativeQueue, blockWithSelf);
}
else
{
if (dispatch_get_specific(AMQueueSpecific) == (__bridge void *)self)
block();
else if (synchronous)
dispatch_sync(_nativeQueue, blockWithSelf);
else
dispatch_async(_nativeQueue, blockWithSelf);
}
}
- (void)dispatchAfter:(NSTimeInterval)seconds block:(dispatch_block_t)block
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC)), _nativeQueue, block);
}
- (dispatch_queue_t)nativeQueue
{
return _nativeQueue;
}
- (void)noop
{
}
@end