diff --git a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj index f468f37..a22c99b 100644 --- a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj +++ b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + A1BF65D2189A6582004DD08C /* STKQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = A1BF65D1189A6582004DD08C /* STKQueueEntry.m */; }; 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 */; }; @@ -47,6 +48,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + A1BF65D0189A6582004DD08C /* STKQueueEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKQueueEntry.h; sourceTree = ""; }; + A1BF65D1189A6582004DD08C /* STKQueueEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKQueueEntry.m; sourceTree = ""; }; 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; }; @@ -145,6 +148,8 @@ A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */, A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */, A1E7C4CE188D57F50010896F /* Supporting Files */, + A1BF65D0189A6582004DD08C /* STKQueueEntry.h */, + A1BF65D1189A6582004DD08C /* STKQueueEntry.m */, ); path = StreamingKit; sourceTree = ""; @@ -260,6 +265,7 @@ A1E7C501188D5E550010896F /* STKCoreFoundationDataSource.m in Sources */, A1E7C4FF188D5E550010896F /* STKAudioPlayer.m in Sources */, A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */, + A1BF65D2189A6582004DD08C /* STKQueueEntry.m in Sources */, A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */, A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */, A1E7C502188D5E550010896F /* STKDataSource.m in Sources */, diff --git a/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h b/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h new file mode 100644 index 0000000..25cfac2 --- /dev/null +++ b/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h @@ -0,0 +1,13 @@ +// +// NSMutableArray+STKAudioPlayer.h +// StreamingKit +// +// Created by Thong Nguyen on 30/01/2014. +// Copyright (c) 2014 Thong Nguyen. All rights reserved. +// + +#import + +@interface NSMutableArray (STKAudioPlayer) + +@end diff --git a/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.m b/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.m new file mode 100644 index 0000000..3339669 --- /dev/null +++ b/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.m @@ -0,0 +1,13 @@ +// +// NSMutableArray+STKAudioPlayer.m +// StreamingKit +// +// Created by Thong Nguyen on 30/01/2014. +// Copyright (c) 2014 Thong Nguyen. All rights reserved. +// + +#import "NSMutableArray+STKAudioPlayer.h" + +@implementation NSMutableArray (STKAudioPlayer) + +@end diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.h b/StreamingKit/StreamingKit/STKAudioPlayer.h index 43761b5..1032541 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.h +++ b/StreamingKit/StreamingKit/STKAudioPlayer.h @@ -2,7 +2,7 @@ AudioPlayer.m Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable + https://github.com/tumtumtum/StreamingKit Inspired by Matt Gallagher's AudioStreamer: https://github.com/mattgallagher/AudioStreamer @@ -143,8 +143,5 @@ STKAudioPlayerErrorCode; -(void) unmute; -(void) dispose; -(NSObject*) currentlyPlayingQueueItemId; --(void) updateMeters; --(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber; --(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber; @end diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index e5ec394..d2006d9 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -2,12 +2,9 @@ AudioPlayer.m Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable + https://github.com/tumtumtum/StreamingKit - Inspired by Matt Gallagher's AudioStreamer: - https://github.com/mattgallagher/AudioStreamer - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. + Copyright (c) 2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -41,7 +38,8 @@ #import "STKLocalFileDataSource.h" #import "libkern/OSAtomic.h" -#define STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS (2) +#define STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS (5) +#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING (0.75) #define STK_BIT_RATE_ESTIMATION_MIN_PACKETS (64) #define STK_BUFFERS_NEEDED_TO_START (32) @@ -51,8 +49,6 @@ #define STK_FRAMES_MISSED_BEFORE_CONSIDERED_UNDERRUN (1024) #define STK_DEFAULT_NUMBER_OF_AUDIOQUEUE_BUFFERS (1024) -#define OSSTATUS_PARAM_ERROR (-50) - #define LOGINFO(x) [self logInfo:[NSString stringWithFormat:@"%s %@", sel_getName(_cmd), x]]; typedef struct @@ -301,6 +297,7 @@ AudioQueueBufferRefLookupEntry; bool* bufferUsed; OSSpinLock pcmBufferSpinLock; + volatile BOOL buffering; volatile UInt32 pcmBufferFrameSizeInBytes; volatile UInt32 pcmBufferTotalFrameCount; volatile UInt32 pcmBufferFrameStartIndex; @@ -3117,79 +3114,6 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ return retval; } -#pragma mark Metering - --(void) setMeteringEnabled:(BOOL)value -{ - if (!audioQueue) - { - meteringEnabled = value; - - return; - } - - UInt32 on = value ? 1 : 0; - OSStatus error = AudioQueueSetProperty(audioQueue, kAudioQueueProperty_EnableLevelMetering, &on, sizeof(on)); - - if (error) - { - meteringEnabled = NO; - } - else - { - meteringEnabled = YES; - } -} - --(BOOL) meteringEnabled -{ - return meteringEnabled; -} - --(void) updateMeters -{ - if (!meteringEnabled) - { - NSAssert(NO, @"Metering is not enabled. Make sure to set meteringEnabled = YES."); - } - - UInt32 channels = currentAudioStreamBasicDescription.mChannelsPerFrame; - - if (numberOfChannels != channels) - { - numberOfChannels = channels; - - if (levelMeterState) free(levelMeterState); - { - levelMeterState = malloc(sizeof(AudioQueueLevelMeterState) * numberOfChannels); - } - } - - UInt32 sizeofMeters = (UInt32)(sizeof(AudioQueueLevelMeterState) * numberOfChannels); - - AudioQueueGetProperty(audioQueue, kAudioQueueProperty_CurrentLevelMeterDB, levelMeterState, &sizeofMeters); -} - --(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber -{ - if (!meteringEnabled || !levelMeterState || (channelNumber > numberOfChannels)) - { - return 0; - } - - return levelMeterState[channelNumber].mPeakPower; -} - --(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber -{ - if (!meteringEnabled || !levelMeterState || (channelNumber > numberOfChannels)) - { - return 0; - } - - return levelMeterState[channelNumber].mAveragePower; -} - /// /// AudioUnit @@ -3571,64 +3495,78 @@ static OSStatus playbackCallback(void* inRefCon, AudioUnitRenderActionFlags* ioA UInt32 start = audioPlayer->pcmBufferFrameStartIndex; UInt32 end = (audioPlayer->pcmBufferFrameStartIndex + audioPlayer->pcmBufferUsedFrameCount) % audioPlayer->pcmBufferTotalFrameCount; BOOL signal = audioPlayer->waiting && used < audioPlayer->pcmBufferTotalFrameCount / 2; - OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); - - assert(audioPlayer->pcmBufferUsedFrameCount <= audioPlayer->pcmBufferTotalFrameCount); + + UInt32 totalFramesCopied = 0; if (used > 0) { - UInt32 totalFramesCopied = 0; - - if (end > start) + if (!(audioPlayer->buffering && used < audioPlayer->pcmBufferTotalFrameCount)) { - UInt32 framesToCopy = MIN(inNumberFrames, used); - - ioData->mBuffers[0].mNumberChannels = 2; - ioData->mBuffers[0].mDataByteSize = frameSizeInBytes * framesToCopy; - memcpy(ioData->mBuffers[0].mData, audioBuffer->mData + (start * frameSizeInBytes), ioData->mBuffers[0].mDataByteSize); - - totalFramesCopied = framesToCopy; - - OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); - audioPlayer->pcmBufferFrameStartIndex = (audioPlayer->pcmBufferFrameStartIndex + totalFramesCopied) % audioPlayer->pcmBufferTotalFrameCount; - audioPlayer->pcmBufferUsedFrameCount -= totalFramesCopied; - OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); - } - else - { - UInt32 framesToCopy = MIN(inNumberFrames, audioPlayer->pcmBufferTotalFrameCount - start); - - ioData->mBuffers[0].mNumberChannels = 2; - ioData->mBuffers[0].mDataByteSize = frameSizeInBytes * framesToCopy; - memcpy(ioData->mBuffers[0].mData, audioBuffer->mData + (start * frameSizeInBytes), ioData->mBuffers[0].mDataByteSize); - - UInt32 moreFramesToCopy = 0; - UInt32 delta = inNumberFrames - framesToCopy; - - if (delta > 0) + if (audioPlayer->buffering) { - moreFramesToCopy = MIN(delta, end); + NSLog(@"Buffering resuming"); - ioData->mBuffers[0].mNumberChannels = 2; - ioData->mBuffers[0].mDataByteSize += frameSizeInBytes * moreFramesToCopy; - memcpy(ioData->mBuffers[0].mData + (framesToCopy * frameSizeInBytes), audioBuffer->mData, frameSizeInBytes * moreFramesToCopy); + audioPlayer->buffering = NO; } - totalFramesCopied = framesToCopy + moreFramesToCopy; - - OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); - audioPlayer->pcmBufferFrameStartIndex = (audioPlayer->pcmBufferFrameStartIndex + totalFramesCopied) % audioPlayer->pcmBufferTotalFrameCount; - audioPlayer->pcmBufferUsedFrameCount -= totalFramesCopied; - OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); + if (end > start) + { + UInt32 framesToCopy = MIN(inNumberFrames, used); + + ioData->mBuffers[0].mNumberChannels = 2; + ioData->mBuffers[0].mDataByteSize = frameSizeInBytes * framesToCopy; + memcpy(ioData->mBuffers[0].mData, audioBuffer->mData + (start * frameSizeInBytes), ioData->mBuffers[0].mDataByteSize); + + totalFramesCopied = framesToCopy; + + OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); + audioPlayer->pcmBufferFrameStartIndex = (audioPlayer->pcmBufferFrameStartIndex + totalFramesCopied) % audioPlayer->pcmBufferTotalFrameCount; + audioPlayer->pcmBufferUsedFrameCount -= totalFramesCopied; + OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); + } + else + { + UInt32 framesToCopy = MIN(inNumberFrames, audioPlayer->pcmBufferTotalFrameCount - start); + + ioData->mBuffers[0].mNumberChannels = 2; + ioData->mBuffers[0].mDataByteSize = frameSizeInBytes * framesToCopy; + memcpy(ioData->mBuffers[0].mData, audioBuffer->mData + (start * frameSizeInBytes), ioData->mBuffers[0].mDataByteSize); + + UInt32 moreFramesToCopy = 0; + UInt32 delta = inNumberFrames - framesToCopy; + + if (delta > 0) + { + moreFramesToCopy = MIN(delta, end); + + ioData->mBuffers[0].mNumberChannels = 2; + ioData->mBuffers[0].mDataByteSize += frameSizeInBytes * moreFramesToCopy; + memcpy(ioData->mBuffers[0].mData + (framesToCopy * frameSizeInBytes), audioBuffer->mData, frameSizeInBytes * moreFramesToCopy); + } + + totalFramesCopied = framesToCopy + moreFramesToCopy; + + OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); + audioPlayer->pcmBufferFrameStartIndex = (audioPlayer->pcmBufferFrameStartIndex + totalFramesCopied) % audioPlayer->pcmBufferTotalFrameCount; + audioPlayer->pcmBufferUsedFrameCount -= totalFramesCopied; + OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); + } + } + } + + if (totalFramesCopied < inNumberFrames) + { + UInt32 delta = inNumberFrames - totalFramesCopied; + + memset(ioData->mBuffers[0].mData + (totalFramesCopied * frameSizeInBytes), 0, delta * frameSizeInBytes); + + if (!audioPlayer->buffering) + { + NSLog(@"Buffering"); } - if (totalFramesCopied < inNumberFrames) - { - UInt32 delta = inNumberFrames - totalFramesCopied; - - memset(ioData->mBuffers[0].mData + (totalFramesCopied * frameSizeInBytes), 1, delta * frameSizeInBytes); - } + audioPlayer->buffering = YES; } if (signal) diff --git a/StreamingKit/StreamingKit/STKQueueEntry.h b/StreamingKit/StreamingKit/STKQueueEntry.h new file mode 100644 index 0000000..8fd8313 --- /dev/null +++ b/StreamingKit/StreamingKit/STKQueueEntry.h @@ -0,0 +1,13 @@ +// +// STKQueueEntry.h +// StreamingKit +// +// Created by Thong Nguyen on 30/01/2014. +// Copyright (c) 2014 Thong Nguyen. All rights reserved. +// + +#import + +@interface STKQueueEntry : NSobject + +@end diff --git a/StreamingKit/StreamingKit/STKQueueEntry.m b/StreamingKit/StreamingKit/STKQueueEntry.m new file mode 100644 index 0000000..842fb1c --- /dev/null +++ b/StreamingKit/StreamingKit/STKQueueEntry.m @@ -0,0 +1,13 @@ +// +// STKQueueEntry.m +// StreamingKit +// +// Created by Thong Nguyen on 30/01/2014. +// Copyright (c) 2014 Thong Nguyen. All rights reserved. +// + +#import "STKQueueEntry.h" + +@implementation STKQueueEntry + +@end