diff --git a/Classes/Private/Manager/Audio/OCTAudioEngine.m b/Classes/Private/Manager/Audio/OCTAudioEngine.m index aceddb8f..9ef72ff8 100644 --- a/Classes/Private/Manager/Audio/OCTAudioEngine.m +++ b/Classes/Private/Manager/Audio/OCTAudioEngine.m @@ -332,6 +332,7 @@ - (BOOL)startAudioSession:(NSError **)error return ([session setCategory:AVAudioSessionCategoryPlayAndRecord error:error] && [session setPreferredSampleRate:kDefaultSampleRate error:error] && + [session setMode:AVAudioSessionModeVideoChat error:error] && [session setActive:YES error:error]); } diff --git a/Classes/Private/Manager/Database/OCTRealmManager.h b/Classes/Private/Manager/Database/OCTRealmManager.h index 74cc1b9e..6ab9a9d6 100644 --- a/Classes/Private/Manager/Database/OCTRealmManager.h +++ b/Classes/Private/Manager/Database/OCTRealmManager.h @@ -62,7 +62,6 @@ sender:(OCTFriend *)sender messageId:(OCTToxMessageId)messageId; -- (void)addMessageCall:(OCTMessageCallEvent)event - call:(OCTCall *)call - callDuration:(NSTimeInterval)duration; +- (void)addMessageCall:(OCTCall *)call; + @end diff --git a/Classes/Private/Manager/Database/OCTRealmManager.m b/Classes/Private/Manager/Database/OCTRealmManager.m index a39a1237..8dbe0658 100644 --- a/Classes/Private/Manager/Database/OCTRealmManager.m +++ b/Classes/Private/Manager/Database/OCTRealmManager.m @@ -52,6 +52,8 @@ - (instancetype)initWithDatabasePath:(NSString *)path _realm = [RLMRealm realmWithPath:path]; }); + [self convertAllCallsToMessages]; + return self; } @@ -258,6 +260,24 @@ - (void)removeChatWithAllMessages:(OCTChat *)chat }); } +- (void)convertAllCallsToMessages +{ + RLMResults *calls = [OCTCall objectsInRealm:self.realm where:nil]; + + DDLogInfo(@"OCTRealmManager: removing %lu calls", calls.count); + + RBQRealmChangeLogger *logger = [self logger]; + + for (OCTCall *call in calls) { + [self addMessageCall:call]; + } + + [self.realm beginWriteTransaction]; + [logger willDeleteObjects:calls]; + [self.realm deleteObjects:calls]; + [self.realm commitWriteTransaction]; +} + - (OCTMessageAbstract *)addMessageWithText:(NSString *)text type:(OCTToxMessageType)type chat:(OCTChat *)chat @@ -290,15 +310,24 @@ - (OCTMessageAbstract *)addMessageWithText:(NSString *)text return messageAbstract; } -- (void)addMessageCall:(OCTMessageCallEvent)event - call:(OCTCall *)call - callDuration:(NSTimeInterval)duration +- (void)addMessageCall:(OCTCall *)call { NSParameterAssert(call); DDLogInfo(@"OCTRealmManager: adding messageCall to call %@", call); + OCTMessageCallEvent event; + switch (call.status) { + case OCTCallStatusDialing: + case OCTCallStatusRinging: + event = OCTMessageCallEventUnanswered; + break; + case OCTCallStatusActive: + event = OCTMessageCallEventAnswered; + break; + } + OCTMessageCall *messageCall = [OCTMessageCall new]; - messageCall.callDuration = duration; + messageCall.callDuration = call.callDuration; messageCall.callEvent = event; OCTMessageAbstract *messageAbstract = [OCTMessageAbstract new]; diff --git a/Classes/Private/Manager/OCTManager.m b/Classes/Private/Manager/OCTManager.m index a77a1e57..09b43e90 100644 --- a/Classes/Private/Manager/OCTManager.m +++ b/Classes/Private/Manager/OCTManager.m @@ -106,6 +106,7 @@ - (instancetype)initWithConfiguration:(OCTManagerConfiguration *)configuration OCTSubmanagerCalls *calls = [[OCTSubmanagerCalls alloc] initWithTox:_tox]; calls.dataSource = self; _calls = calls; + [_calls setupWithError:nil]; OCTSubmanagerObjects *objects = [OCTSubmanagerObjects new]; objects.dataSource = self; diff --git a/Classes/Private/Manager/Submanagers/OCTSubmanagerCalls.m b/Classes/Private/Manager/Submanagers/OCTSubmanagerCalls.m index 14b63e73..5fb06711 100644 --- a/Classes/Private/Manager/Submanagers/OCTSubmanagerCalls.m +++ b/Classes/Private/Manager/Submanagers/OCTSubmanagerCalls.m @@ -8,7 +8,7 @@ #import "OCTSubmanagerCalls+Private.h" -const OCTToxAVAudioBitRate kDefaultAudioBitRate = 48; +const OCTToxAVAudioBitRate kDefaultAudioBitRate = OCTToxAVAudioBitRate48; const OCTToxAVAudioBitRate kDefaultVideoBitRate = 400; @interface OCTSubmanagerCalls () @@ -36,10 +36,6 @@ - (instancetype)initWithTox:(OCTTox *)tox _toxAV.delegate = self; [_toxAV start]; - _audioEngine = [OCTAudioEngine new]; - _audioEngine.toxav = self.toxAV; - [_audioEngine setupWithError:nil]; - return self; } @@ -61,7 +57,7 @@ - (BOOL)setupWithError:(NSError **)error - (OCTCall *)callToChat:(OCTChat *)chat enableAudio:(BOOL)enableAudio enableVideo:(BOOL)enableVideo error:(NSError **)error { - OCTToxAVAudioBitRate audioBitRate = (enableAudio) ? kDefaultAudioBitRate : kOCTToxAVAudioBitRateDisable; + OCTToxAVAudioBitRate audioBitRate = (enableAudio) ? kDefaultAudioBitRate : OCTToxAVAudioBitRateDisabled; OCTToxAVVideoBitRate videoBitRate = (enableVideo) ? kDefaultVideoBitRate : kOCTToxAVVideoBitRateDisable; if (chat.friends.count == 1) { @@ -89,7 +85,7 @@ - (OCTCall *)callToChat:(OCTChat *)chat enableAudio:(BOOL)enableAudio enableVide - (BOOL)answerCall:(OCTCall *)call enableAudio:(BOOL)enableAudio enableVideo:(BOOL)enableVideo error:(NSError **)error { - OCTToxAVAudioBitRate audioBitRate = (enableAudio) ? kDefaultAudioBitRate : kOCTToxAVAudioBitRateDisable; + OCTToxAVAudioBitRate audioBitRate = (enableAudio) ? kDefaultAudioBitRate : OCTToxAVAudioBitRateDisabled; OCTToxAVVideoBitRate videoBitRate = (enableVideo) ? kDefaultVideoBitRate : kOCTToxAVVideoBitRateDisable; if (call.chat.friends.count == 1) { @@ -141,15 +137,13 @@ - (BOOL)sendCallControl:(OCTToxAVCallControl)control toCall:(OCTCall *)call erro return NO; } - OCTMessageCallEvent event = (call.status == OCTCallStatusActive) ? OCTMessageCallEventAnswered : OCTMessageCallEventUnanswered; - switch (control) { case OCTToxAVCallControlResume: [self updateCall:call withStatus:OCTCallStatusActive]; break; case OCTToxAVCallControlCancel: [self.timer stopTimer]; - [self addMessageCall:event forCall:call withDuration:call.callDuration]; + [self addMessageCall:call]; return [self.audioEngine stopAudioFlow:error]; case OCTToxAVCallControlPause: break; @@ -221,10 +215,10 @@ - (void)updateCall:(OCTCall *)call withStatus:(OCTCallStatus)status }]; } -- (void)addMessageCall:(OCTMessageCallEvent)event forCall:(OCTCall *)call withDuration:(NSTimeInterval)duration +- (void)addMessageCall:(OCTCall *)call { OCTRealmManager *realmManager = [self.dataSource managerGetRealmManager]; - [realmManager addMessageCall:event call:call callDuration:duration]; + [realmManager addMessageCall:call]; [self.timer stopTimer]; [realmManager deleteObject:call]; @@ -234,28 +228,28 @@ - (void)updateCall:(OCTCall *)call withState:(OCTToxAVCallState)state { BOOL sendingAudio, sendingVideo, receivingAudio, receivingVideo; - if (state & OCTToxAVCallStateReceivingAudio) { + if (state & OCTToxAVFriendCallStateReceivingAudio) { receivingAudio = YES; } - if (state & OCTToxAVCallStateReceivingVideo) { + if (state & OCTToxAVFriendCallStateReceivingVideo) { receivingVideo = YES; } - if (state & OCTToxAVCallStateSendingAudio) { + if (state & OCTToxAVFriendCallStateSendingAudio) { sendingAudio = YES; } - if (state & OCTToxAVCallStateSendingVideo) { + if (state & OCTToxAVFriendCallStateSendingVideo) { sendingVideo = YES; } OCTRealmManager *realmManager = [self.dataSource managerGetRealmManager]; [realmManager updateObject:call withBlock:^(OCTCall *callToUpdate) { - call.receivingAudio = receivingAudio; - call.receivingVideo = receivingVideo; - call.sendingAudio = sendingAudio; - call.sendingVideo = sendingVideo; + callToUpdate.receivingAudio = receivingAudio; + callToUpdate.receivingVideo = receivingVideo; + callToUpdate.sendingAudio = sendingAudio; + callToUpdate.sendingVideo = sendingVideo; }]; } @@ -275,13 +269,9 @@ - (void)toxAV:(OCTToxAV *)toxAV callStateChanged:(OCTToxAVCallState)state friend { OCTCall *call = [self getOrCreateCallWithFriendNumber:friendNumber]; - OCTCallStatus status = call.status; - - if ((state & OCTToxAVCallStateFinished) || (state & OCTToxAVCallStateError)) { + if ((state & OCTToxAVFriendCallStateFinished) || (state & OCTToxAVFriendCallStateError)) { - OCTMessageCallEvent event = (status = OCTCallStatusRinging) ? OCTMessageCallEventUnanswered : OCTMessageCallEventAnswered; - - [self addMessageCall:event forCall:call withDuration:call.callDuration]; + [self addMessageCall:call]; [self.audioEngine stopAudioFlow:nil]; @@ -290,6 +280,8 @@ - (void)toxAV:(OCTToxAV *)toxAV callStateChanged:(OCTToxAVCallState)state friend if (call.status == OCTCallStatusDialing) { [self updateCall:call withStatus:OCTCallStatusActive]; + self.audioEngine.friendNumber = friendNumber; + [self.audioEngine startAudioFlow:nil]; [self.timer startTimerForCall:call]; } @@ -298,13 +290,37 @@ - (void)toxAV:(OCTToxAV *)toxAV callStateChanged:(OCTToxAVCallState)state friend - (void)toxAV:(OCTToxAV *)toxAV audioBitRateChanged:(OCTToxAVAudioBitRate)bitrate stable:(BOOL)stable friendNumber:(OCTToxFriendNumber)friendNumber { - // Lower bitrate if unstable? + if (stable) { + return; + } + + OCTToxAVAudioBitRate newBitrate; + + switch (bitrate) { + case OCTToxAVAudioBitRate48: + newBitrate = OCTToxAVAudioBitRate32; + break; + case OCTToxAVAudioBitRate32: + newBitrate = OCTToxAVAudioBitRate24; + break; + case OCTToxAVAudioBitRate24: + newBitrate = OCTToxAVAudioBitRate16; + break; + case OCTToxAVAudioBitRate16: + newBitrate = OCTToxAVAudioBitRate8; + break; + case OCTToxAVAudioBitRate8: + return; + case OCTToxAVAudioBitRateDisabled: + NSAssert(NO, @"We shouldn't be here!"); + break; + } + + [self.toxAV setAudioBitRate:newBitrate force:NO forFriend:friendNumber error:nil]; } - (void)toxAV:(OCTToxAV *)toxAV videoBitRateChanged:(OCTToxAVVideoBitRate)bitrate friendNumber:(OCTToxFriendNumber)friendNumber stable:(BOOL)stable -{ - // Lower bitrate if unstable? -} +{} - (void) toxAV:(OCTToxAV *)toxAV receiveAudio:(OCTToxAVPCMData *)pcm diff --git a/Classes/Private/Wrapper/OCTToxAV.m b/Classes/Private/Wrapper/OCTToxAV.m index b8478b26..e1e99454 100644 --- a/Classes/Private/Wrapper/OCTToxAV.m +++ b/Classes/Private/Wrapper/OCTToxAV.m @@ -494,6 +494,9 @@ - (void)fillError:(NSError **)error withCErrorSendFrame:(TOXAV_ERR_SEND_FRAME)cE code = OCTToxAVErrorSendFrameInvalid; failureReason = @"One of the frame parameters was invalid. E.g. the resolution may be too small or too large, or the audio sampling rate may be unsupported"; break; + case TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED: + code = OCTToxAVErrorSendFramePayloadTypeDisabled; + failureReason = @"Either friend turned off audio/video receiving or we turned off sending for the said payload."; case TOXAV_ERR_SEND_FRAME_RTP_FAILED: code = OCTToxAVErrorSendFrameRTPFailed; failureReason = @"Failed to push frame through rtp interface"; @@ -542,7 +545,7 @@ void callIncomingCallback(ToxAV *cToxAV, void callStateCallback(ToxAV *cToxAV, uint32_t friendNumber, - enum TOXAV_CALL_STATE cState, + enum TOXAV_FRIEND_CALL_STATE cState, void *userData) { OCTToxAV *toxAV = (__bridge OCTToxAV *)userData; @@ -553,23 +556,23 @@ void callStateCallback(ToxAV *cToxAV, OCTToxAVCallState state = 0; - if (cState & TOXAV_CALL_STATE_ERROR) { - state |= OCTToxAVCallStateError; + if (cState & TOXAV_FRIEND_CALL_STATE_ERROR) { + state |= OCTToxAVFriendCallStateError; } - if (cState & TOXAV_CALL_STATE_FINISHED) { - state |= OCTToxAVCallStateFinished; + if (cState & TOXAV_FRIEND_CALL_STATE_FINISHED) { + state |= OCTToxAVFriendCallStateFinished; } - if (cState & TOXAV_CALL_STATE_SENDING_A) { - state |= OCTToxAVCallStateSendingAudio; + if (cState & TOXAV_FRIEND_CALL_STATE_SENDING_A) { + state |= OCTToxAVFriendCallStateSendingAudio; } - if (cState & TOXAV_CALL_STATE_SENDING_V) { - state |= OCTToxAVCallStateSendingVideo; + if (cState & TOXAV_FRIEND_CALL_STATE_SENDING_V) { + state |= OCTToxAVFriendCallStateSendingVideo; } - if (cState & TOXAV_CALL_STATE_RECEIVING_A) { - state |= OCTToxAVCallStateReceivingAudio; + if (cState & TOXAV_FRIEND_CALL_STATE_RECEIVING_A) { + state |= OCTToxAVFriendCallStateReceivingAudio; } - if (cState & TOXAV_CALL_STATE_RECEIVING_V) { - state |= OCTToxAVCallStateReceivingVideo; + if (cState & TOXAV_FRIEND_CALL_STATE_RECEIVING_V) { + state |= OCTToxAVFriendCallStateReceivingVideo; } if ([toxAV.delegate respondsToSelector:@selector(toxAV:callStateChanged:friendNumber:)]) { diff --git a/Classes/Public/Wrapper/OCTToxAVConstants.h b/Classes/Public/Wrapper/OCTToxAVConstants.h index 6897c8cf..19625db4 100644 --- a/Classes/Public/Wrapper/OCTToxAVConstants.h +++ b/Classes/Public/Wrapper/OCTToxAVConstants.h @@ -8,7 +8,6 @@ #import -typedef int OCTToxAVAudioBitRate; typedef const int16_t OCTToxAVPCMData; typedef size_t OCTToxAVSampleCount; typedef uint8_t OCTToxAVChannels; @@ -20,7 +19,6 @@ typedef uint16_t OCTToxAVVideoHeight; typedef const uint8_t OCTToxAVPlaneData; typedef const int32_t OCTToxAVStrideData; -extern const OCTToxAVAudioBitRate kOCTToxAVAudioBitRateDisable; extern const OCTToxAVVideoBitRate kOCTToxAVVideoBitRateDisable; extern NSString *const kOCTToxAVErrorDomain; @@ -38,34 +36,34 @@ typedef NS_OPTIONS(NSInteger, OCTToxAVCallState) { * transitions can occur for the call. This call state will never be triggered * in combination with other call states. */ - OCTToxAVCallStateError = 1 << 0, + OCTToxAVFriendCallStateError = 1 << 0, /** * The call has finished. This is the final state after which no more state * transitions can occur for the call. This call state will never be * triggered in combination with other call states. */ - OCTToxAVCallStateFinished = 1 << 1, + OCTToxAVFriendCallStateFinished = 1 << 1, /** * The flag that marks that friend is sending audio. */ - OCTToxAVCallStateSendingAudio = 1 << 2, + OCTToxAVFriendCallStateSendingAudio = 1 << 2, /** * The flag that marks that friend is sending video. */ - OCTToxAVCallStateSendingVideo = 1 << 3, + OCTToxAVFriendCallStateSendingVideo = 1 << 3, /** * The flag that marks that friend is receiving audio. */ - OCTToxAVCallStateReceivingAudio = 1 << 4, + OCTToxAVFriendCallStateReceivingAudio = 1 << 4, /** * The flag that marks that friend is receiving video. */ - OCTToxAVCallStateReceivingVideo = 1 << 5, + OCTToxAVFriendCallStateReceivingVideo = 1 << 5, }; /******************************************************************************* @@ -235,6 +233,11 @@ typedef NS_ENUM(NSInteger, OCTToxAVErrorSendFrame) { */ OCTToxAVErrorSendFrameInvalid, + /** + * Bit rate for this payload type was not set up. + */ + OCTToxAVErrorSendFramePayloadTypeDisabled, + /** * Failed to push frame through rtp interface. */ @@ -288,3 +291,22 @@ typedef NS_ENUM(NSInteger, OCTToxAVCallControl) { */ OCTToxAVCallControlShowVideo, }; + +/******************************************************************************* + * + * Audio Bitrates. All bitrates are in kb/s. + * + ******************************************************************************/ +typedef NS_ENUM(NSInteger, OCTToxAVAudioBitRate) { + OCTToxAVAudioBitRateDisabled = 0, + + OCTToxAVAudioBitRate8 = 8, + + OCTToxAVAudioBitRate16 = 16, + + OCTToxAVAudioBitRate24 = 24, + + OCTToxAVAudioBitRate32 = 32, + + OCTToxAVAudioBitRate48 = 48, +}; diff --git a/Podfile b/Podfile index 4204750c..56ee3a37 100644 --- a/Podfile +++ b/Podfile @@ -5,7 +5,7 @@ platform :ios, '7.0' # ignore all warnings from all pods inhibit_all_warnings! -pod 'toxcore-ios', :podspec => 'https://raw.githubusercontent.com/Chuongv/toxcore-ios/0.1.10-new-av/toxcore-ios.podspec' +pod 'toxcore-ios', :podspec => 'https://raw.githubusercontent.com/Chuongv/toxcore-ios/0.1.12-new-av/toxcore-ios.podspec' pod 'CocoaLumberjack', '~> 1.9.2' pod 'TPCircularBuffer', '~> 0.0.1' pod 'Realm', '0.93.2' diff --git a/objcTox.xcodeproj/project.pbxproj b/objcTox.xcodeproj/project.pbxproj index b2a248e9..068f824b 100644 --- a/objcTox.xcodeproj/project.pbxproj +++ b/objcTox.xcodeproj/project.pbxproj @@ -85,6 +85,7 @@ EE9A84F0183CA4D0C3342BD50E2F44E5 /* OCTMessageAbstract.m in Sources */ = {isa = PBXBuildFile; fileRef = 5309FB4CA1007014A575D75CB9387C5C /* OCTMessageAbstract.m */; }; EF084F94290314128486E23E3CE9B22F /* OCTToxAV.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DA03E67FB19C7268351D5CDA3ABCAD3 /* OCTToxAV.m */; }; F02C04D11B20FB98001025D1 /* OCTSubmanagerCallsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F02C04D01B20FB98001025D1 /* OCTSubmanagerCallsTests.m */; }; + F02DA7D11B3DEFF800B89491 /* OCTCallsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F02DA7D01B3DEFF800B89491 /* OCTCallsViewController.m */; }; F041A4491B3B1BC7007A5AE8 /* OCTCallTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = F041A4481B3B1BC7007A5AE8 /* OCTCallTimer.m */; }; F041A44A1B3B1BC7007A5AE8 /* OCTCallTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = F041A4481B3B1BC7007A5AE8 /* OCTCallTimer.m */; }; F05BE2681B3A6DF200C5795D /* OCTToxAVConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = F07C8F981B1E37D300E399F5 /* OCTToxAVConstants.m */; }; @@ -206,6 +207,8 @@ EEE0165339DE12FD2EE1821ACE3E19B8 /* OCTToxOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCTToxOptions.h; sourceTree = ""; }; F02C04CF1B20F7E0001025D1 /* OCTSubmanagerCalls+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OCTSubmanagerCalls+Private.h"; sourceTree = ""; }; F02C04D01B20FB98001025D1 /* OCTSubmanagerCallsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCTSubmanagerCallsTests.m; sourceTree = ""; }; + F02DA7CF1B3DEFF800B89491 /* OCTCallsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCTCallsViewController.h; sourceTree = ""; }; + F02DA7D01B3DEFF800B89491 /* OCTCallsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCTCallsViewController.m; sourceTree = ""; }; F041A4471B3B1BC7007A5AE8 /* OCTCallTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCTCallTimer.h; sourceTree = ""; }; F041A4481B3B1BC7007A5AE8 /* OCTCallTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCTCallTimer.m; sourceTree = ""; }; F056BC181B251AC2008D60B8 /* OCTAudioEngine+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OCTAudioEngine+Private.h"; sourceTree = ""; }; @@ -353,6 +356,8 @@ 7218668C8B51B22E4E473DA9AF6979D1 /* OCTUserViewController.m */, F0B36B531B2CFE2200892E05 /* OCTTabBarControllerViewController.h */, F0B36B541B2CFE2200892E05 /* OCTTabBarControllerViewController.m */, + F02DA7CF1B3DEFF800B89491 /* OCTCallsViewController.h */, + F02DA7D01B3DEFF800B89491 /* OCTCallsViewController.m */, ); path = objcToxDemo; sourceTree = ""; @@ -752,6 +757,7 @@ 11B4BAF21B11E2850001A96A /* OCTSubmanagerFiles.m in Sources */, EC8B1CF4E9445717B8E61A26FD52E36B /* OCTMessageFile.m in Sources */, 9CB71FC31B399EE800E3C1EF /* OCTObject.m in Sources */, + F02DA7D11B3DEFF800B89491 /* OCTCallsViewController.m in Sources */, 9CB71FC21B399EE400E3C1EF /* OCTRealmManager.m in Sources */, 25E5DD48EE60A2A6203731909C2F310E /* OCTMessageText.m in Sources */, F9A7007A32C59757AC4132DF656C5793 /* OCTStartDemoViewController.m in Sources */, diff --git a/objcToxDemo/OCTCallsViewController.h b/objcToxDemo/OCTCallsViewController.h new file mode 100644 index 00000000..4e36d25e --- /dev/null +++ b/objcToxDemo/OCTCallsViewController.h @@ -0,0 +1,13 @@ +// +// OCTCallsViewController.h +// objcTox +// +// Created by Chuong Vu on 6/26/15. +// Copyright (c) 2015 dvor. All rights reserved. +// + +#import "OCTTableViewController.h" + +@interface OCTCallsViewController : OCTTableViewController + +@end diff --git a/objcToxDemo/OCTCallsViewController.m b/objcToxDemo/OCTCallsViewController.m new file mode 100644 index 00000000..821d9f65 --- /dev/null +++ b/objcToxDemo/OCTCallsViewController.m @@ -0,0 +1,244 @@ +// +// OCTCallsViewController.m +// objcTox +// +// Created by Chuong Vu on 6/26/15. +// Copyright (c) 2015 dvor. All rights reserved. +// +#import +#import +#import + +#import "OCTCallsViewController.h" +#import "RBQFetchedResultsController.h" +#import "OCTSubmanagerCalls.h" +#import "OCTCall.h" + +@interface OCTCallsViewController () + +@property (strong, nonatomic) RBQFetchedResultsController *resultsController; +@property (strong, nonatomic) OCTCall *selectedCall; + +@end + +@implementation OCTCallsViewController + +#pragma mark - Lifecycle + +- (instancetype)initWithManager:(OCTManager *)manager +{ + self = [super initWithManager:manager]; + + if (! self) { + return nil; + } + + RBQFetchRequest *fetchRequest = [self.manager.objects fetchRequestForType:OCTFetchRequestTypeCall withPredicate:nil]; + + _resultsController = [[RBQFetchedResultsController alloc] initWithFetchRequest:fetchRequest + sectionNameKeyPath:nil + cacheName:nil]; + _resultsController.delegate = self; + [_resultsController performFetch]; + + self.title = @"Calls"; + + return self; +} + +#pragma mark - UITableViewDelegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + self.selectedCall = [self.resultsController objectAtIndexPath:indexPath]; + + [self showActionDialog]; + + [tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + +#pragma mark - UITableViewDataSource + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [self cellForIndexPath:indexPath]; + + OCTCall *call = [self.resultsController objectAtIndexPath:indexPath]; + + cell.textLabel.text = [NSString stringWithFormat:@"Call\n" + @"Chat identifier %@\n" + @"call status: %ld\n" + @"callDuration: %f\n" + @"friend sending audio: %d\n" + @"friend receiving audio: %d\n" + @"friend sending video: %d\n" + @"friend receiving Video: %d\n", + call.chat.uniqueIdentifier, call.status, call.callDuration, call.sendingAudio, call.receivingAudio, + call.sendingVideo, call.receivingVideo]; + + return cell; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.resultsController numberOfRowsForSectionIndex:section]; +} + +#pragma mark - RBQFetchedResultsControllerDelegate + +- (void)controllerWillChangeContent:(RBQFetchedResultsController *)controller +{ + [self.tableView beginUpdates]; +} + +- (void) controller:(RBQFetchedResultsController *)controller + didChangeObject:(RBQSafeRealmObject *)anObject + atIndexPath:(NSIndexPath *)indexPath + forChangeType:(NSFetchedResultsChangeType)type + newIndexPath:(NSIndexPath *)newIndexPath +{ + switch (type) { + case NSFetchedResultsChangeInsert: + [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + break; + case NSFetchedResultsChangeDelete: + [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; + break; + case NSFetchedResultsChangeUpdate: + [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + break; + case NSFetchedResultsChangeMove: + [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + break; + } +} + +- (void)controllerDidChangeContent:(RBQFetchedResultsController *)controller +{ + @try { + [self.tableView endUpdates]; + } + @catch (NSException *ex) { + [self.resultsController reset]; + [self.tableView reloadData]; + } +} + +#pragma mark - Private + +- (void)showActionDialog +{ + __weak OCTCallsViewController *weakSelf = self; + + [self showActionSheet:^(UIActionSheet *sheet) { + [sheet bk_addButtonWithTitle:@"Send call controls" handler:^{ + [weakSelf showSendControlDialog]; + }]; + + [sheet bk_addButtonWithTitle:@"Mute/Unmute Mic" handler:^{ + [weakSelf toggleMuteMic]; + }]; + + [sheet bk_addButtonWithTitle:@"Use speaker phone" handler:^{ + [weakSelf useSpeaker]; + }]; + + [sheet bk_addButtonWithTitle:@"Use default speakers" handler:^{ + [weakSelf useDefaultSpeaker]; + }]; + }]; + +} + +- (void)showSendControlDialog +{ + __weak OCTCallsViewController *weakSelf = self; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Call control" + message:@"Pick call control to send to friend" + preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *pauseAction = [UIAlertAction actionWithTitle:@"Pause" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) {[weakSelf pause]; + }]; + + UIAlertAction *resumeAction = [UIAlertAction actionWithTitle:@"Resume" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) {[weakSelf resume]; + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"End/Reject Call" + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction *action) {[weakSelf cancel]; + }]; + + UIAlertAction *muteAction = [UIAlertAction actionWithTitle:@"Mute Audio" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) {[weakSelf muteFriend]; + }]; + + UIAlertAction *unmuteAction = [UIAlertAction actionWithTitle:@"Unmute Audio" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) {[weakSelf unmuteFriend]; + }]; + + [alertController addAction:pauseAction]; + [alertController addAction:resumeAction]; + [alertController addAction:cancelAction]; + [alertController addAction:muteAction]; + [alertController addAction:unmuteAction]; + + [self presentViewController:alertController animated:YES completion:nil]; +} + + +#pragma mark - Call methods + +- (void)cancel +{ + NSError *error; + if (! [self.manager.calls sendCallControl:OCTToxAVCallControlCancel toCall:self.selectedCall error:&error]) { + NSLog(@"%@ Error %@", self, error.localizedDescription); + NSLog(@"%@ Reason: %@", self, error.localizedFailureReason); + } +} + +- (void)useSpeaker +{ + [self.manager.calls routeAudioToSpeaker:YES error:nil]; +} + +- (void)useDefaultSpeaker +{ + [self.manager.calls routeAudioToSpeaker:NO error:nil]; +} + +- (void)toggleMuteMic +{ + BOOL currentStatus = self.manager.calls.enableMicrophone; + self.manager.calls.enableMicrophone = ! currentStatus; +} + +- (void)pause +{ + [self.manager.calls sendCallControl:OCTToxAVCallControlPause toCall:self.selectedCall error:nil]; +} + +- (void)resume +{ + [self.manager.calls sendCallControl:OCTToxAVCallControlResume toCall:self.selectedCall error:nil]; +} + +- (void)muteFriend +{ + [self.manager.calls sendCallControl:OCTToxAVCallControlMuteAudio toCall:self.selectedCall error:nil]; +} + +- (void)unmuteFriend +{ + [self.manager.calls sendCallControl:OCTToxAVCallControlUnmuteAudio toCall:self.selectedCall error:nil]; +} + +@end diff --git a/objcToxDemo/OCTConversationViewController.m b/objcToxDemo/OCTConversationViewController.m index 582b8569..5b4ed34f 100644 --- a/objcToxDemo/OCTConversationViewController.m +++ b/objcToxDemo/OCTConversationViewController.m @@ -140,66 +140,10 @@ - (void)showSendDialog [sheet bk_addButtonWithTitle:@"Call friend" handler:^{ [weakSelf callFriend]; }]; - - [sheet bk_addButtonWithTitle:@"Send call controls" - handler:^{ - [weakSelf showSendControlDialog]; - }]; - - [sheet bk_addButtonWithTitle:@"Mute/Unmute Mic" handler:^{ - [weakSelf toggleMuteMic]; - }]; - - [sheet bk_addButtonWithTitle:@"Use speaker phone" handler:^{ - [weakSelf useSpeaker]; - }]; - - [sheet bk_addButtonWithTitle:@"Use default speakers" handler:^{ - [weakSelf useDefaultSpeaker]; - }]; }]; } -- (void)showSendControlDialog -{ - __weak OCTConversationViewController *weakSelf = self; - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Call control" - message:@"Pick call control to send to friend" - preferredStyle:UIAlertControllerStyleActionSheet]; - UIAlertAction *pauseAction = [UIAlertAction actionWithTitle:@"Pause" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) {[weakSelf pause]; - }]; - - UIAlertAction *resumeAction = [UIAlertAction actionWithTitle:@"Resume" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) {[weakSelf resume]; - }]; - - UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"End/Reject Call" - style:UIAlertActionStyleDestructive - handler:^(UIAlertAction *action) {[weakSelf cancel]; - }]; - - UIAlertAction *muteAction = [UIAlertAction actionWithTitle:@"Mute Audio" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) {[weakSelf muteFriend]; - }]; - - UIAlertAction *unmuteAction = [UIAlertAction actionWithTitle:@"Unmute Audio" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) {[weakSelf unmuteFriend]; - }]; - - [alertController addAction:pauseAction]; - [alertController addAction:resumeAction]; - [alertController addAction:cancelAction]; - [alertController addAction:muteAction]; - [alertController addAction:unmuteAction]; - - [self presentViewController:alertController animated:YES completion:nil]; -} - (void)sendMessage { @@ -225,60 +169,11 @@ - (void)sendMessage - (void)callFriend { NSError *error; - [self.manager.calls callToChat:self.chat enableAudio:YES enableVideo:NO error:&error]; - - NSLog(@"%@ Error %@", self, error.localizedDescription); - NSLog(@"%@ Reason: %@", self, error.localizedFailureReason); -} - -- (void)cancel -{ - // OCTCall *call = [self.manager.calls.calls callWithChat:self.chat]; - // - // NSError *error; - // if (! [self.manager.calls sendCallControl:OCTToxAVCallControlCancel toCall:call error:&error]) { - // NSLog(@"%@ Error %@", self, error.localizedDescription); - // NSLog(@"%@ Reason: %@", self, error.localizedFailureReason); - // } -} - -- (void)useSpeaker -{ - [self.manager.calls routeAudioToSpeaker:YES error:nil]; -} - -- (void)useDefaultSpeaker -{ - [self.manager.calls routeAudioToSpeaker:NO error:nil]; -} + OCTCall *call = [self.manager.calls callToChat:self.chat enableAudio:YES enableVideo:NO error:&error]; -- (void)toggleMuteMic -{ - BOOL currentStatus = self.manager.calls.enableMicrophone; - self.manager.calls.enableMicrophone = ! currentStatus; -} - -- (void)pause -{ - // OCTCall *call = [self.manager.calls.calls callWithChat:self.chat]; - // [self.manager.calls sendCallControl:OCTToxAVCallControlPause toCall:call error:nil]; -} - -- (void)resume -{ - // OCTCall *call = [self.manager.calls.calls callWithChat:self.chat]; - // [self.manager.calls sendCallControl:OCTToxAVCallControlResume toCall:call error:nil]; -} - -- (void)muteFriend -{ - // OCTCall *call = [self.manager.calls.calls callWithChat:self.chat]; - // [self.manager.calls sendCallControl:OCTToxAVCallControlMuteAudio toCall:call error:nil]; + if (! call) { + NSLog(@"Unable to create call, %@", error.localizedFailureReason); + } } -- (void)unmuteFriend -{ - // OCTCall *call = [self.manager.calls.calls callWithChat:self.chat]; - // [self.manager.calls sendCallControl:OCTToxAVCallControlUnmuteAudio toCall:call error:nil]; -} @end diff --git a/objcToxDemo/OCTStartDemoViewController.m b/objcToxDemo/OCTStartDemoViewController.m index 93a5a9d4..6c0cfcfa 100644 --- a/objcToxDemo/OCTStartDemoViewController.m +++ b/objcToxDemo/OCTStartDemoViewController.m @@ -12,6 +12,7 @@ #import "OCTUserViewController.h" #import "OCTFriendsViewController.h" #import "OCTChatsViewController.h" +#import "OCTCallsViewController.h" #import "OCTTabBarControllerViewController.h" #import "AppDelegate.h" @@ -116,6 +117,7 @@ - (void)bootstrap NAVIGATION_WITH_CONTROLLER(OCTUserViewController), NAVIGATION_WITH_CONTROLLER(OCTFriendsViewController), NAVIGATION_WITH_CONTROLLER(OCTChatsViewController), + NAVIGATION_WITH_CONTROLLER(OCTCallsViewController), ]; AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate; diff --git a/objcToxDemo/OCTTabBarControllerViewController.m b/objcToxDemo/OCTTabBarControllerViewController.m index 2e1ba4b1..94ca86ce 100644 --- a/objcToxDemo/OCTTabBarControllerViewController.m +++ b/objcToxDemo/OCTTabBarControllerViewController.m @@ -18,7 +18,8 @@ @implementation OCTTabBarControllerViewController - (void)callSubmanager:(OCTSubmanagerCalls *)callSubmanager receiveCall:(OCTCall *)call audioEnabled:(BOOL)audioEnabled videoEnabled:(BOOL)videoEnabled { - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Receiving call" message:@"call" preferredStyle:UIAlertControllerStyleAlert]; + NSString *title = [NSString stringWithFormat:@"audio: %d video: %d", audioEnabled, videoEnabled]; + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Receiving call" message:title preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *rejectAction = [UIAlertAction actionWithTitle:@"Reject Call" style:UIAlertActionStyleCancel @@ -47,7 +48,7 @@ - (void)callSubmanager:(OCTSubmanagerCalls *)callSubmanager receiveCall:(OCTCall [alertController addAction:rejectAction]; [alertController addAction:acceptAction]; - NSLog(@"Presented view controller"); + [self presentViewController:alertController animated:YES completion:nil]; } diff --git a/objcToxTests/OCTAudioEngineTests.m b/objcToxTests/OCTAudioEngineTests.m index 84ba296a..60832173 100644 --- a/objcToxTests/OCTAudioEngineTests.m +++ b/objcToxTests/OCTAudioEngineTests.m @@ -60,6 +60,7 @@ - (void)setUp [OCMStub([self.audioSession setPreferredSampleRate:0 error:[OCMArg anyObjectRef]]).andReturn(YES) ignoringNonObjectArgs]; OCMStub([self.audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:[OCMArg anyObjectRef]]).andReturn(YES); [OCMStub([self.audioSession setPreferredIOBufferDuration:0 error:[OCMArg anyObjectRef]]).andReturn(YES) ignoringNonObjectArgs]; + OCMStub(([self.audioSession setMode:AVAudioSessionModeVideoChat error:[OCMArg anyObjectRef]])).andReturn(YES); OCMStub([self.audioSession setActive:YES error:[OCMArg anyObjectRef]]).andReturn(YES); OCMStub([self.audioSession setActive:NO error:[OCMArg anyObjectRef]]).andReturn(YES); diff --git a/objcToxTests/OCTSubmanagerCallsTests.m b/objcToxTests/OCTSubmanagerCallsTests.m index 9ea55842..2bdd5bbb 100644 --- a/objcToxTests/OCTSubmanagerCallsTests.m +++ b/objcToxTests/OCTSubmanagerCallsTests.m @@ -24,6 +24,7 @@ @interface OCTSubmanagerCalls (Tests) @property (strong, nonatomic) OCTToxAV *toxAV; @property (strong, nonatomic) OCTAudioEngine *audioEngine; @property (weak, nonatomic) id dataSource; +@property (strong, nonatomic) OCTCallTimer *timer; - (OCTCall *)getOrCreateCallWithFriendNumber:(OCTToxFriendNumber)friendNumber; @@ -74,7 +75,16 @@ - (void)tearDown - (void)testInit { XCTAssertNotNil(self.callManager); - XCTAssertNotNil(self.callManager.audioEngine); +} + +- (void)testSetup +{ + id audioEngine = OCMClassMock([OCTAudioEngine class]); + OCMStub([audioEngine new]).andReturn(audioEngine); + OCMStub([audioEngine setupWithError:[OCMArg anyObjectRef]]).andReturn(YES); + self.callManager.audioEngine = audioEngine; + + XCTAssertTrue([self.callManager setupWithError:nil]); } - (void)testCallToChat @@ -114,12 +124,7 @@ - (void)testEndCall OCMStub([audioEngine stopAudioFlow:[OCMArg anyObjectRef]]).andReturn(YES); self.callManager.audioEngine = audioEngine; - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 12; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + OCTFriend *friend = [self createFriendWithFriendNumber:12]; OCTChat *chat = [self.realmManager getOrCreateChatWithFriend:friend]; OCTCall *call = [self.callManager callToChat:chat enableAudio:YES enableVideo:NO error:nil]; @@ -138,12 +143,7 @@ - (void)testAnswerCallFail id toxAV = OCMClassMock([OCTToxAV class]); self.callManager.toxAV = toxAV; - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 123; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:123]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:123]; @@ -156,15 +156,11 @@ - (void)testAnswerCallSuccess id toxAV = OCMClassMock([OCTToxAV class]); self.callManager.toxAV = toxAV; + self.callManager.audioEngine = [OCTAudioEngine new]; id audioEngine = OCMPartialMock(self.callManager.audioEngine); OCMStub([audioEngine startAudioFlow:[OCMArg anyObjectRef]]).andReturn(YES); - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 1234; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:1234]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:1234]; @@ -174,6 +170,68 @@ - (void)testAnswerCallSuccess XCTAssertEqual(self.callManager.audioEngine.friendNumber, 1234); } +- (void)testCallStateReceiveFinished +{ + id audioEngine = OCMClassMock([OCTAudioEngine class]); + self.callManager.audioEngine = audioEngine; + + OCTFriend *friend = [self createFriendWithFriendNumber:89]; + + OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:89]; + [self.realmManager updateObject:call withBlock:^(OCTCall *callToUpdate) { + callToUpdate.status = OCTCallStatusRinging; + }]; + + OCTToxAVCallState state; + state |= OCTToxAVFriendCallStateFinished; + + [self.callManager toxAV:nil callStateChanged:state friendNumber:89]; + + OCTChat *chat = [self.realmManager getOrCreateChatWithFriend:friend]; + + OCMVerify([audioEngine stopAudioFlow:nil]); + XCTAssertNotNil(chat.lastMessage.messageCall); + XCTAssertEqual(chat.lastMessage.messageCall.callEvent, OCTMessageCallEventUnanswered); + + call = [self.callManager getOrCreateCallWithFriendNumber:89]; + [self.realmManager updateObject:call withBlock:^(OCTCall *callToUpdate) { + call.status = OCTCallStatusActive; + }]; + + [self.callManager toxAV:nil callStateChanged:state friendNumber:89]; + + XCTAssertEqual(chat.lastMessage.messageCall.callEvent, OCTMessageCallEventAnswered); +} + +- (void)testFriendAnsweredCall +{ + id timer = OCMClassMock([OCTCallTimer class]); + self.callManager.timer = timer; + + id audioEngine = OCMClassMock([OCTAudioEngine class]); + self.callManager.audioEngine = audioEngine; + + [self createFriendWithFriendNumber:92]; + + OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:92]; + [self.realmManager updateObject:call withBlock:^(OCTCall *callToUpdate) { + callToUpdate.status = OCTCallStatusDialing; + }]; + + OCTToxAVCallState state; + state |= OCTToxAVFriendCallStateReceivingVideo; + + [self.callManager toxAV:nil callStateChanged:state friendNumber:92]; + + OCMVerify([audioEngine startAudioFlow:nil]); + OCMVerify([audioEngine setFriendNumber:92]); + OCMVerify([timer startTimerForCall:call]); + + XCTAssertEqual(call.status, OCTCallStatusActive); + XCTAssertTrue(call.receivingVideo); + +} + - (void)testRouteAudioToSpeaker { id audioEngine = OCMClassMock([OCTAudioEngine class]); @@ -192,6 +250,8 @@ - (void)testEnableMicrophone [self.callManager setEnableMicrophone:NO]; OCMVerify([audioEngine setEnableMicrophone:NO]); + + XCTAssertFalse(self.callManager.enableMicrophone); } - (void)testTogglePauseForCall @@ -200,12 +260,7 @@ - (void)testTogglePauseForCall self.callManager.toxAV = toxAV; OCMStub([toxAV sendCallControl:OCTToxAVCallControlPause toFriendNumber:12345 error:nil]).andReturn(YES); - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 12345; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:12345]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:12345]; @@ -217,12 +272,7 @@ - (void)testTogglePauseForCall - (void)testSetAudioBitRate { - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 123456; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:123456]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:123456]; @@ -236,12 +286,7 @@ - (void)testSetAudioBitRate - (void)testSetVideoBitRate { - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 321; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:321]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:321]; @@ -256,12 +301,7 @@ - (void)testSetVideoBitRate #pragma mark - Private - (void)testGetOrCreateCallWithFriend { - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 222; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + OCTFriend *friend = [self createFriendWithFriendNumber:222]; OCTChat *chat = [self.realmManager getOrCreateChatWithFriend:friend]; @@ -281,12 +321,7 @@ - (void)testReceiveCalls OCMStub([delegate respondsToSelector:[OCMArg anySelector]]).andReturn(YES); self.callManager.delegate = delegate; - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 221; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:221]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:221]; @@ -296,19 +331,14 @@ - (void)testReceiveCalls - (void)testCallStateChanged { - OCTFriend *friend = [self createFriend]; - friend.friendNumber = 111; - - [self.realmManager.realm beginWriteTransaction]; - [self.realmManager.realm addObject:friend]; - [self.realmManager.realm commitWriteTransaction]; + [self createFriendWithFriendNumber:111]; OCTCall *call = [self.callManager getOrCreateCallWithFriendNumber:111]; OCTToxAVCallState state; - state |= OCTToxAVCallStateReceivingAudio; - state |= OCTToxAVCallStateReceivingVideo; + state |= OCTToxAVFriendCallStateReceivingAudio; + state |= OCTToxAVFriendCallStateReceivingVideo; [self.callManager toxAV:nil callStateChanged:state friendNumber:111]; @@ -332,4 +362,35 @@ - (void)testReceiveAudio OCMVerify([audioEngine provideAudioFrames:pcm sampleCount:4 channels:2 sampleRate:55]); } +- (void)testReceiveUnstableBitrate +{ + id toxAV = OCMClassMock([OCTToxAV class]); + self.callManager.toxAV = toxAV; + + [self.callManager toxAV:toxAV audioBitRateChanged:48 stable:NO friendNumber:1234]; + OCMVerify([toxAV setAudioBitRate:32 force:NO forFriend:1234 error:nil]); + + [self.callManager toxAV:toxAV audioBitRateChanged:32 stable:NO friendNumber:1234]; + OCMVerify([toxAV setAudioBitRate:24 force:NO forFriend:1234 error:nil]); + + [self.callManager toxAV:toxAV audioBitRateChanged:24 stable:NO friendNumber:1234]; + OCMVerify([toxAV setAudioBitRate:16 force:NO forFriend:1234 error:nil]); + + [self.callManager toxAV:toxAV audioBitRateChanged:16 stable:NO friendNumber:1234]; + OCMVerify([toxAV setAudioBitRate:8 force:NO forFriend:1234 error:nil]); +} + +#pragma mark Test helper methods +- (OCTFriend *)createFriendWithFriendNumber:(OCTToxFriendNumber)friendNumber +{ + OCTFriend *friend = [self createFriend]; + friend.friendNumber = friendNumber; + + [self.realmManager.realm beginWriteTransaction]; + [self.realmManager.realm addObject:friend]; + [self.realmManager.realm commitWriteTransaction]; + + return friend; +} + @end diff --git a/objcToxTests/OCTToxAVTests.m b/objcToxTests/OCTToxAVTests.m index 6b5a4525..972d0637 100644 --- a/objcToxTests/OCTToxAVTests.m +++ b/objcToxTests/OCTToxAVTests.m @@ -74,11 +74,11 @@ - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. - refToSelf = NULL; - self.tox = nil; self.toxAV = nil; + refToSelf = NULL; + [super tearDown]; } @@ -332,38 +332,38 @@ - (void)testReceiveCallback - (void)testCallStateCallback { [self makeTestCallbackWithCallBlock:^{ - callStateCallback(NULL, 1, TOXAV_CALL_STATE_RECEIVING_A | TOXAV_CALL_STATE_SENDING_A, (__bridge void *)self.toxAV); + callStateCallback(NULL, 1, TOXAV_FRIEND_CALL_STATE_RECEIVING_A | TOXAV_FRIEND_CALL_STATE_SENDING_A, (__bridge void *)self.toxAV); } expectBlock:^(id delegate) { OCTToxFriendNumber friendNumber = 1; OCMExpect([self.toxAV.delegate toxAV:self.toxAV - callStateChanged:OCTToxAVCallStateReceivingAudio | OCTToxAVCallStateSendingAudio + callStateChanged:OCTToxAVFriendCallStateReceivingAudio | OCTToxAVFriendCallStateSendingAudio friendNumber:friendNumber]); }]; [self makeTestCallbackWithCallBlock:^{ - callStateCallback(NULL, 1, TOXAV_CALL_STATE_SENDING_A, (__bridge void *)self.toxAV); + callStateCallback(NULL, 1, TOXAV_FRIEND_CALL_STATE_SENDING_A, (__bridge void *)self.toxAV); } expectBlock:^(id delegate) { OCTToxFriendNumber friendNumber = 1; OCMExpect([self.toxAV.delegate toxAV:self.toxAV - callStateChanged:OCTToxAVCallStateSendingAudio + callStateChanged:OCTToxAVFriendCallStateSendingAudio friendNumber:friendNumber]); }]; [self makeTestCallbackWithCallBlock:^{ - callStateCallback(NULL, 1, TOXAV_CALL_STATE_ERROR, (__bridge void *)self.toxAV); + callStateCallback(NULL, 1, TOXAV_FRIEND_CALL_STATE_ERROR, (__bridge void *)self.toxAV); } expectBlock:^(id delegate) { OCTToxFriendNumber friendNumber = 1; OCMExpect([self.toxAV.delegate toxAV:self.toxAV - callStateChanged:OCTToxAVCallStateError + callStateChanged:OCTToxAVFriendCallStateError friendNumber:friendNumber]); }]; [self makeTestCallbackWithCallBlock:^{ - callStateCallback(NULL, 1, TOXAV_CALL_STATE_RECEIVING_A | TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V, (__bridge void *)self.toxAV); + callStateCallback(NULL, 1, TOXAV_FRIEND_CALL_STATE_RECEIVING_A | TOXAV_FRIEND_CALL_STATE_SENDING_A | TOXAV_FRIEND_CALL_STATE_SENDING_V, (__bridge void *)self.toxAV); } expectBlock:^(id delegate) { OCTToxFriendNumber friendNumber = 1; OCMExpect([self.toxAV.delegate toxAV:self.toxAV - callStateChanged:OCTToxAVCallStateReceivingAudio | OCTToxAVCallStateSendingAudio | OCTToxAVCallStateSendingVideo + callStateChanged:OCTToxAVFriendCallStateReceivingAudio | OCTToxAVFriendCallStateSendingAudio | OCTToxAVFriendCallStateSendingVideo friendNumber:friendNumber]); }]; }