Skip to content

Commit

Permalink
Finish recording synchronously if ‘time’ parameter is zero
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeltyson committed Jul 13, 2016
1 parent 9ef6bc7 commit 09153f8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ typedef void (^AEAudioFileRecorderModuleCompletionBlock)();
/*!
* Stop recording
*
* Will finish recording asynchronously at the given time, or if time is zero,
* will finish recording synchronously.
*
* @param time Time to end recording, or 0 for "now"
* @param block Block to perform once recording has completed
*/
Expand Down
55 changes: 43 additions & 12 deletions TheAmazingAudioEngine/Modules/Taps/AEAudioFileRecorderModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
#import "AEMainThreadEndpoint.h"
#import <AudioToolbox/AudioToolbox.h>
#import <libkern/OSAtomic.h>
#import <pthread.h>

@interface AEAudioFileRecorderModule () {
ExtAudioFileRef _audioFile;
pthread_mutex_t _audioFileMutex;
AEHostTicks _startTime;
AEHostTicks _stopTime;
BOOL _complete;
Expand Down Expand Up @@ -48,13 +50,16 @@ - (instancetype)initWithRenderer:(AERenderer *)renderer URL:(NSURL *)url type:(A
self.processFunction = AEAudioFileRecorderModuleProcess;
self.numberOfChannels = numberOfChannels;

pthread_mutex_init(&_audioFileMutex, NULL);

return self;
}

- (void)dealloc {
if ( _audioFile ) {
[self finishWriting];
}
pthread_mutex_destroy(&_audioFileMutex);
}

- (void)beginRecordingAtTime:(AEHostTicks)time {
Expand All @@ -65,42 +70,66 @@ - (void)beginRecordingAtTime:(AEHostTicks)time {
}

- (void)stopRecordingAtTime:(AEHostTicks)time completionBlock:(AEAudioFileRecorderModuleCompletionBlock)block {
__weak typeof(self) weakSelf = self;
self.stopRecordingNotificationEndpoint = [[AEMainThreadEndpoint alloc] initWithHandler:^(const void * _Nullable data, size_t length) {
weakSelf.stopRecordingNotificationEndpoint = nil;
weakSelf.recording = NO;
[weakSelf finishWriting];
if ( block ) block();
} bufferCapacity:32];

OSMemoryBarrier();
_stopTime = time ? time : AECurrentTimeInHostTicks();
if ( time ) {
// Stop after a delay
__weak typeof(self) weakSelf = self;
self.stopRecordingNotificationEndpoint = [[AEMainThreadEndpoint alloc] initWithHandler:^(const void * _Nullable data, size_t length) {
weakSelf.stopRecordingNotificationEndpoint = nil;
[weakSelf finishWriting];
weakSelf.recording = NO;
if ( block ) block();
} bufferCapacity:32];

OSMemoryBarrier();
_stopTime = time;
} else {
// Stop immediately
pthread_mutex_lock(&_audioFileMutex);
[self finishWriting];
self.recording = NO;
pthread_mutex_unlock(&_audioFileMutex);
if ( block ) {
block();
}
}
}

static void AEAudioFileRecorderModuleProcess(__unsafe_unretained AEAudioFileRecorderModule * THIS,
const AERenderContext * _Nonnull context) {

if ( !THIS->_recording || THIS->_complete ) return;
if ( pthread_mutex_trylock(&THIS->_audioFileMutex) != 0 ) {
return;
}

if ( !THIS->_recording || THIS->_complete ) {
pthread_mutex_unlock(&THIS->_audioFileMutex);
return;
}

AEHostTicks startTime = THIS->_startTime;
AEHostTicks stopTime = THIS->_stopTime;

if ( stopTime && stopTime < context->timestamp->mHostTime ) {
THIS->_complete = YES;
AEMainThreadEndpointSend(THIS->_stopRecordingNotificationEndpoint, NULL, 0);
pthread_mutex_unlock(&THIS->_audioFileMutex);
return;
}

AEHostTicks hostTimeAtBufferEnd
= context->timestamp->mHostTime + AEHostTicksFromSeconds((double)context->frames / context->sampleRate);
if ( startTime && startTime > hostTimeAtBufferEnd ) {
pthread_mutex_unlock(&THIS->_audioFileMutex);
return;
}

THIS->_startTime = 0;

const AudioBufferList * abl = AEBufferStackGet(context->stack, 0);
if ( !abl ) return;
if ( !abl ) {
pthread_mutex_unlock(&THIS->_audioFileMutex);
return;
}

// Prepare buffer with the right number of channels
AEAudioBufferListCreateOnStackWithFormat(buffer, AEAudioDescriptionWithChannelsAndRate(THIS->_numberOfChannels, 0));
Expand Down Expand Up @@ -141,6 +170,8 @@ static void AEAudioFileRecorderModuleProcess(__unsafe_unretained AEAudioFileReco
THIS->_complete = YES;
AEMainThreadEndpointSend(THIS->_stopRecordingNotificationEndpoint, NULL, 0);
}

pthread_mutex_unlock(&THIS->_audioFileMutex);
}

- (void)finishWriting {
Expand Down

0 comments on commit 09153f8

Please sign in to comment.