Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ringtone app made simple. #326

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Ringtones/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,3 @@ Application Notes
* There is no timeout for the audio player. If the asset plays to completion or
there is an error, all calls from OTAudioBus will be passed to the audio
driver, and playback/capture for OpenTok will proceed as normal.

* An additional tap gesture recognizer has been added to this sample to show
and test that this sequence will work through multiple calls. The
`resetSession` method is added to implement this workflow.
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,97 @@
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
2 changes: 2 additions & 0 deletions Ringtones/Ringtones/OTAudioDeviceRingtone.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@

// Immediately stops the ringtone and allows OpenTok audio calls to flow
- (void)stopRingtone;
- (void)startRingtone;
- (BOOL)isRingTonePlaying;

@end
109 changes: 31 additions & 78 deletions Ringtones/Ringtones/OTAudioDeviceRingtone.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ @interface OTAudioDeviceRingtone() <AVAudioPlayerDelegate>

@implementation OTAudioDeviceRingtone {
AVAudioPlayer* _audioPlayer;
NSMutableArray* _deferredCallbacks;
BOOL _vibratesWithRingtone;
NSTimer* _vibrateTimer;
NSURL * ringtoneURL;
Expand All @@ -29,7 +28,6 @@ @implementation OTAudioDeviceRingtone {
- (instancetype)initWithRingtone:(NSURL *)url {
self = [super init];
if (self) {
_deferredCallbacks = [NSMutableArray new];
ringtoneURL = url;
}

Expand Down Expand Up @@ -74,116 +72,71 @@ - (void)playRingtoneFromURL:(NSURL*)url
[_audioPlayer play];
}

- (void)stopRingtone {
// Stop Audio
[_audioPlayer stop];
_audioPlayer = nil;

// Stop vibration
[_vibrateTimer invalidate];
_vibrateTimer = nil;

[self startCapture];
[self startRendering];
// Allow deferred audio callback calls to flow
[self flushDeferredCallbacks];
}

- (void)buzz:(NSTimer*)timer {
if (_vibratesWithRingtone) {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
}

/**
* Private method: Can't always do as requested immediately. Defer incoming
* callbacks from OTAudioBus until we aren't playing anything back
*/
- (void)enqueueDeferredCallback:(SEL)callback
{
@synchronized(self) {
NSString* selectorString = NSStringFromSelector(callback);
[_deferredCallbacks addObject:selectorString];
}
}

- (void)flushDeferredCallbacks {
while (_deferredCallbacks.count > 0) {
NSString* selectorString = [_deferredCallbacks objectAtIndex:0];
NSLog(@"performing deferred callback %@", selectorString);
SEL callback = NSSelectorFromString(selectorString);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:callback];
#pragma clang diagnostic pop
[_deferredCallbacks removeObjectAtIndex:0];
}
}

#pragma mark - OTDefaultAudioDevice overrides

// The following callbacks are overridden just in case you want to add logs etc.
// You could have made a call to the parent methods directly.

- (BOOL)startRendering
{
if (_audioPlayer) {
[self enqueueDeferredCallback:_cmd];
return YES;
} else {
return [super startRendering];
}
return [super startRendering];
}

- (BOOL)stopRendering
{
if (_audioPlayer) {
[self enqueueDeferredCallback:_cmd];
return YES;
} else {
return [super stopRendering];
}
return [super stopRendering];
}

- (BOOL)startCapture
{
if (_audioPlayer) {
[self enqueueDeferredCallback:_cmd];
return YES;
} else {
static dispatch_once_t once;
BOOL ret = [super startCapture];
dispatch_once(&once, ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self playRingtoneFromURL:self->ringtoneURL];
});
});
return ret;
}
return [super startCapture];
}

- (BOOL)stopCapture
{
if (_audioPlayer) {
[self enqueueDeferredCallback:_cmd];
return YES;
} else {
return [super stopCapture];
}
return [super stopCapture];
}

#pragma mark - AVAudioPlayerDelegate

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
successfully:(BOOL)flag
{
NSLog(@"audioPlayerDidFinishPlaying success=%d", flag);
[self stopRingtone];
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player
error:(NSError * __nullable)error
{
NSLog(@"audioPlayerDecodeErrorDidOccur %@", error);
[self stopRingtone];
}

#pragma mark - Exposed interface methods
- (void)startRingtone {
if (_audioPlayer == nil) {
[self playRingtoneFromURL:ringtoneURL];
}
}

- (void)stopRingtone {
// Stop Audio
[_audioPlayer stop];
_audioPlayer = nil;

// Stop vibration
[_vibrateTimer invalidate];
_vibrateTimer = nil;

[self startCapture];
[self startRendering];

}

- (BOOL)isRingTonePlaying {
return _audioPlayer != nil;
}

@end
Loading