diff --git a/ExampleApp/ExampleApp.xcodeproj/project.pbxproj b/ExampleApp/ExampleApp.xcodeproj/project.pbxproj index 046b397..53b60b7 100644 --- a/ExampleApp/ExampleApp.xcodeproj/project.pbxproj +++ b/ExampleApp/ExampleApp.xcodeproj/project.pbxproj @@ -230,7 +230,7 @@ A1115929188D686000641365 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Thong Nguyen"; TargetAttributes = { A111594B188D686000641365 = { @@ -346,6 +346,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -422,6 +423,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 6.0; LLVM_LTO = YES; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -438,6 +440,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 6.0; LLVM_LTO = YES; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -459,6 +462,7 @@ "$(inherited)", ); INFOPLIST_FILE = "ExampleAppTests/ExampleAppTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = xctest; @@ -477,6 +481,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch"; INFOPLIST_FILE = "ExampleAppTests/ExampleAppTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = xctest; diff --git a/ExampleApp/ExampleApp/AppDelegate.m b/ExampleApp/ExampleApp/AppDelegate.m index d0680af..bb3d37c 100644 --- a/ExampleApp/ExampleApp/AppDelegate.m +++ b/ExampleApp/ExampleApp/AppDelegate.m @@ -32,6 +32,7 @@ AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(bufferLength), &bufferLength); self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = [[UIViewController alloc] init]; self.window.backgroundColor = [UIColor whiteColor]; @@ -39,7 +40,6 @@ audioPlayer.meteringEnabled = YES; audioPlayer.volume = 1; - AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds andAudioPlayer:audioPlayer]; audioPlayerView.delegate = self; @@ -47,9 +47,9 @@ [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; [self becomeFirstResponder]; - [self.window addSubview:audioPlayerView]; - [self.window makeKeyAndVisible]; + + [self.window.rootViewController.view addSubview:audioPlayerView]; return YES; } diff --git a/ExampleApp/ExampleApp/AudioPlayerView.m b/ExampleApp/ExampleApp/AudioPlayerView.m index a93ea0b..5be5e70 100644 --- a/ExampleApp/ExampleApp/AudioPlayerView.m +++ b/ExampleApp/ExampleApp/AudioPlayerView.m @@ -58,27 +58,27 @@ CGSize size = CGSizeMake(220, 50); playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - playFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10, size.width, size.height); + playFromHTTPButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10, size.width, size.height); [playFromHTTPButton addTarget:self action:@selector(playFromHTTPButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [playFromHTTPButton setTitle:@"Play from HTTP" forState:UIControlStateNormal]; playFromIcecastButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - playFromIcecastButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 35, size.width, size.height); + playFromIcecastButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 35, size.width, size.height); [playFromIcecastButton addTarget:self action:@selector(playFromIcecasButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [playFromIcecastButton setTitle:@"Play from Icecast" forState:UIControlStateNormal]; playFromLocalFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height); + playFromLocalFileButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height); [playFromLocalFileButton addTarget:self action:@selector(playFromLocalFileButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [playFromLocalFileButton setTitle:@"Play from Local File" forState:UIControlStateNormal]; queueShortFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height); + queueShortFileButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height); [queueShortFileButton addTarget:self action:@selector(queueShortFileButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [queueShortFileButton setTitle:@"Queue short file" forState:UIControlStateNormal]; queuePcmWaveFileFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height); + queuePcmWaveFileFromHTTPButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height); [queuePcmWaveFileFromHTTPButton addTarget:self action:@selector(queuePcmWaveFileButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [queuePcmWaveFileFromHTTPButton setTitle:@"Queue PCM/WAVE from HTTP" forState:UIControlStateNormal]; @@ -89,12 +89,12 @@ [playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside]; stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - stopButton.frame = CGRectMake((320 - size.width) - 30, 400, size.width, size.height); + stopButton.frame = CGRectMake((frame.size.width - size.width) - 30, 400, size.width, size.height); [stopButton addTarget:self action:@selector(stopButtonPressed) forControlEvents:UIControlEventTouchUpInside]; [stopButton setTitle:@"Stop" forState:UIControlStateNormal]; muteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - muteButton.frame = CGRectMake((320 - size.width) - 30, 430, size.width, size.height); + muteButton.frame = CGRectMake((frame.size.width - size.width) - 30, 430, size.width, size.height); [muteButton addTarget:self action:@selector(muteButtonPressed) forControlEvents:UIControlEventTouchUpInside]; [muteButton setTitle:@"Mute" forState:UIControlStateNormal]; @@ -106,7 +106,7 @@ repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(30, frame.size.height * 0.15 + 180, size.width, size.height)]; - enableEqSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(320 - size.width - 30, frame.size.height * 0.15 + 180, size.width, size.height)]; + enableEqSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(frame.size.width - size.width - 30, frame.size.height * 0.15 + 180, size.width, size.height)]; enableEqSwitch.on = audioPlayer.equalizerEnabled; [enableEqSwitch addTarget:self action:@selector(onEnableEqSwitch) forControlEvents:UIControlEventAllTouchEvents]; diff --git a/ExampleApp/ExampleApp/ExampleApp-Info.plist b/ExampleApp/ExampleApp/ExampleApp-Info.plist index f2f0135..ef8abcd 100644 --- a/ExampleApp/ExampleApp/ExampleApp-Info.plist +++ b/ExampleApp/ExampleApp/ExampleApp-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - abstractpath.com.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/ExampleApp/ExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json b/ExampleApp/ExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json index 91bf9c1..36d2c80 100644 --- a/ExampleApp/ExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/ExampleApp/ExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json @@ -5,16 +5,31 @@ "size" : "29x29", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, { "idiom" : "ipad", "size" : "29x29", diff --git a/ExampleApp/ExampleApp/Images.xcassets/Contents.json b/ExampleApp/ExampleApp/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/ExampleApp/ExampleApp/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/Contents.json b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/Contents.json index 6f870a4..fb0c438 100644 --- a/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/Contents.json +++ b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -1,5 +1,31 @@ { "images" : [ + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "TX6sV.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "3x" + }, + { + "orientation" : "landscape", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "8.0", + "subtype" : "736h", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "667h", + "filename" : "dBEHd.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "2x" + }, { "orientation" : "portrait", "idiom" : "iphone", @@ -8,11 +34,12 @@ "scale" : "2x" }, { - "orientation" : "portrait", + "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", - "extent" : "full-screen", + "filename" : "TX6sV-2.png", "minimum-system-version" : "7.0", + "orientation" : "portrait", "scale" : "2x" }, { @@ -42,6 +69,26 @@ "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "TX6sV-1.png", + "extent" : "full-screen", + "subtype" : "retina4", + "scale" : "2x" } ], "info" : { diff --git a/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV-1.png b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV-1.png new file mode 100644 index 0000000..20c7652 Binary files /dev/null and b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV-1.png differ diff --git a/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV-2.png b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV-2.png new file mode 100644 index 0000000..20c7652 Binary files /dev/null and b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV-2.png differ diff --git a/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV.png b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV.png new file mode 100644 index 0000000..2f5242b Binary files /dev/null and b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/TX6sV.png differ diff --git a/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/dBEHd.png b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/dBEHd.png new file mode 100644 index 0000000..8f82b77 Binary files /dev/null and b/ExampleApp/ExampleApp/Images.xcassets/LaunchImage.launchimage/dBEHd.png differ diff --git a/ExampleApp/ExampleAppTests/ExampleAppTests-Info.plist b/ExampleApp/ExampleAppTests/ExampleAppTests-Info.plist index 12b70c6..169b6f7 100644 --- a/ExampleApp/ExampleAppTests/ExampleAppTests-Info.plist +++ b/ExampleApp/ExampleAppTests/ExampleAppTests-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - abstractpath.com.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType diff --git a/LICENSE b/LICENSE index 220f79b..06a551b 100644 --- a/LICENSE +++ b/LICENSE @@ -4,7 +4,7 @@ Inspired by Matt Gallagher's AudioStreamer: https://github.com/mattgallagher/AudioStreamer - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. + Copyright (c) 2015 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: @@ -15,12 +15,12 @@ documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: - This product includes software developed by the . + This product includes software developed by Thong Nguyen. 4. Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY + THIS SOFTWARE IS PROVIDED BY THONG NGUYEN ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY diff --git a/README.md b/README.md index c68a827..c40e84a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The primary motivation of this project was to decouple the input data sources fr * Easy to read source. * Carefully multi-threaded to provide a responsive API that won't block your UI thread nor starve the audio buffers. * Buffered and gapless playback between all format types. -* Easy to implement audio data sources (Local, HTTP, AutoRecoveryingHTTP DataSources are provided). +* Easy to implement audio data sources (Local, HTTP, AutoRecoveringHTTP DataSources are provided). * Easy to extend DataSource to support adaptive buffering, encryption, etc. * Optimised for low CPU/battery usage (0% - 1% CPU usage when streaming). * Optimised for linear data sources. Random access sources are required only for seeking. diff --git a/StreamingKit.podspec b/StreamingKit.podspec index 2e7e9c1..289f402 100644 --- a/StreamingKit.podspec +++ b/StreamingKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "StreamingKit" - s.version = "0.1.25" + s.version = "0.1.29" s.summary = "A fast and extensible audio streamer for iOS and OSX with support for gapless playback and custom (non-HTTP) sources." s.homepage = "https://github.com/tumtumtum/StreamingKit/" s.license = 'MIT' diff --git a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj index 0e131d5..1614799 100644 --- a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj +++ b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj @@ -432,7 +432,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = STK; - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Thong Nguyen"; }; buildConfigurationList = A1E7C4C3188D57F50010896F /* Build configuration list for PBXProject "StreamingKit" */; @@ -641,6 +641,7 @@ ); INFOPLIST_FILE = "StreamingKitMacTests/StreamingKitMacTests-Info.plist"; MACOSX_DEPLOYMENT_TARGET = 10.8; + PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; WRAPPER_EXTENSION = xctest; @@ -661,6 +662,7 @@ GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch"; INFOPLIST_FILE = "StreamingKitMacTests/StreamingKitMacTests-Info.plist"; MACOSX_DEPLOYMENT_TARGET = 10.8; + PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; WRAPPER_EXTENSION = xctest; @@ -684,6 +686,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -784,6 +787,7 @@ "$(inherited)", ); INFOPLIST_FILE = "StreamingKitTests/StreamingKitTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = xctest; }; @@ -800,6 +804,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "StreamingKit/StreamingKit-Prefix.pch"; INFOPLIST_FILE = "StreamingKitTests/StreamingKitTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = xctest; }; diff --git a/StreamingKit/StreamingKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/StreamingKit/StreamingKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/StreamingKit/StreamingKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h b/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h index 12ca839..1e4de5f 100644 --- a/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h +++ b/StreamingKit/StreamingKit/NSMutableArray+STKAudioPlayer.h @@ -8,10 +8,14 @@ #import +NS_ASSUME_NONNULL_BEGIN + @interface NSMutableArray (STKAudioPlayer) -(void) enqueue:(id)obj; -(void) skipQueue:(id)obj; -(void) skipQueueWithQueue:(NSMutableArray*)queue; --(id) dequeue; --(id) peek; +-(nullable id) dequeue; +-(nullable id) peek; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.h b/StreamingKit/StreamingKit/STKAudioPlayer.h index cfd9af5..aa69469 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.h +++ b/StreamingKit/StreamingKit/STKAudioPlayer.h @@ -44,7 +44,9 @@ #include "UIKit/UIApplication.h" #endif -typedef enum +NS_ASSUME_NONNULL_BEGIN + +typedef NS_OPTIONS(NSInteger, STKAudioPlayerState) { STKAudioPlayerStateReady, STKAudioPlayerStateRunning = 1, @@ -54,10 +56,9 @@ typedef enum STKAudioPlayerStateStopped = (1 << 4), STKAudioPlayerStateError = (1 << 5), STKAudioPlayerStateDisposed = (1 << 6) -} -STKAudioPlayerState; +}; -typedef enum +typedef NS_ENUM(NSInteger, STKAudioPlayerStopReason) { STKAudioPlayerStopReasonNone = 0, STKAudioPlayerStopReasonEof, @@ -65,10 +66,9 @@ typedef enum STKAudioPlayerStopReasonPendingNext, STKAudioPlayerStopReasonDisposed, STKAudioPlayerStopReasonError = 0xffff -} -STKAudioPlayerStopReason; +}; -typedef enum +typedef NS_ENUM(NSInteger, STKAudioPlayerErrorCode) { STKAudioPlayerErrorNone = 0, STKAudioPlayerErrorDataSource, @@ -77,9 +77,13 @@ typedef enum STKAudioPlayerErrorCodecError, STKAudioPlayerErrorDataNotFound, STKAudioPlayerErrorOther = 0xffff -} -STKAudioPlayerErrorCode; +}; +/// +/// Options to initiailise the Audioplayer with. +/// By default if you set buffer size or seconds to 0, the non-zero default will be used +/// If you would like to disable the buffer option completely set to STK_DISABLE_BUFFER +/// typedef struct { /// If YES then seeking a track will cause all pending items to be flushed from the queue @@ -101,6 +105,8 @@ typedef struct } STKAudioPlayerOptions; +#define STK_DISABLE_BUFFER (0xffffffff) + typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, float* frames); @interface STKFrameFilterEntry : NSObject @@ -149,13 +155,13 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn /// Enables or disables the EQ @property (readwrite) BOOL equalizerEnabled; /// Returns an array of STKFrameFilterEntry objects representing the filters currently in use -@property (readonly) NSArray* frameFilters; +@property (readonly, nullable) NSArray* frameFilters; /// Returns the items pending to be played (includes buffering and upcoming items but does not include the current item) @property (readonly) NSArray* pendingQueue; /// The number of items pending to be played (includes buffering and upcoming items but does not include the current item) @property (readonly) NSUInteger pendingQueueCount; /// Gets the most recently queued item that is still pending to play -@property (readonly) NSObject* mostRecentlyQueuedStillPendingItem; +@property (readonly, nullable) NSObject* mostRecentlyQueuedStillPendingItem; /// Gets the current state of the player @property (readwrite) STKAudioPlayerState state; /// Gets the options provided to the player on startup @@ -172,10 +178,10 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn +(STKDataSource*) dataSourceFromURL:(NSURL*)url; /// Initializes a new STKAudioPlayer with the default options --(id) init; +-(instancetype) init; /// Initializes a new STKAudioPlayer with the given options --(id) initWithOptions:(STKAudioPlayerOptions)optionsIn; +-(instancetype) initWithOptions:(STKAudioPlayerOptions)optionsIn; /// Plays an item from the given URL string (all pending queued items are removed). /// The NSString is used as the queue item ID @@ -252,7 +258,7 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn /// Appends a frame filter with the given name and filter block just after the filter with the given name. /// If the given name is nil, the filter will be inserted at the beginning of the filter change --(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(NSString*)afterFilterWithName block:(STKFrameFilter)block; +-(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(nullable NSString*)afterFilterWithName block:(STKFrameFilter)block; /// Reads the peak power in decibals for the given channel (0 or 1). /// Return values are between -60 (low) and 0 (high). @@ -266,3 +272,5 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn -(void) setGain:(float)gain forEqualizerBand:(int)bandIndex; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 22564be..4ab5437 100755 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -65,7 +65,7 @@ #define STK_DEFAULT_GRACE_PERIOD_AFTER_SEEK_SECONDS (0.5) #define OSSTATUS_PRINTF_PLACEHOLDER @"%c%c%c%c" -#define OSSTATUS_PRINTF_VALUE(status) ((status) >> 24) & 0xFF, ((status) >> 16) & 0xFF, ((status) >> 8) & 0xFF, (status) & 0xFF +#define OSSTATUS_PRINTF_VALUE(status) (char)(((status) >> 24) & 0xFF), (char)(((status) >> 16) & 0xFF), (char)(((status) >> 8) & 0xFF), (char)((status) & 0xFF) #define LOGINFO(x) [self logInfo:[NSString stringWithFormat:@"%s %@", sel_getName(_cmd), x]]; @@ -97,6 +97,34 @@ static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options) } } +static void NormalizeDisabledBuffers(STKAudioPlayerOptions* options) +{ + if (options->bufferSizeInSeconds == STK_DISABLE_BUFFER) + { + options->bufferSizeInSeconds = 0; + } + + if (options->readBufferSize == STK_DISABLE_BUFFER) + { + options->readBufferSize = 0; + } + + if (options->secondsRequiredToStartPlaying == STK_DISABLE_BUFFER) + { + options->secondsRequiredToStartPlaying = 0; + } + + if (options->secondsRequiredToStartPlayingAfterBufferUnderun == STK_DISABLE_BUFFER) + { + options->secondsRequiredToStartPlayingAfterBufferUnderun = 0; + } + + if (options->gracePeriodAfterSeekInSeconds == STK_DISABLE_BUFFER) + { + options->gracePeriodAfterSeekInSeconds = 0; + } +} + #define CHECK_STATUS_AND_REPORT(call) \ if ((status = (call))) \ { \ @@ -146,7 +174,7 @@ STKAudioPlayerInternalState; @end @implementation STKFrameFilterEntry --(id) initWithFilter:(STKFrameFilter)filterIn andName:(NSString*)nameIn +-(instancetype) initWithFilter:(STKFrameFilter)filterIn andName:(NSString*)nameIn { if (self = [super init]) { @@ -480,12 +508,12 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn } } --(id) init +-(instancetype) init { return [self initWithOptions:(STKAudioPlayerOptions){}]; } --(id) initWithOptions:(STKAudioPlayerOptions)optionsIn +-(instancetype) initWithOptions:(STKAudioPlayerOptions)optionsIn { if (self = [super init]) { @@ -495,6 +523,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn self->equalizerEnabled = optionsIn.equalizerBandFrequencies[0] != 0; PopulateOptionsWithDefault(&options); + NormalizeDisabledBuffers(&options); framesRequiredToStartPlaying = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlaying; framesRequiredToPlayAfterRebuffering = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlayingAfterBufferUnderun; @@ -896,7 +925,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn } case kAudioFileStreamProperty_ReadyToProducePackets: { - if (!audioConverterAudioStreamBasicDescription.mFormatID == kAudioFormatLinearPCM) + if (audioConverterAudioStreamBasicDescription.mFormatID != kAudioFormatLinearPCM) { discontinuous = YES; } @@ -1966,10 +1995,8 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl [self destroyAudioConverter]; - //This breaks mono files - //canonicalAudioStreamBasicDescription.mChannelsPerFrame = asbd->mChannelsPerFrame; - BOOL isRecording = currentlyReadingEntry.dataSource.recordToFileUrl != nil; + if (isRecording) { recordAudioStreamBasicDescription = (AudioStreamBasicDescription) @@ -2432,6 +2459,9 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl } else if (!isRunning) { + stopReason = stopReasonIn; + self.internalState = STKAudioPlayerInternalStateStopped; + return; } diff --git a/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.h b/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.h index c55895f..bab707b 100644 --- a/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.h +++ b/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.h @@ -36,6 +36,8 @@ #import "STKHTTPDataSource.h" #import "STKDataSourceWrapper.h" +NS_ASSUME_NONNULL_BEGIN + typedef struct { int watchdogPeriodSeconds; @@ -45,8 +47,10 @@ STKAutoRecoveringHTTPDataSourceOptions; @interface STKAutoRecoveringHTTPDataSource : STKDataSourceWrapper --(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource; +-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource; @property (readonly) STKHTTPDataSource* innerDataSource; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.m b/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.m index 37fa5e5..8dfe3a8 100644 --- a/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.m +++ b/StreamingKit/StreamingKit/STKAutoRecoveringHTTPDataSource.m @@ -101,22 +101,24 @@ static void PopulateOptionsWithDefault(STKAutoRecoveringHTTPDataSourceOptions* o @implementation STKAutoRecoveringHTTPDataSource +@dynamic innerDataSource; + -(STKHTTPDataSource*) innerHTTPDataSource { return (STKHTTPDataSource*)self.innerDataSource; } --(id) initWithDataSource:(STKDataSource *)innerDataSource +-(instancetype) initWithDataSource:(STKDataSource *)innerDataSource { return [self initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource]; } --(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn +-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn { return [self initWithHTTPDataSource:innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions){}]; } --(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn +-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn { if (self = [super initWithDataSource:innerDataSourceIn]) { diff --git a/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h b/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h index b25a72e..b1dd325 100644 --- a/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h +++ b/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h @@ -34,6 +34,8 @@ #import "STKDataSource.h" +NS_ASSUME_NONNULL_BEGIN + @class STKCoreFoundationDataSource; @interface CoreFoundationDataSourceClientInfo : NSObject @@ -62,3 +64,5 @@ -(CFStreamStatus) status; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKDataSource.h b/StreamingKit/StreamingKit/STKDataSource.h index 8ca4150..0a1e716 100755 --- a/StreamingKit/StreamingKit/STKDataSource.h +++ b/StreamingKit/StreamingKit/STKDataSource.h @@ -35,6 +35,8 @@ #import #include +NS_ASSUME_NONNULL_BEGIN + @class STKDataSource; @protocol STKDataSourceDelegate @@ -50,8 +52,8 @@ @property (readonly) SInt64 length; @property (readonly) BOOL hasBytesAvailable; @property (nonatomic, readwrite, assign) double durationHint; -@property (readwrite, unsafe_unretained) id delegate; -@property (nonatomic, strong) NSURL *recordToFileUrl; +@property (readwrite, unsafe_unretained, nullable) id delegate; +@property (nonatomic, strong, nullable) NSURL *recordToFileUrl; -(BOOL) registerForEvents:(NSRunLoop*)runLoop; -(void) unregisterForEvents; @@ -62,3 +64,5 @@ -(AudioFileTypeID) audioFileTypeHint; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKDataSourceWrapper.h b/StreamingKit/StreamingKit/STKDataSourceWrapper.h index 4d3e035..cde9b73 100644 --- a/StreamingKit/StreamingKit/STKDataSourceWrapper.h +++ b/StreamingKit/StreamingKit/STKDataSourceWrapper.h @@ -34,10 +34,14 @@ #import "STKDataSource.h" +NS_ASSUME_NONNULL_BEGIN + @interface STKDataSourceWrapper : STKDataSource --(id) initWithDataSource:(STKDataSource*)innerDataSource; +-(instancetype) initWithDataSource:(STKDataSource*)innerDataSource; @property (readonly) STKDataSource* innerDataSource; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKDataSourceWrapper.m b/StreamingKit/StreamingKit/STKDataSourceWrapper.m index 76e1634..c75a499 100644 --- a/StreamingKit/StreamingKit/STKDataSourceWrapper.m +++ b/StreamingKit/StreamingKit/STKDataSourceWrapper.m @@ -40,7 +40,7 @@ @implementation STKDataSourceWrapper --(id) initWithDataSource:(STKDataSource*)innerDataSourceIn +-(instancetype) initWithDataSource:(STKDataSource*)innerDataSourceIn { if (self = [super init]) { diff --git a/StreamingKit/StreamingKit/STKHTTPDataSource.h b/StreamingKit/StreamingKit/STKHTTPDataSource.h index 9bf7002..691bbff 100644 --- a/StreamingKit/StreamingKit/STKHTTPDataSource.h +++ b/StreamingKit/StreamingKit/STKHTTPDataSource.h @@ -34,10 +34,12 @@ #import "STKCoreFoundationDataSource.h" +NS_ASSUME_NONNULL_BEGIN + @class STKHTTPDataSource; typedef void(^STKURLBlock)(NSURL* url); -typedef NSURL*(^STKURLProvider)(); +typedef NSURL* _Nonnull (^STKURLProvider)(); typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock callback); @interface STKHTTPDataSource : STKCoreFoundationDataSource @@ -46,11 +48,13 @@ typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek, @property (readonly) UInt32 httpStatusCode; +(AudioFileTypeID) audioFileTypeHintFromMimeType:(NSString*)fileExtension; --(id) initWithURL:(NSURL*)url; --(id) initWithURL:(NSURL *)url httpRequestHeaders:(NSDictionary *)httpRequestHeaders; --(id) initWithURLProvider:(STKURLProvider)urlProvider; --(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider; --(NSRunLoop*) eventsRunLoop; +-(instancetype) initWithURL:(NSURL*)url; +-(instancetype) initWithURL:(NSURL*)url httpRequestHeaders:(NSDictionary*)httpRequestHeaders; +-(instancetype) initWithURLProvider:(STKURLProvider)urlProvider; +-(instancetype) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider; +-(nullable NSRunLoop*) eventsRunLoop; -(void) reconnect; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKHTTPDataSource.m b/StreamingKit/StreamingKit/STKHTTPDataSource.m index bd66ab5..7af8686 100755 --- a/StreamingKit/StreamingKit/STKHTTPDataSource.m +++ b/StreamingKit/StreamingKit/STKHTTPDataSource.m @@ -64,19 +64,19 @@ @implementation STKHTTPDataSource --(id) initWithURL:(NSURL*)urlIn +-(instancetype) initWithURL:(NSURL*)urlIn { return [self initWithURLProvider:^NSURL* { return urlIn; }]; } --(id) initWithURL:(NSURL *)urlIn httpRequestHeaders:(NSDictionary *)httpRequestHeaders +-(instancetype) initWithURL:(NSURL *)urlIn httpRequestHeaders:(NSDictionary *)httpRequestHeaders { self = [self initWithURLProvider:^NSURL* { return urlIn; }]; self->requestHeaders = httpRequestHeaders; return self; } --(id) initWithURLProvider:(STKURLProvider)urlProviderIn +-(instancetype) initWithURLProvider:(STKURLProvider)urlProviderIn { urlProviderIn = [urlProviderIn copy]; @@ -86,7 +86,7 @@ }]; } --(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn +-(instancetype) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn { if (self = [super init]) { @@ -411,7 +411,7 @@ eventsRunLoop = savedEventsRunLoop; - [self seekToOffset:self.position]; + [self seekToOffset:self->supportsSeek ? self.position : 0]; } -(void) seekToOffset:(SInt64)offset diff --git a/StreamingKit/StreamingKit/STKLocalFileDataSource.h b/StreamingKit/StreamingKit/STKLocalFileDataSource.h index 2a5f571..581f42d 100644 --- a/StreamingKit/StreamingKit/STKLocalFileDataSource.h +++ b/StreamingKit/StreamingKit/STKLocalFileDataSource.h @@ -34,10 +34,14 @@ #import "STKCoreFoundationDataSource.h" +NS_ASSUME_NONNULL_BEGIN + @interface STKLocalFileDataSource : STKCoreFoundationDataSource +(AudioFileTypeID) audioFileTypeHintFromFileExtension:(NSString*)fileExtension; @property (readonly, copy) NSString* filePath; --(id) initWithFilePath:(NSString*)filePath; +-(instancetype) initWithFilePath:(NSString*)filePath; @end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKLocalFileDataSource.m b/StreamingKit/StreamingKit/STKLocalFileDataSource.m index 1362cc2..fb573f8 100644 --- a/StreamingKit/StreamingKit/STKLocalFileDataSource.m +++ b/StreamingKit/StreamingKit/STKLocalFileDataSource.m @@ -47,7 +47,7 @@ @implementation STKLocalFileDataSource @synthesize filePath; --(id) initWithFilePath:(NSString*)filePathIn +-(instancetype) initWithFilePath:(NSString*)filePathIn { if (self = [super init]) { diff --git a/StreamingKit/StreamingKit/STKQueueEntry.h b/StreamingKit/StreamingKit/STKQueueEntry.h index 3ae6f6a..f13d277 100755 --- a/StreamingKit/StreamingKit/STKQueueEntry.h +++ b/StreamingKit/StreamingKit/STKQueueEntry.h @@ -10,6 +10,8 @@ #import "libkern/OSAtomic.h" #import "AudioToolbox/AudioToolbox.h" +NS_ASSUME_NONNULL_BEGIN + @interface STKQueueEntry : NSObject { @public @@ -35,7 +37,7 @@ @property (readwrite, retain) NSObject* queueItemId; @property (readwrite, retain) STKDataSource* dataSource; --(id) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId; +-(instancetype) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId; -(void) reset; -(double) duration; @@ -43,4 +45,6 @@ -(double) calculatedBitRate; -(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription; -@end \ No newline at end of file +@end + +NS_ASSUME_NONNULL_END diff --git a/StreamingKit/StreamingKit/STKQueueEntry.m b/StreamingKit/StreamingKit/STKQueueEntry.m index 7c2ca4a..330e918 100755 --- a/StreamingKit/StreamingKit/STKQueueEntry.m +++ b/StreamingKit/StreamingKit/STKQueueEntry.m @@ -14,7 +14,7 @@ @implementation STKQueueEntry --(id) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn +-(instancetype) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn { if (self = [super init]) { @@ -121,4 +121,4 @@ return [[self queueItemId] description]; } -@end \ No newline at end of file +@end diff --git a/StreamingKit/StreamingKitMacTests/StreamingKitMacTests-Info.plist b/StreamingKit/StreamingKitMacTests/StreamingKitMacTests-Info.plist index 552d5b1..169b6f7 100644 --- a/StreamingKit/StreamingKitMacTests/StreamingKitMacTests-Info.plist +++ b/StreamingKit/StreamingKitMacTests/StreamingKitMacTests-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.abstractpath.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType diff --git a/StreamingKit/StreamingKitTests/StreamingKitTests-Info.plist b/StreamingKit/StreamingKitTests/StreamingKitTests-Info.plist index 12b70c6..169b6f7 100644 --- a/StreamingKit/StreamingKitTests/StreamingKitTests-Info.plist +++ b/StreamingKit/StreamingKitTests/StreamingKitTests-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - abstractpath.com.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType