From 693c5ed059adc16379e38773bea6652921560e66 Mon Sep 17 00:00:00 2001 From: Thong Nguyen Date: Wed, 5 Feb 2014 20:22:29 +0000 Subject: [PATCH 1/6] Started adding EQ --- ExampleApp/ExampleApp/AppDelegate.m | 2 +- StreamingKit/StreamingKit/STKAudioPlayer.h | 2 + StreamingKit/StreamingKit/STKAudioPlayer.m | 106 +++++++++++++++++---- 3 files changed, 93 insertions(+), 17 deletions(-) diff --git a/ExampleApp/ExampleApp/AppDelegate.m b/ExampleApp/ExampleApp/AppDelegate.m index feeab66..219e046 100644 --- a/ExampleApp/ExampleApp/AppDelegate.m +++ b/ExampleApp/ExampleApp/AppDelegate.m @@ -31,7 +31,7 @@ self.window.backgroundColor = [UIColor whiteColor]; - audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = YES}]; + audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = NO, .equalizerBandFrequencies = { 0 } /*{50, 100, 200, 400, 800, 1600, 2600, 16000}*/ }]; audioPlayer.meteringEnabled = YES; audioPlayer.volume = 1.0; diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.h b/StreamingKit/StreamingKit/STKAudioPlayer.h index 1948378..138c736 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.h +++ b/StreamingKit/StreamingKit/STKAudioPlayer.h @@ -84,6 +84,8 @@ typedef struct BOOL flushQueueOnSeek; /// If YES then volume control will be enabled on iOS BOOL enableVolumeMixer; + /// A pointer to a 0 terminated array of band frequencies (iOS 5.0 and later, OSX 10.9 and later) + Float32 equalizerBandFrequencies[24]; /// 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) diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 45f4dc6..e8604d1 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -84,7 +84,7 @@ static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options) } #define CHECK_STATUS_AND_RETURN(call) \ - if ((call)) \ + if ((status = (call))) \ { \ pthread_mutex_unlock(&playerMutex); \ [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ @@ -144,6 +144,9 @@ STKAudioPlayerInternalState; #pragma mark STKAudioPlayer +static AudioComponentDescription convertUnitDescription; +static AudioStreamBasicDescription canonicalAudioStreamBasicDescription; + @interface STKAudioPlayer() { BOOL muted; @@ -160,11 +163,15 @@ STKAudioPlayerInternalState; STKAudioPlayerOptions options; AUGraph audioGraph; + AUNode eqNode; AUNode mixerNode; AUNode outputNode; + AudioComponentInstance eqUnit; AudioComponentInstance mixerUnit; AudioComponentInstance outputUnit; + UInt32 eqBandCount; + UInt32 framesRequiredToStartPlaying; UInt32 framesRequiredToPlayAfterRebuffering; @@ -185,7 +192,6 @@ STKAudioPlayerInternalState; AudioBufferList pcmAudioBufferList; AudioConverterRef audioConverterRef; - AudioStreamBasicDescription canonicalAudioStreamBasicDescription; AudioStreamBasicDescription audioConverterAudioStreamBasicDescription; BOOL discontinuous; @@ -239,6 +245,31 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn @implementation STKAudioPlayer ++(void) initialize +{ + convertUnitDescription = (AudioComponentDescription) + { + .componentManufacturer = kAudioUnitManufacturer_Apple, + .componentType = kAudioUnitType_FormatConverter, + .componentSubType = kAudioUnitSubType_AUConverter, + .componentFlags = 0, + .componentFlagsMask = 0 + }; + + const int bytesPerSample = sizeof(AudioSampleType); + + canonicalAudioStreamBasicDescription = (AudioStreamBasicDescription) + { + .mSampleRate = 44100.00, + .mFormatID = kAudioFormatLinearPCM, + .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked, + .mFramesPerPacket = 1, + .mChannelsPerFrame = 2, + .mBytesPerFrame = bytesPerSample * 2 /*channelsPerFrame*/, + .mBitsPerChannel = 8 * bytesPerSample, + .mBytesPerPacket = (bytesPerSample * 2) + }; +} -(STKAudioPlayerOptions) options { return options; @@ -372,17 +403,6 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn PopulateOptionsWithDefault(&options); - const int bytesPerSample = sizeof(AudioSampleType); - - canonicalAudioStreamBasicDescription.mSampleRate = 44100.00; - canonicalAudioStreamBasicDescription.mFormatID = kAudioFormatLinearPCM; - canonicalAudioStreamBasicDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - canonicalAudioStreamBasicDescription.mFramesPerPacket = 1; - canonicalAudioStreamBasicDescription.mChannelsPerFrame = 2; - canonicalAudioStreamBasicDescription.mBytesPerFrame = bytesPerSample * canonicalAudioStreamBasicDescription.mChannelsPerFrame; - canonicalAudioStreamBasicDescription.mBitsPerChannel = 8 * bytesPerSample; - canonicalAudioStreamBasicDescription.mBytesPerPacket = canonicalAudioStreamBasicDescription.mBytesPerFrame * canonicalAudioStreamBasicDescription.mFramesPerPacket; - framesRequiredToStartPlaying = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlaying; framesRequiredToPlayAfterRebuffering = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlayingAfterBufferUnderun; @@ -1841,6 +1861,43 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); + if (self->options.equalizerBandFrequencies[0] != 0) + { + AudioComponentDescription eqDescription = (AudioComponentDescription) + { + .componentType = kAudioUnitType_Effect, + .componentSubType = kAudioUnitSubType_NBandEQ, + .componentManufacturer=kAudioUnitManufacturer_Apple + }; + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); + + CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &eqDescription, &eqNode)); + CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, eqNode, NULL, &eqUnit)); + + while (self->options.equalizerBandFrequencies[eqBandCount] != 0) + { + eqBandCount++; + } + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAUNBandEQProperty_NumberOfBands, kAudioUnitScope_Global, 0, &eqBandCount, sizeof(eqBandCount))); + + for (int i = 0; i < eqBandCount; i++) + { + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Frequency + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)self->options.equalizerBandFrequencies[i], 0)); + } + + for (int i = 0; i < eqBandCount; i++) + { + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_BypassBand + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)0, 0)); + } + + for (int i = 0; i < eqBandCount; i++) + { + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + i, kAudioUnitScope_Global, -74, 0, 0)); + } + } + AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = OutputRenderCallback; @@ -1884,13 +1941,30 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl } else { + if (eqUnit) + { + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, eqNode, 0, &callbackStruct)); + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, eqNode, 0, mixerNode, 0)); + } + else + { + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, mixerNode, 0, &callbackStruct)); + } + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, mixerNode, 0, outputNode, 0)); - CHECK_STATUS_AND_RETURN(status = AUGraphSetNodeInputCallback(audioGraph, mixerNode, 0, &callbackStruct)); } } else { - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, outputNode, 0, &callbackStruct)); + if (eqUnit) + { + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, eqNode, 0, &callbackStruct)); + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, eqNode, 0, outputNode, 0)); + } + else + { + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, outputNode, 0, &callbackStruct)); + } } CHECK_STATUS_AND_RETURN(AUGraphInitialize(audioGraph)); @@ -2407,7 +2481,7 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags* if (frameFilters) { NSUInteger count = frameFilters.count; - AudioStreamBasicDescription asbd = audioPlayer->canonicalAudioStreamBasicDescription; + AudioStreamBasicDescription asbd = canonicalAudioStreamBasicDescription; for (int i = 0; i < count; i++) { From c98b673064451d86c3322b4eee505419fcf0f4f5 Mon Sep 17 00:00:00 2001 From: Thong Nguyen Date: Fri, 7 Feb 2014 09:43:47 +0000 Subject: [PATCH 2/6] Refactoring how the graph and nodes are created --- StreamingKit/StreamingKit/STKAudioPlayer.m | 307 +++++++++++---------- 1 file changed, 164 insertions(+), 143 deletions(-) diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index e8604d1..4bd0199 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -86,9 +86,7 @@ static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options) #define CHECK_STATUS_AND_RETURN(call) \ if ((status = (call))) \ { \ - pthread_mutex_unlock(&playerMutex); \ [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ - return; \ } typedef enum @@ -144,6 +142,8 @@ STKAudioPlayerInternalState; #pragma mark STKAudioPlayer +static AudioComponentDescription mixerDescription; +static AudioComponentDescription outputUnitDescription; static AudioComponentDescription convertUnitDescription; static AudioStreamBasicDescription canonicalAudioStreamBasicDescription; @@ -166,10 +166,16 @@ static AudioStreamBasicDescription canonicalAudioStreamBasicDescription; AUNode eqNode; AUNode mixerNode; AUNode outputNode; + + AUNode eqInputNode; + AUNode eqOutputNode; + AUNode mixerInputNode; + AUNode mixerOutputNode; + AudioComponentInstance eqUnit; AudioComponentInstance mixerUnit; AudioComponentInstance outputUnit; - + UInt32 eqBandCount; UInt32 framesRequiredToStartPlaying; @@ -269,6 +275,28 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn .mBitsPerChannel = 8 * bytesPerSample, .mBytesPerPacket = (bytesPerSample * 2) }; + + outputUnitDescription = (AudioComponentDescription) + { + .componentType = kAudioUnitType_Output, +#if TARGET_OS_IPHONE + .componentSubType = kAudioUnitSubType_RemoteIO, +#else + .componentSubType = kAudioUnitSubType_DefaultOutput, +#endif + .componentFlags = 0, + .componentFlagsMask = 0, + .componentManufacturer = kAudioUnitManufacturer_Apple + }; + + mixerDescription = (AudioComponentDescription) + { + .componentType = kAudioUnitType_Mixer, + .componentSubType = kAudioUnitSubType_MultiChannelMixer, + .componentFlags = 0, + .componentFlagsMask = 0, + .componentManufacturer = kAudioUnitManufacturer_Apple + }; } -(STKAudioPlayerOptions) options { @@ -1808,51 +1836,13 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl } } --(void) createAudioGraph +-(void) createOutputUnit { - pthread_mutex_lock(&playerMutex); - - OSStatus status; - AudioComponentDescription desc; - - desc.componentType = kAudioUnitType_Output; -#if TARGET_OS_IPHONE - desc.componentSubType = kAudioUnitSubType_RemoteIO; -#else - desc.componentSubType = kAudioUnitSubType_DefaultOutput; -#endif - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; + OSStatus status; - AudioComponentDescription mixerDescription; + CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &outputUnitDescription, &outputNode)); + CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, outputNode, &outputUnitDescription, &outputUnit)); - mixerDescription.componentType = kAudioUnitType_Mixer; - mixerDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer; - mixerDescription.componentFlags = 0; - mixerDescription.componentFlagsMask = 0; - mixerDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - - CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph)); - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &desc, &outputNode)); - - if (self.options.enableVolumeMixer) - { - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &mixerDescription, &mixerNode)); - } - - CHECK_STATUS_AND_RETURN(AUGraphOpen(audioGraph)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, outputNode, &desc, &outputUnit)); - - if (self.options.enableVolumeMixer) - { - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, mixerNode, &mixerDescription, &mixerUnit)); - - UInt32 busCount = 1; - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount))); - } - #if TARGET_OS_IPHONE UInt32 flag = 1; @@ -1860,118 +1850,149 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl #endif CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); - - if (self->options.equalizerBandFrequencies[0] != 0) +} + +-(void) createMixerUnit +{ + OSStatus status; + + if (!self.options.enableVolumeMixer) + { + return; + } + + CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &mixerDescription, &mixerNode)); + CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, mixerNode, &mixerDescription, &mixerUnit)); + + UInt32 busCount = 1; + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount))); + + Float64 graphSampleRate = 44100.0; + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &graphSampleRate, sizeof(graphSampleRate))); + + status = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)); + + if (status) + { + AUNode convertNode; + AudioComponentInstance convertUnit; + AudioStreamBasicDescription format; + UInt32 size = sizeof(format); + + // Converter -> Mixer -> Output + + CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, &size)); + CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode)); + CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit)); + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format))); + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, mixerNode, 0)); + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, mixerNode, 0, outputNode, 0)); + CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, &size)); + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, 0, 1.0, 0)); + + mixerInputNode = convertNode; + mixerOutputNode = mixerNode; + } + else + { + mixerInputNode = mixerNode; + mixerOutputNode = mixerNode; + } +} + +-(void) createEqUnit +{ + if (self->options.equalizerBandFrequencies[0] == 0) { - AudioComponentDescription eqDescription = (AudioComponentDescription) - { - .componentType = kAudioUnitType_Effect, - .componentSubType = kAudioUnitSubType_NBandEQ, - .componentManufacturer=kAudioUnitManufacturer_Apple - }; - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); - - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &eqDescription, &eqNode)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, eqNode, NULL, &eqUnit)); - - while (self->options.equalizerBandFrequencies[eqBandCount] != 0) - { - eqBandCount++; - } - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAUNBandEQProperty_NumberOfBands, kAudioUnitScope_Global, 0, &eqBandCount, sizeof(eqBandCount))); - - for (int i = 0; i < eqBandCount; i++) - { - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Frequency + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)self->options.equalizerBandFrequencies[i], 0)); - } - - for (int i = 0; i < eqBandCount; i++) - { - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_BypassBand + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)0, 0)); - } - - for (int i = 0; i < eqBandCount; i++) - { - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + i, kAudioUnitScope_Global, -74, 0, 0)); - } - } - + return; + } + + OSStatus status; + + AudioComponentDescription eqDescription = (AudioComponentDescription) + { + .componentType = kAudioUnitType_Effect, + .componentSubType = kAudioUnitSubType_NBandEQ, + .componentManufacturer=kAudioUnitManufacturer_Apple + }; + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); + + CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &eqDescription, &eqNode)); + CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, eqNode, NULL, &eqUnit)); + + while (self->options.equalizerBandFrequencies[eqBandCount] != 0) + { + eqBandCount++; + } + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAUNBandEQProperty_NumberOfBands, kAudioUnitScope_Global, 0, &eqBandCount, sizeof(eqBandCount))); + + for (int i = 0; i < eqBandCount; i++) + { + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Frequency + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)self->options.equalizerBandFrequencies[i], 0)); + } + + for (int i = 0; i < eqBandCount; i++) + { + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_BypassBand + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)0, 0)); + } + + for (int i = 0; i < eqBandCount; i++) + { + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + i, kAudioUnitScope_Global, -74, 0, 0)); + } +} + +-(void) connectNode:(AUNode)srcNode destination:(AUNode)desNode +{ +} + +-(void) createAudioGraph +{ + OSStatus status; + AUNode currentNode; AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = OutputRenderCallback; callbackStruct.inputProcRefCon = (__bridge void*)self; + + CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph)); + CHECK_STATUS_AND_RETURN(AUGraphOpen(audioGraph)); - if (self->mixerUnit) + [self createEqUnit]; + [self createMixerUnit]; + [self createOutputUnit]; + + currentNode = outputNode; + + if (mixerNode) { - Float64 graphSampleRate = 44100.0; + AUGraphConnectNodeInput(audioGraph, mixerOutputNode, 0, currentNode, 0); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &graphSampleRate, sizeof(graphSampleRate))); - - status = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)); - - if (status) - { - AUNode convertNode; - AudioComponentInstance convertUnit; - AudioStreamBasicDescription format; - UInt32 size = sizeof(format); - AudioComponentDescription convertUnitDescription; - - convertUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - convertUnitDescription.componentType = kAudioUnitType_FormatConverter; - convertUnitDescription.componentSubType = kAudioUnitSubType_AUConverter; - convertUnitDescription.componentFlags = 0; - convertUnitDescription.componentFlagsMask = 0; - - // Converter -> Mixer -> Output - - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, &size)); - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit)); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format))); - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, convertNode, 0, &callbackStruct)); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, mixerNode, 0)); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, mixerNode, 0, outputNode, 0)); - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, &size)); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &format, sizeof(format))); - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, 0, 1.0, 0)); - } - else - { - if (eqUnit) - { - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, eqNode, 0, &callbackStruct)); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, eqNode, 0, mixerNode, 0)); - } - else - { - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, mixerNode, 0, &callbackStruct)); - } - - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, mixerNode, 0, outputNode, 0)); - } + currentNode = mixerNode; } - else + + if (eqNode) { - if (eqUnit) - { - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, eqNode, 0, &callbackStruct)); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, eqNode, 0, outputNode, 0)); - } - else - { - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, outputNode, 0, &callbackStruct)); - } + AUGraphConnectNodeInput(audioGraph, eqNode, 0, currentNode, 0); + + currentNode = eqNode; } - + + if (currentNode != outputNode) + { + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, currentNode, 0, outputNode, 0)); + } + + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, currentNode, 0, &callbackStruct)); + CHECK_STATUS_AND_RETURN(AUGraphInitialize(audioGraph)); self.volume = self->volume; - - pthread_mutex_unlock(&playerMutex); } -(BOOL) startAudioGraph From 3ecba8c8b46ea0f9b38e0f057e27da1fed2b0f3d Mon Sep 17 00:00:00 2001 From: Thong Nguyen Date: Fri, 7 Feb 2014 18:30:54 +0000 Subject: [PATCH 3/6] Some more EQ work --- StreamingKit/StreamingKit/STKAudioPlayer.m | 87 +++++++++++++++------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 4bd0199..1a00275 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -1947,15 +1947,41 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl } } --(void) connectNode:(AUNode)srcNode destination:(AUNode)desNode +-(void) connectNodes:(AUNode)srcNode desNode:(AUNode)desNode srcUnit:(AudioComponentInstance)srcUnit desUnit:(AudioComponentInstance)desUnit { + OSStatus status; + AudioStreamBasicDescription srcFormat, desFormat; + UInt32 size = sizeof(AudioStreamBasicDescription); + + CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(srcUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size)); + CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &desFormat, &size)); + + status = AudioUnitSetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)); + + if (status == 0) + { + } +} + +#define CHECK_AND_CREATE_FIRST_UNIT(x, y) \ +{ \ + if (firstNode == 0) \ + { \ + firstUnit = x; \ + firstNode = y; \ + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); \ + } \ } -(void) createAudioGraph { OSStatus status; - AUNode currentNode; + AUNode firstNode = 0; + AudioComponentInstance firstUnit = 0; + AUNode currentNode = 0; AURenderCallbackStruct callbackStruct; + NSMutableArray* nodes = [[NSMutableArray alloc] init]; + NSMutableArray* units = [[NSMutableArray alloc] init]; callbackStruct.inputProc = OutputRenderCallback; callbackStruct.inputProcRefCon = (__bridge void*)self; @@ -1966,29 +1992,40 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl [self createEqUnit]; [self createMixerUnit]; [self createOutputUnit]; - - currentNode = outputNode; - - if (mixerNode) - { - AUGraphConnectNodeInput(audioGraph, mixerOutputNode, 0, currentNode, 0); - - currentNode = mixerNode; - } - - if (eqNode) - { - AUGraphConnectNodeInput(audioGraph, eqNode, 0, currentNode, 0); - - currentNode = eqNode; - } - - if (currentNode != outputNode) - { - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, currentNode, 0, outputNode, 0)); - } - - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, currentNode, 0, &callbackStruct)); + + if (eqNode) + { + [nodes addObject:@(eqNode)]; + [units addObject:[NSValue valueWithPointer:eqUnit]]; + } + + if (mixerNode) + { + [nodes addObject:@(mixerNode)]; + [units addObject:[NSValue valueWithPointer:mixerUnit]]; + } + + if (outputNode) + { + [nodes addObject:@(outputNode)]; + [units addObject:[NSValue valueWithPointer:outputUnit]]; + } + + firstNode = (AUNode)[[nodes objectAtIndex:0] intValue]; + firstUnit = (AudioComponentInstance)[[nodes objectAtIndex:0] pointerValue]; + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, firstNode, 0, &callbackStruct)); + + CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); + + for (int i = 0; i < nodes.count - 1; i++) + { + AUNode srcNode = [[nodes objectAtIndex:i] intValue]; + AUNode desNode = [[nodes objectAtIndex:i + 1] intValue]; + AudioComponentInstance srcUnit = (AudioComponentInstance)[[units objectAtIndex:i] pointerValue]; + AudioComponentInstance desUnit = (AudioComponentInstance)[[units objectAtIndex:i + 1] pointerValue]; + + [self connectNodes:srcNode desNode:desNode srcUnit:srcUnit desUnit:desUnit]; + } CHECK_STATUS_AND_RETURN(AUGraphInitialize(audioGraph)); From a58269fcdb23629955375adb8d5fd89b9ef1ae21 Mon Sep 17 00:00:00 2001 From: Thong Nguyen Date: Sun, 9 Feb 2014 23:32:49 +0000 Subject: [PATCH 4/6] Got EQ working (iOS5 and OSX 10.9). Changed OSX projects to use 10.9 SDK --- ExampleApp/ExampleApp/AppDelegate.m | 4 +- .../ExampleAppMac.xcodeproj/project.pbxproj | 4 +- ExampleAppMac/ExampleAppMac/AppDelegate.m | 2 +- .../StreamingKit.xcodeproj/project.pbxproj | 4 +- StreamingKit/StreamingKit/STKAudioPlayer.h | 2 + StreamingKit/StreamingKit/STKAudioPlayer.m | 91 +++++++++++++------ 6 files changed, 72 insertions(+), 35 deletions(-) diff --git a/ExampleApp/ExampleApp/AppDelegate.m b/ExampleApp/ExampleApp/AppDelegate.m index 219e046..04f016a 100644 --- a/ExampleApp/ExampleApp/AppDelegate.m +++ b/ExampleApp/ExampleApp/AppDelegate.m @@ -31,10 +31,12 @@ self.window.backgroundColor = [UIColor whiteColor]; - audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = NO, .equalizerBandFrequencies = { 0 } /*{50, 100, 200, 400, 800, 1600, 2600, 16000}*/ }]; + audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = NO, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} }]; audioPlayer.meteringEnabled = YES; audioPlayer.volume = 1.0; + [audioPlayer setGain:24 forEqualizerBand:0]; + AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds]; audioPlayerView.delegate = self; diff --git a/ExampleAppMac/ExampleAppMac.xcodeproj/project.pbxproj b/ExampleAppMac/ExampleAppMac.xcodeproj/project.pbxproj index d2e7fce..727c796 100644 --- a/ExampleAppMac/ExampleAppMac.xcodeproj/project.pbxproj +++ b/ExampleAppMac/ExampleAppMac.xcodeproj/project.pbxproj @@ -432,7 +432,7 @@ "$(SRCROOT)/../StreamingKit/StreamingKit", ); INFOPLIST_FILE = "ExampleAppMac/ExampleAppMac-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = ""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; @@ -452,7 +452,7 @@ "$(SRCROOT)/../StreamingKit/StreamingKit", ); INFOPLIST_FILE = "ExampleAppMac/ExampleAppMac-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = ""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; diff --git a/ExampleAppMac/ExampleAppMac/AppDelegate.m b/ExampleAppMac/ExampleAppMac/AppDelegate.m index 15e52c2..e215d62 100644 --- a/ExampleAppMac/ExampleAppMac/AppDelegate.m +++ b/ExampleAppMac/ExampleAppMac/AppDelegate.m @@ -40,7 +40,7 @@ [[self.window contentView] addSubview:playFromHTTPButton]; [[self.window contentView] addSubview:meter]; - audioPlayer = [[STKAudioPlayer alloc] init]; + audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} } ]; audioPlayer.delegate = self; audioPlayer.meteringEnabled = YES; audioPlayer.volume = 1.0; diff --git a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj index 9d2c596..fc79b52 100644 --- a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj +++ b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj @@ -565,7 +565,7 @@ "DEBUG=1", "$(inherited)", ); - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = ""; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; @@ -582,7 +582,7 @@ GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = ""; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.h b/StreamingKit/StreamingKit/STKAudioPlayer.h index 138c736..f0c766c 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.h +++ b/StreamingKit/StreamingKit/STKAudioPlayer.h @@ -254,4 +254,6 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn /// Return values are between -60 (low) and 0 (high). -(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber; +-(void) setGain:(float)gain forEqualizerBand:(int)bandIndex; + @end diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 1a00275..90b5071 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -87,6 +87,7 @@ static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options) if ((status = (call))) \ { \ [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ + return;\ } typedef enum @@ -1909,7 +1910,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl { return; } - + OSStatus status; AudioComponentDescription eqDescription = (AudioComponentDescription) @@ -1919,8 +1920,6 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl .componentManufacturer=kAudioUnitManufacturer_Apple }; - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &eqDescription, &eqNode)); CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, eqNode, NULL, &eqUnit)); @@ -1940,11 +1939,30 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl { CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_BypassBand + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)0, 0)); } - - for (int i = 0; i < eqBandCount; i++) +} + +-(void) setGain:(float)gain forEqualizerBand:(int)bandIndex +{ + if (!eqUnit) { - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + i, kAudioUnitScope_Global, -74, 0, 0)); + return; } + + AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + bandIndex, kAudioUnitScope_Global, 0, gain, 0); +} + +-(AUNode) createConverterNode:(AudioStreamBasicDescription)srcFormat desFormat:(AudioStreamBasicDescription)desFormat +{ + OSStatus status; + AUNode convertNode; + AudioComponentInstance convertUnit; + + status = AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode); + status = AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit); + status = AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)); + status = AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &desFormat, sizeof(desFormat)); + + return convertNode; } -(void) connectNodes:(AUNode)srcNode desNode:(AUNode)desNode srcUnit:(AudioComponentInstance)srcUnit desUnit:(AudioComponentInstance)desUnit @@ -1958,35 +1976,54 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl status = AudioUnitSetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)); - if (status == 0) + if (status) { + AUNode convertNode = [self createConverterNode:srcFormat desFormat:desFormat]; + + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, mixerNode, 0)); } + else + { + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, srcNode, 0, desNode, 0)); + } } -#define CHECK_AND_CREATE_FIRST_UNIT(x, y) \ -{ \ - if (firstNode == 0) \ - { \ - firstUnit = x; \ - firstNode = y; \ - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); \ - } \ +-(void) setOutputCallbackForFirstNode:(AUNode)firstNode firstUnit:(AudioComponentInstance)firstUnit +{ + OSStatus status; + AURenderCallbackStruct callbackStruct; + + callbackStruct.inputProc = OutputRenderCallback; + callbackStruct.inputProcRefCon = (__bridge void*)self; + + status = AudioUnitSetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)); + + if (status) + { + AudioStreamBasicDescription format; + UInt32 size = sizeof(format); + + CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, &size)); + + AUNode converterNode = [self createConverterNode:canonicalAudioStreamBasicDescription desFormat:format]; + + CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, converterNode, 0, firstNode, 0)); + + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, converterNode, 0, &callbackStruct)); + } + else + { + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, firstNode, 0, &callbackStruct)); + } } -(void) createAudioGraph { OSStatus status; - AUNode firstNode = 0; - AudioComponentInstance firstUnit = 0; - AUNode currentNode = 0; - AURenderCallbackStruct callbackStruct; NSMutableArray* nodes = [[NSMutableArray alloc] init]; NSMutableArray* units = [[NSMutableArray alloc] init]; - callbackStruct.inputProc = OutputRenderCallback; - callbackStruct.inputProcRefCon = (__bridge void*)self; - - CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph)); + CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph)); CHECK_STATUS_AND_RETURN(AUGraphOpen(audioGraph)); [self createEqUnit]; @@ -2010,12 +2047,8 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl [nodes addObject:@(outputNode)]; [units addObject:[NSValue valueWithPointer:outputUnit]]; } - - firstNode = (AUNode)[[nodes objectAtIndex:0] intValue]; - firstUnit = (AudioComponentInstance)[[nodes objectAtIndex:0] pointerValue]; - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, firstNode, 0, &callbackStruct)); - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); + + [self setOutputCallbackForFirstNode:(AUNode)[[nodes objectAtIndex:0] intValue] firstUnit:(AudioComponentInstance)[[units objectAtIndex:0] pointerValue]]; for (int i = 0; i < nodes.count - 1; i++) { From ce30f0de57f57d7a1c31917c4c56ef804741ed7e Mon Sep 17 00:00:00 2001 From: Thong Nguyen Date: Mon, 10 Feb 2014 13:25:17 +0000 Subject: [PATCH 5/6] New AudioGraph creation code mostly done. EQ working on iOS and OSX --- ExampleApp/ExampleApp/AppDelegate.m | 4 +- ExampleAppMac/ExampleAppMac/AppDelegate.m | 6 +- StreamingKit/StreamingKit/STKAudioPlayer.h | 1 + StreamingKit/StreamingKit/STKAudioPlayer.m | 94 ++++++++++------------ 4 files changed, 47 insertions(+), 58 deletions(-) diff --git a/ExampleApp/ExampleApp/AppDelegate.m b/ExampleApp/ExampleApp/AppDelegate.m index 04f016a..9d2938e 100644 --- a/ExampleApp/ExampleApp/AppDelegate.m +++ b/ExampleApp/ExampleApp/AppDelegate.m @@ -33,9 +33,7 @@ audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = NO, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} }]; audioPlayer.meteringEnabled = YES; - audioPlayer.volume = 1.0; - - [audioPlayer setGain:24 forEqualizerBand:0]; + audioPlayer.volume = 0.1; AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds]; diff --git a/ExampleAppMac/ExampleAppMac/AppDelegate.m b/ExampleAppMac/ExampleAppMac/AppDelegate.m index e215d62..1bfc81a 100644 --- a/ExampleAppMac/ExampleAppMac/AppDelegate.m +++ b/ExampleAppMac/ExampleAppMac/AppDelegate.m @@ -40,11 +40,11 @@ [[self.window contentView] addSubview:playFromHTTPButton]; [[self.window contentView] addSubview:meter]; - audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} } ]; + audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .enableVolumeMixer = YES, .equalizerBandFrequencies = {0, 50, 100, 200, 400, 800, 1600, 2600, 16000} } ]; audioPlayer.delegate = self; audioPlayer.meteringEnabled = YES; - audioPlayer.volume = 1.0; - + audioPlayer.volume = 0.1; + [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(tick:) userInfo:nil repeats:YES]; } diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.h b/StreamingKit/StreamingKit/STKAudioPlayer.h index f0c766c..8c58712 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.h +++ b/StreamingKit/StreamingKit/STKAudioPlayer.h @@ -254,6 +254,7 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn /// Return values are between -60 (low) and 0 (high). -(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber; +/// Sets the gain value (from -96 low to +24 high) for an equalizer band (0 based index) -(void) setGain:(float)gain forEqualizerBand:(int)bandIndex; @end diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 90b5071..31a48ee 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -90,6 +90,13 @@ static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options) return;\ } +#define CHECK_STATUS_AND_RETURN_VALUE(call, value) \ + if ((status = (call))) \ + { \ + [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ + return value;\ + } + typedef enum { STKAudioPlayerInternalStateInitialised = 0, @@ -144,6 +151,7 @@ STKAudioPlayerInternalState; #pragma mark STKAudioPlayer static AudioComponentDescription mixerDescription; +static AudioComponentDescription nbandUnitDescription; static AudioComponentDescription outputUnitDescription; static AudioComponentDescription convertUnitDescription; static AudioStreamBasicDescription canonicalAudioStreamBasicDescription; @@ -298,6 +306,13 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn .componentFlagsMask = 0, .componentManufacturer = kAudioUnitManufacturer_Apple }; + + nbandUnitDescription = (AudioComponentDescription) + { + .componentType = kAudioUnitType_Effect, + .componentSubType = kAudioUnitSubType_NBandEQ, + .componentManufacturer=kAudioUnitManufacturer_Apple + }; } -(STKAudioPlayerOptions) options { @@ -1872,55 +1887,19 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl Float64 graphSampleRate = 44100.0; CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &graphSampleRate, sizeof(graphSampleRate))); - - status = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)); - - if (status) - { - AUNode convertNode; - AudioComponentInstance convertUnit; - AudioStreamBasicDescription format; - UInt32 size = sizeof(format); - - // Converter -> Mixer -> Output - - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, &size)); - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit)); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format))); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, mixerNode, 0)); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, mixerNode, 0, outputNode, 0)); - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, &size)); - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, 0, 1.0, 0)); - - mixerInputNode = convertNode; - mixerOutputNode = mixerNode; - } - else - { - mixerInputNode = mixerNode; - mixerOutputNode = mixerNode; - } + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, 0, 1.0, 0)); } -(void) createEqUnit { + OSStatus status; + if (self->options.equalizerBandFrequencies[0] == 0) { return; } - OSStatus status; - - AudioComponentDescription eqDescription = (AudioComponentDescription) - { - .componentType = kAudioUnitType_Effect, - .componentSubType = kAudioUnitSubType_NBandEQ, - .componentManufacturer=kAudioUnitManufacturer_Apple - }; - - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &eqDescription, &eqNode)); + CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &nbandUnitDescription, &eqNode)); CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, eqNode, NULL, &eqUnit)); while (self->options.equalizerBandFrequencies[eqBandCount] != 0) @@ -1947,8 +1926,10 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl { return; } + + OSStatus status; - AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + bandIndex, kAudioUnitScope_Global, 0, gain, 0); + CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + bandIndex, kAudioUnitScope_Global, 0, gain, 0)); } -(AUNode) createConverterNode:(AudioStreamBasicDescription)srcFormat desFormat:(AudioStreamBasicDescription)desFormat @@ -1957,10 +1938,10 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl AUNode convertNode; AudioComponentInstance convertUnit; - status = AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode); - status = AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit); - status = AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)); - status = AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &desFormat, sizeof(desFormat)); + CHECK_STATUS_AND_RETURN_VALUE(AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode), 0); + CHECK_STATUS_AND_RETURN_VALUE(status = AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit), 0); + CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)), 0); + CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &desFormat, sizeof(desFormat)), 0); return convertNode; } @@ -2007,9 +1988,9 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl AUNode converterNode = [self createConverterNode:canonicalAudioStreamBasicDescription desFormat:format]; - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, converterNode, 0, firstNode, 0)); + CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, converterNode, 0, &callbackStruct)); - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, converterNode, 0, &callbackStruct)); + status = AUGraphConnectNodeInput(audioGraph, converterNode, 0, firstNode, 0); } else { @@ -2075,6 +2056,13 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl status = AUGraphIsRunning(audioGraph, &isRunning); + if (status) + { + [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; + + return NO; + } + if (isRunning) { return NO; @@ -2108,22 +2096,24 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl status = AUGraphIsRunning(audioGraph, &isRunning); - if (!isRunning) + if (status) + { + [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; + } + else if (!isRunning) { return; } status = AUGraphStop(audioGraph); - [self resetPcmBuffers]; - if (status) { [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - - return; } + [self resetPcmBuffers]; + stopReason = stopReasonIn; self.internalState = STKAudioPlayerInternalStateStopped; } From ac7aabf746ec3fc4fb036a9f2ccd43164cf33326 Mon Sep 17 00:00:00 2001 From: Thong Nguyen Date: Mon, 10 Feb 2014 14:14:59 +0000 Subject: [PATCH 6/6] Removed EQ support for OSX < 10.9 --- StreamingKit/StreamingKit/STKAudioPlayer.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 31a48ee..bc9762d 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -1892,6 +1892,9 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl -(void) createEqUnit { +#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9 + return; +#else OSStatus status; if (self->options.equalizerBandFrequencies[0] == 0) @@ -1918,6 +1921,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl { CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_BypassBand + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)0, 0)); } +#endif } -(void) setGain:(float)gain forEqualizerBand:(int)bandIndex