diff --git a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj index 5f6d53b..f468f37 100644 --- a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj +++ b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + A1C9767718981BFE0057F881 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C9767618981BFE0057F881 /* AudioUnit.framework */; }; A1E7C4CC188D57F50010896F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4CB188D57F50010896F /* Foundation.framework */; }; A1E7C4DA188D57F60010896F /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4D9188D57F60010896F /* XCTest.framework */; }; A1E7C4DB188D57F60010896F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4CB188D57F50010896F /* Foundation.framework */; }; @@ -46,6 +47,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + A1C9767618981BFE0057F881 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; A1E7C4C8188D57F50010896F /* libStreamingKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStreamingKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; A1E7C4CB188D57F50010896F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; A1E7C4CF188D57F50010896F /* StreamingKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StreamingKit-Prefix.pch"; sourceTree = ""; }; @@ -76,6 +78,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A1C9767718981BFE0057F881 /* AudioUnit.framework in Frameworks */, A1E7C508188D62D20010896F /* UIKit.framework in Frameworks */, A1E7C4CC188D57F50010896F /* Foundation.framework in Frameworks */, ); @@ -116,6 +119,7 @@ A1E7C4CA188D57F50010896F /* Frameworks */ = { isa = PBXGroup; children = ( + A1C9767618981BFE0057F881 /* AudioUnit.framework */, A1E7C507188D62D20010896F /* UIKit.framework */, A1E7C4CB188D57F50010896F /* Foundation.framework */, A1E7C4D9188D57F60010896F /* XCTest.framework */, diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 1c46c13..bd17acb 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -287,6 +287,8 @@ AudioQueueBufferRefLookupEntry; { UInt8* readBuffer; int readBufferSize; + + AudioComponentInstance audioUnit; STKQueueEntry* currentlyPlayingEntry; STKQueueEntry* currentlyReadingEntry; @@ -295,6 +297,7 @@ AudioQueueBufferRefLookupEntry; NSMutableArray* bufferingQueue; bool* bufferUsed; + AudioConverterRef audioConverterRef; AudioQueueBufferRef* audioQueueBuffer; AudioQueueBufferRefLookupEntry* audioQueueBufferLookup; unsigned int audioQueueBufferRefLookupCount; @@ -304,6 +307,7 @@ AudioQueueBufferRefLookupEntry; AudioQueueRef audioQueue; AudioStreamBasicDescription currentAudioStreamBasicDescription; + AudioStreamBasicDescription canonicalAudioStreamBasicDescription; NSThread* playbackThread; NSRunLoop* playbackThreadRunLoop; @@ -516,6 +520,15 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ { if (self = [super init]) { + canonicalAudioStreamBasicDescription.mSampleRate = 44100.00; + canonicalAudioStreamBasicDescription.mFormatID = kAudioFormatLinearPCM; + canonicalAudioStreamBasicDescription.mFormatFlags = kAudioFormatFlagsCanonical; + canonicalAudioStreamBasicDescription.mFramesPerPacket = 1; + canonicalAudioStreamBasicDescription.mChannelsPerFrame = 2; + canonicalAudioStreamBasicDescription.mBitsPerChannel = 8 * sizeof(AudioSampleType); + canonicalAudioStreamBasicDescription.mBytesPerPacket = sizeof(AudioSampleType) * 2; + canonicalAudioStreamBasicDescription.mBytesPerFrame = sizeof(AudioSampleType) * 2; + readBufferSize = readBufferSizeIn; readBuffer = calloc(sizeof(UInt8), readBufferSize); @@ -1169,7 +1182,7 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ if (upcomingQueue.count > 0) { - if ([((STKQueueEntry*)[upcomingQueue peek]) isDefinitelyCompatible:¤tAudioStreamBasicDescription]) + if ([((STKQueueEntry*)[upcomingQueue peek]) isDefinitelyCompatible:¤tAudioStreamBasicDescription]) { return YES; } @@ -1704,6 +1717,10 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ -(void) createAudioQueue { + [self createAudioUnit]; + + return; + OSStatus error; LOGINFO(@"Called"); @@ -2537,6 +2554,8 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ -(BOOL) startAudioQueue { + [self startAudioUnit]; + OSStatus error; LOGINFO(@"Called"); @@ -3147,4 +3166,109 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ return levelMeterState[channelNumber].mAveragePower; } + +/// +/// AudioUnit +/// + +#define kOutputBus 0 +#define kInputBus 1 + +static OSStatus playbackCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData) +{ + return 0; +} + +BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* classDesc) +{ + UInt32 size; + + if (AudioFormatGetPropertyInfo(kAudioFormatProperty_Decoders, sizeof(formatId), &formatId, &size) != 0) + { + return NO; + } + + UInt32 decoderCount = size / sizeof(AudioClassDescription); + AudioClassDescription encoderDescriptions[decoderCount]; + + if (AudioFormatGetProperty(kAudioFormatProperty_Decoders, sizeof(formatId), &formatId, &size, encoderDescriptions) != 0) + { + return NO; + } + + for (UInt32 i=0; i < decoderCount; ++i) + { + if (encoderDescriptions[i].mManufacturer == kAppleHardwareAudioCodecManufacturer) + { + *classDesc = encoderDescriptions[i]; + + return YES; + } + } + + return NO; +} + + +-(void) createAudioUnit +{ + pthread_mutex_lock(&playerMutex); + pthread_mutex_lock(&queueBuffersMutex); + + currentAudioStreamBasicDescription = currentlyPlayingEntry->audioStreamBasicDescription; + + OSStatus status; + AudioComponentDescription desc; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_RemoteIO; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + + AudioComponent component = AudioComponentFindNext(NULL, &desc); + + status = AudioComponentInstanceNew(component, &audioUnit); + + UInt32 flag; + + status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)); + status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)); + + AudioClassDescription classDesc; + + if (GetHardwareCodecClassDesc(currentAudioStreamBasicDescription.mFormatID, &classDesc)) + { + status = AudioConverterNewSpecific(¤tAudioStreamBasicDescription, &canonicalAudioStreamBasicDescription, 1, &classDesc, &audioConverterRef); + } + else + { + status = AudioConverterNew(¤tAudioStreamBasicDescription, &canonicalAudioStreamBasicDescription, &audioConverterRef); + } + + AURenderCallbackStruct callbackStruct; + + callbackStruct.inputProc = playbackCallback; + callbackStruct.inputProcRefCon = (__bridge void*)self; + status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); + + status = AudioUnitInitialize(audioUnit); + + pthread_mutex_unlock(&queueBuffersMutex); + pthread_mutex_unlock(&playerMutex); +} + +-(BOOL) startAudioUnit +{ + AudioOutputUnitStart(audioUnit); + + return YES; +} + +-(void) stopAudioUnit +{ + AudioOutputUnitStop(audioUnit); +} + @end +