Changed STKAudioPlayerOptions to be a struct rather than enum. Most values that can be tweaked can be provided in constructor. Fixed deadlock if createAudioGraph fails
This commit is contained in:
parent
0a6e1d4534
commit
63bb19747f
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
||||
-(BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
|
||||
{
|
||||
NSError* error;
|
||||
|
|
@ -32,7 +31,7 @@
|
|||
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:STKAudioPlayerOptionFlushQueueOnSeek|STKAudioPlayerOptionEnableVolumeMixer];
|
||||
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = YES}];
|
||||
audioPlayer.meteringEnabled = YES;
|
||||
audioPlayer.volume = 1.0;
|
||||
|
||||
|
|
|
|||
|
|
@ -78,11 +78,20 @@ typedef enum
|
|||
}
|
||||
STKAudioPlayerErrorCode;
|
||||
|
||||
typedef enum
|
||||
typedef struct
|
||||
{
|
||||
STKAudioPlayerOptionNone = 0,
|
||||
STKAudioPlayerOptionFlushQueueOnSeek = 1,
|
||||
STKAudioPlayerOptionEnableVolumeMixer = 2
|
||||
/// If YES then seeking a track will cause all pending items to be flushed from the queue
|
||||
BOOL flushQueueOnSeek;
|
||||
/// If YES then volume control will be enabled on iOS
|
||||
BOOL enableVolumeMixer;
|
||||
/// The size of the internal I/O read buffer. This data in this buffer is transient and does not need to be larger.
|
||||
UInt32 readBufferSize;
|
||||
/// The size of the decompressed buffer (Default is 10 seconds which uses about 1.7MB of RAM)
|
||||
UInt32 bufferSizeInSeconds;
|
||||
/// Number of seconds of decompressed audio is required before playback first starts for each item (Default is 0.5 seconds. Must be larger than bufferSizeInSeconds)
|
||||
Float32 secondsRequiredToStartPlaying;
|
||||
/// Number of seconds of decompressed audio required before playback resumes after a buffer underrun (Default is 5 seconds. Must be larger than bufferSizeinSeconds)
|
||||
Float32 secondsRequiredToStartPlayingAfterBufferUnderun;
|
||||
}
|
||||
STKAudioPlayerOptions;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,16 +52,41 @@
|
|||
#define STK_LOWPASSFILTERTIMESLICE (0.0005)
|
||||
|
||||
#define STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS (10)
|
||||
#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING (0.1)
|
||||
#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING (1)
|
||||
#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING_AFTER_BUFFER_UNDERRUN (7.5)
|
||||
#define STK_MAX_COMPRESSED_PACKETS_FOR_BITRATE_CALCULATION (2048)
|
||||
#define STK_DEFAULT_READ_BUFFER_SIZE (64 * 1024)
|
||||
#define STK_DEFAULT_PACKET_BUFFER_SIZE (2048)
|
||||
|
||||
#define LOGINFO(x) [self logInfo:[NSString stringWithFormat:@"%s %@", sel_getName(_cmd), x]];
|
||||
|
||||
static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options)
|
||||
{
|
||||
if (options->bufferSizeInSeconds == 0)
|
||||
{
|
||||
options->bufferSizeInSeconds = STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS;
|
||||
}
|
||||
|
||||
if (options->readBufferSize == 0)
|
||||
{
|
||||
options->readBufferSize = STK_DEFAULT_READ_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (options->secondsRequiredToStartPlaying == 0)
|
||||
{
|
||||
options->secondsRequiredToStartPlaying = MIN(STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING, options->bufferSizeInSeconds);
|
||||
}
|
||||
|
||||
if (options->secondsRequiredToStartPlayingAfterBufferUnderun == 0)
|
||||
{
|
||||
options->secondsRequiredToStartPlayingAfterBufferUnderun = MIN(STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING_AFTER_BUFFER_UNDERRUN, options->bufferSizeInSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_STATUS_AND_RETURN(call) \
|
||||
if ((call)) \
|
||||
{ \
|
||||
pthread_mutex_unlock(&playerMutex); \
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \
|
||||
return; \
|
||||
}
|
||||
|
|
@ -308,15 +333,10 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
|
||||
-(id) init
|
||||
{
|
||||
return [self initWithReadBufferSize:STK_DEFAULT_READ_BUFFER_SIZE andOptions:STKAudioPlayerOptionNone];
|
||||
return [self initWithOptions:(STKAudioPlayerOptions){}];
|
||||
}
|
||||
|
||||
-(id) initWithOptions:(STKAudioPlayerOptions)optionsIn
|
||||
{
|
||||
return [self initWithReadBufferSize:STK_DEFAULT_READ_BUFFER_SIZE andOptions:optionsIn];
|
||||
}
|
||||
|
||||
-(id) initWithReadBufferSize:(int)readBufferSizeIn andOptions:(STKAudioPlayerOptions)optionsIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
@ -324,6 +344,8 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
|
||||
self->volume = 1.0;
|
||||
|
||||
PopulateOptionsWithDefault(&options);
|
||||
|
||||
const int bytesPerSample = sizeof(AudioSampleType);
|
||||
|
||||
canonicalAudioStreamBasicDescription.mSampleRate = 44100.00;
|
||||
|
|
@ -335,20 +357,20 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
canonicalAudioStreamBasicDescription.mBitsPerChannel = 8 * bytesPerSample;
|
||||
canonicalAudioStreamBasicDescription.mBytesPerPacket = canonicalAudioStreamBasicDescription.mBytesPerFrame * canonicalAudioStreamBasicDescription.mFramesPerPacket;
|
||||
|
||||
framesRequiredToStartPlaying = canonicalAudioStreamBasicDescription.mSampleRate * STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING;
|
||||
framesRequiredToPlayAfterRebuffering = canonicalAudioStreamBasicDescription.mSampleRate * STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS;
|
||||
framesRequiredToStartPlaying = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlaying;
|
||||
framesRequiredToPlayAfterRebuffering = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlayingAfterBufferUnderun;
|
||||
|
||||
pcmAudioBuffer = &pcmAudioBufferList.mBuffers[0];
|
||||
|
||||
pcmAudioBufferList.mNumberBuffers = 1;
|
||||
pcmAudioBufferList.mBuffers[0].mDataByteSize = (canonicalAudioStreamBasicDescription.mSampleRate * STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS) * canonicalAudioStreamBasicDescription.mBytesPerFrame;
|
||||
pcmAudioBufferList.mBuffers[0].mDataByteSize = (canonicalAudioStreamBasicDescription.mSampleRate * options.bufferSizeInSeconds) * canonicalAudioStreamBasicDescription.mBytesPerFrame;
|
||||
pcmAudioBufferList.mBuffers[0].mData = (void*)calloc(pcmAudioBuffer->mDataByteSize, 1);
|
||||
pcmAudioBufferList.mBuffers[0].mNumberChannels = 2;
|
||||
|
||||
pcmBufferFrameSizeInBytes = canonicalAudioStreamBasicDescription.mBytesPerFrame;
|
||||
pcmBufferTotalFrameCount = pcmAudioBuffer->mDataByteSize / pcmBufferFrameSizeInBytes;
|
||||
|
||||
readBufferSize = readBufferSizeIn;
|
||||
readBufferSize = options.readBufferSize;
|
||||
readBuffer = calloc(sizeof(UInt8), readBufferSize);
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
|
|
@ -370,7 +392,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
bufferingQueue = [[NSMutableArray alloc] init];
|
||||
|
||||
[self resetPcmBuffers];
|
||||
[self createAudioUnit];
|
||||
[self createAudioGraph];
|
||||
[self createPlaybackThread];
|
||||
}
|
||||
|
||||
|
|
@ -949,7 +971,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
}
|
||||
|
||||
[self processFinishPlayingIfAnyAndPlayingNext:currentlyPlayingEntry withNext:entry];
|
||||
[self startAudioUnit];
|
||||
[self startAudioGraph];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1128,7 +1150,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
[currentlyReadingEntry.dataSource unregisterForEvents];
|
||||
}
|
||||
|
||||
if (self->options & STKAudioPlayerOptionFlushQueueOnSeek)
|
||||
if (self->options.flushQueueOnSeek)
|
||||
{
|
||||
self.internalState = STKAudioPlayerInternalStateWaitingForDataAfterSeek;
|
||||
[self setCurrentlyReadingEntry:currentlyPlayingEntry andStartPlaying:YES clearQueue:YES];
|
||||
|
|
@ -1741,7 +1763,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
}
|
||||
}
|
||||
|
||||
-(void) createAudioUnit
|
||||
-(void) createAudioGraph
|
||||
{
|
||||
pthread_mutex_lock(&playerMutex);
|
||||
|
||||
|
|
@ -1766,92 +1788,34 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
mixerDescription.componentFlagsMask = 0;
|
||||
mixerDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
status = NewAUGraph(&audioGraph);
|
||||
CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph));
|
||||
CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &desc, &outputNode));
|
||||
|
||||
if (status)
|
||||
if (self.options.enableVolumeMixer)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &mixerDescription, &mixerNode));
|
||||
}
|
||||
|
||||
status = AUGraphAddNode(audioGraph, &desc, &outputNode);
|
||||
CHECK_STATUS_AND_RETURN(AUGraphOpen(audioGraph));
|
||||
CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, outputNode, &desc, &outputUnit));
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.options & STKAudioPlayerOptionEnableVolumeMixer)
|
||||
if (self.options.enableVolumeMixer)
|
||||
{
|
||||
status = AUGraphAddNode(audioGraph, &mixerDescription, &mixerNode);
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
status = AUGraphOpen(audioGraph);
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
status = AUGraphNodeInfo(audioGraph, outputNode, &desc, &outputUnit);
|
||||
|
||||
if (self.options & STKAudioPlayerOptionEnableVolumeMixer)
|
||||
{
|
||||
status = AUGraphNodeInfo(audioGraph, mixerNode, &mixerDescription, &mixerUnit);
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, mixerNode, &mixerDescription, &mixerUnit));
|
||||
|
||||
UInt32 busCount = 1;
|
||||
|
||||
status = AudioUnitSetProperty (mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount));
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount)));
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
UInt32 flag = 1;
|
||||
|
||||
status = AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag));
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)));
|
||||
#endif
|
||||
|
||||
status = AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription));
|
||||
CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)));
|
||||
|
||||
if (status)
|
||||
{
|
||||
[self unexpectedError:STKAudioPlayerErrorAudioSystemError];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
AURenderCallbackStruct callbackStruct;
|
||||
|
||||
callbackStruct.inputProc = OutputRenderCallback;
|
||||
|
|
@ -1911,7 +1875,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
pthread_mutex_unlock(&playerMutex);
|
||||
}
|
||||
|
||||
-(BOOL) startAudioUnit
|
||||
-(BOOL) startAudioGraph
|
||||
{
|
||||
OSStatus status;
|
||||
|
||||
|
|
@ -2272,7 +2236,7 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
|
|||
}
|
||||
else if (state == STKAudioPlayerInternalStateRebuffering)
|
||||
{
|
||||
int64_t framesRequiredToStartPlaying = audioPlayer->framesRequiredToStartPlaying;
|
||||
int64_t framesRequiredToStartPlaying = audioPlayer->framesRequiredToPlayAfterRebuffering;
|
||||
|
||||
if (entry->lastFrameQueued >= 0)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue