AudioMessageSender.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2012-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import <AVFoundation/AVFoundation.h>
  21. #import <AVFoundation/AVAsset.h>
  22. #import "AudioMessageSender.h"
  23. #import "AudioMessage.h"
  24. #import "AudioData.h"
  25. #import "Conversation.h"
  26. #import "Contact.h"
  27. #import "NaClCrypto.h"
  28. #import "MyIdentityStore.h"
  29. #import "BoxAudioMessage.h"
  30. #import "GroupAudioMessage.h"
  31. #import "MessageQueue.h"
  32. #import "EntityManager.h"
  33. #import "ContactPhotoSender.h"
  34. #ifdef DEBUG
  35. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  36. #else
  37. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  38. #endif
  39. @interface AudioMessageSender ()
  40. @property NSNumber *duration;
  41. @property uint32_t boxDataLength;
  42. @property NSData *encryptionKey;
  43. @property NSData *audioData;
  44. @property NSString *webRequestId;
  45. @end
  46. @implementation AudioMessageSender
  47. - (void)sendItem:(URLSenderItem *)item inConversation:(Conversation *)conversation {
  48. [self startWithAudioFile:item.url inConversation:conversation requestId:nil];
  49. }
  50. - (void)startWithAudioFile:(NSURL *)audioUrl inConversation:(Conversation *)_conversation requestId:(NSString *)requestId {
  51. /* Find duration */
  52. AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:audioUrl options:nil];
  53. float durationF = CMTimeGetSeconds(asset.duration);
  54. NSNumber *duration = [NSNumber numberWithFloat:durationF];
  55. NSData *audioData = [[NSData alloc] initWithContentsOfURL:audioUrl];
  56. [self startWithAudioData:audioData duration:duration inConversation:_conversation requestId:requestId];
  57. }
  58. - (void)startWithAudioData:(NSData *)audioData duration:(NSNumber *)duration inConversation:(Conversation *)conversation requestId:(NSString *)requestId {
  59. self.conversation = conversation;
  60. _duration = duration;
  61. _audioData = audioData;
  62. _webRequestId = requestId;
  63. [self scheduleUpload];
  64. }
  65. - (void)retryWithAudioMessage:(AudioMessage*)message {
  66. self.message = message;
  67. self.conversation = message.conversation;
  68. _duration = message.duration;
  69. [self scheduleUpload];
  70. }
  71. - (void)createDBMessage {
  72. EntityManager *entityManager = [[EntityManager alloc] init];
  73. [entityManager performSyncBlockAndSafe:^{
  74. Conversation *conversationOwnContext = (Conversation *)[entityManager.entityFetcher getManagedObjectById:self.conversation.objectID];
  75. AudioMessage *message = [entityManager.entityCreator audioMessageForConversation:conversationOwnContext];
  76. AudioData *dbAudio = [entityManager.entityCreator audioData];
  77. dbAudio.data = _audioData;
  78. message.audio = dbAudio;
  79. message.duration = _duration;
  80. message.progress = nil;
  81. message.sendFailed = [NSNumber numberWithBool:NO];
  82. message.webRequestId = _webRequestId;
  83. self.message = message;
  84. }];
  85. }
  86. -(NSData *)encryptedData {
  87. /* Generate random symmetric key and encrypt */
  88. _encryptionKey = [[NaClCrypto sharedCrypto] randomBytes:kBlobKeyLen];
  89. AudioMessage *message = (AudioMessage *)self.message;
  90. NSData *boxAudioData = [[NaClCrypto sharedCrypto] symmetricEncryptData:message.audio.data withKey:_encryptionKey nonce:[NSData dataWithBytesNoCopy:kNonce_1 length:sizeof(kNonce_1) freeWhenDone:NO]];
  91. if (boxAudioData == nil) {
  92. DDLogWarn(@"Audio encryption failed");
  93. }
  94. _boxDataLength = (uint32_t)boxAudioData.length;
  95. return boxAudioData;
  96. }
  97. #pragma mark - BlobMessageSender
  98. - (void)sendMessageTo:(Contact *)contact blobIds:(NSArray *)blobIds {
  99. BoxAudioMessage *boxMsg = [[BoxAudioMessage alloc] init];
  100. boxMsg.messageId = self.message.id;
  101. boxMsg.toIdentity = contact.identity;
  102. boxMsg.duration = _duration.floatValue;
  103. boxMsg.audioBlobId = blobIds[0];
  104. boxMsg.audioSize = _boxDataLength;
  105. boxMsg.encryptionKey = _encryptionKey;
  106. [[MessageQueue sharedMessageQueue] enqueue:boxMsg];
  107. [ContactPhotoSender sendProfilePicture:boxMsg];
  108. }
  109. -(void)sendGroupMessageTo:(Contact *)contact blobIds:(NSArray *)blobIds {
  110. GroupAudioMessage *msg = [[GroupAudioMessage alloc] init];
  111. msg.messageId = self.message.id;
  112. msg.date = self.message.date;
  113. msg.duration = _duration.floatValue;
  114. msg.audioBlobId = blobIds[0];
  115. msg.audioSize = _boxDataLength;
  116. msg.encryptionKey = _encryptionKey;
  117. msg.groupId = self.conversation.groupId;
  118. if (self.conversation.contact == nil) {
  119. msg.groupCreator = [MyIdentityStore sharedMyIdentityStore].identity;
  120. } else {
  121. msg.groupCreator = self.conversation.contact.identity;
  122. }
  123. msg.toIdentity = contact.identity;
  124. [[MessageQueue sharedMessageQueue] enqueue:msg];
  125. [ContactPhotoSender sendProfilePicture:msg];
  126. }
  127. @end