Compare commits

..

2 Commits

Author SHA1 Message Date
Thong Nguyen e805e4740c More Spectrum Analyzer work 2014-04-24 18:22:40 +01:00
Thong Nguyen 484285df84 Started work on Spectrum Analyzer 2014-04-23 18:03:23 +01:00
48 changed files with 718 additions and 2032 deletions
-2
View File
@@ -24,5 +24,3 @@ Icon?
ehthumbs.db
Thumbs.db
xcuserdata
xcshareddata
*.idea
+9 -127
View File
@@ -27,44 +27,10 @@
A17FFB6318A0028300BAA7FF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A17FFB6218A0028300BAA7FF /* AudioToolbox.framework */; };
A17FFB6918A002E400BAA7FF /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F5E491189EB3F20070B03F /* AVFoundation.framework */; };
A1EBEE64188DE34500681B04 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1EBEE63188DE34500681B04 /* SystemConfiguration.framework */; };
A1F3410A1908185900CA7755 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F341091908185900CA7755 /* Accelerate.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
1D5086651A711D060030B19C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A1E7C4C8188D57F50010896F;
remoteInfo = StreamingKit;
};
1D5086671A711D060030B19C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A1E7C4D8188D57F60010896F;
remoteInfo = StreamingKitTests;
};
1D5086691A711D060030B19C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A1A49969189E744400E2A2E2;
remoteInfo = StreamingKitMac;
};
1D50866B1A711D060030B19C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A1A4997A189E744500E2A2E2;
remoteInfo = StreamingKitMacTests;
};
1D50866D1A711D160030B19C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = A1E7C4C7188D57F50010896F;
remoteInfo = StreamingKit;
};
A1115951188D686000641365 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A1115929188D686000641365 /* Project object */;
@@ -75,7 +41,6 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = StreamingKit.xcodeproj; path = ../StreamingKit/StreamingKit.xcodeproj; sourceTree = "<group>"; };
A1115931188D686000641365 /* ExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
A1115934188D686000641365 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
A1115936188D686000641365 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -101,6 +66,7 @@
A142571C18907861005F0129 /* airplane.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = airplane.aac; sourceTree = "<group>"; };
A17FFB6218A0028300BAA7FF /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
A1EBEE63188DE34500681B04 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
A1F341091908185900CA7755 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
A1F5E48F189EB3CB0070B03F /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
A1F5E491189EB3F20070B03F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
@@ -110,6 +76,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1F3410A1908185900CA7755 /* Accelerate.framework in Frameworks */,
A17FFB6918A002E400BAA7FF /* AVFoundation.framework in Frameworks */,
A17FFB6318A0028300BAA7FF /* AudioToolbox.framework in Frameworks */,
A1EBEE64188DE34500681B04 /* SystemConfiguration.framework in Frameworks */,
@@ -133,17 +100,6 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1D50865E1A711D050030B19C /* Products */ = {
isa = PBXGroup;
children = (
1D5086661A711D060030B19C /* libStreamingKit.a */,
1D5086681A711D060030B19C /* StreamingKitTests.xctest */,
1D50866A1A711D060030B19C /* libStreamingKitMac.a */,
1D50866C1A711D060030B19C /* StreamingKitMacTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
A1115928188D686000641365 = {
isa = PBXGroup;
children = (
@@ -166,7 +122,7 @@
A1115933188D686000641365 /* Frameworks */ = {
isa = PBXGroup;
children = (
1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */,
A1F341091908185900CA7755 /* Accelerate.framework */,
A17FFB6218A0028300BAA7FF /* AudioToolbox.framework */,
A1F5E491189EB3F20070B03F /* AVFoundation.framework */,
A1F5E48F189EB3CB0070B03F /* AudioUnit.framework */,
@@ -248,7 +204,6 @@
buildRules = (
);
dependencies = (
1D50866E1A711D160030B19C /* PBXTargetDependency */,
);
name = ExampleApp;
productName = ExampleApp;
@@ -279,7 +234,7 @@
A1115929188D686000641365 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
LastUpgradeCheck = 0510;
ORGANIZATIONNAME = "Thong Nguyen";
TargetAttributes = {
A111594B188D686000641365 = {
@@ -297,12 +252,6 @@
mainGroup = A1115928188D686000641365;
productRefGroup = A1115932188D686000641365 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 1D50865E1A711D050030B19C /* Products */;
ProjectRef = 1D50865D1A711D050030B19C /* StreamingKit.xcodeproj */;
},
);
projectRoot = "";
targets = (
A1115930188D686000641365 /* ExampleApp */,
@@ -311,37 +260,6 @@
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
1D5086661A711D060030B19C /* libStreamingKit.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libStreamingKit.a;
remoteRef = 1D5086651A711D060030B19C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
1D5086681A711D060030B19C /* StreamingKitTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = StreamingKitTests.xctest;
remoteRef = 1D5086671A711D060030B19C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
1D50866A1A711D060030B19C /* libStreamingKitMac.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libStreamingKitMac.a;
remoteRef = 1D5086691A711D060030B19C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
1D50866C1A711D060030B19C /* StreamingKitMacTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = StreamingKitMacTests.xctest;
remoteRef = 1D50866B1A711D060030B19C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
A111592F188D686000641365 /* Resources */ = {
isa = PBXResourcesBuildPhase;
@@ -387,11 +305,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
1D50866E1A711D160030B19C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = StreamingKit;
targetProxy = 1D50866D1A711D160030B19C /* PBXContainerItemProxy */;
};
A1115952188D686000641365 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = A1115930188D686000641365 /* ExampleApp */;
@@ -427,32 +340,18 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -470,7 +369,7 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -485,31 +384,18 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -521,7 +407,7 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
@@ -537,10 +423,9 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch";
INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
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;
};
@@ -554,10 +439,9 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch";
INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
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;
};
@@ -579,7 +463,6 @@
"$(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;
@@ -598,7 +481,6 @@
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;
+8 -17
View File
@@ -24,21 +24,21 @@
-(BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
NSError* error;
Float32 bufferLength = 0.1;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
[[AVAudioSession sharedInstance] setPreferredIOBufferDuration:bufferLength error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
Float32 bufferLength = 0.1;
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];
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = NO, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} }];
audioPlayer.meteringEnabled = YES;
audioPlayer.volume = 1;
AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds andAudioPlayer:audioPlayer];
audioPlayerView.delegate = self;
@@ -46,9 +46,9 @@
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[self.window addSubview:audioPlayerView];
[self.window makeKeyAndVisible];
[self.window.rootViewController.view addSubview:audioPlayerView];
return YES;
}
@@ -60,22 +60,13 @@
-(void) audioPlayerViewPlayFromHTTPSelected:(AudioPlayerView*)audioPlayerView
{
NSURL* url = [NSURL URLWithString:@"http://www.abstractpath.com/files/audiosamples/sample.mp3"];
NSURL* url = [NSURL URLWithString:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
[audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
}
-(void) audioPlayerViewPlayFromIcecastSelected:(AudioPlayerView *)audioPlayerView
{
NSURL* url = [NSURL URLWithString:@"http://nashe.streamr.ru/jazz-128.mp3"];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
[audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
}
-(void) audioPlayerViewQueueShortFileSelected:(AudioPlayerView*)audioPlayerView
{
NSString* path = [[NSBundle mainBundle] pathForResource:@"airplane" ofType:@"aac"];
@@ -98,7 +89,7 @@
-(void) audioPlayerViewQueuePcmWaveFileSelected:(AudioPlayerView*)audioPlayerView
{
NSURL* url = [NSURL URLWithString:@"http://www.abstractpath.com/files/audiosamples/perfectly.wav"];
NSURL* url = [NSURL URLWithString:@"http://fs.bloom.fm/oss/audiosamples/perfectly.wav"];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
-3
View File
@@ -39,7 +39,6 @@
@protocol AudioPlayerViewDelegate<NSObject>
-(void) audioPlayerViewPlayFromHTTPSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewPlayFromIcecastSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewQueueShortFileSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewPlayFromLocalFileSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewQueuePcmWaveFileSelected:(AudioPlayerView*)audioPlayerView;
@@ -50,7 +49,6 @@
@private
NSTimer* timer;
UILabel* label;
UILabel* metadataLabel;
UILabel* statusLabel;
UISlider* slider;
UISwitch* enableEqSwitch;
@@ -59,7 +57,6 @@
UIButton* playButton;
UIButton* stopButton;
UIButton* playFromHTTPButton;
UIButton* playFromIcecastButton;
UIButton* queueShortFileButton;
UIButton* queuePcmWaveFileFromHTTPButton;
UIButton* playFromLocalFileButton;
+41 -53
View File
@@ -40,6 +40,9 @@
///
@interface AudioPlayerView()
{
NSMutableArray* meters;
}
-(void) setupTimer;
-(void) updateControls;
@end
@@ -55,50 +58,47 @@
{
self.audioPlayer = audioPlayerIn;
self.audioPlayer.spectrumAnalyzerEnabled = YES;
CGSize size = CGSizeMake(220, 50);
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromHTTPButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10, size.width, size.height);
playFromHTTPButton.frame = CGRectMake((320 - 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((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((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height);
playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 50, 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((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height);
queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 100, 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((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height);
queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 150, size.width, size.height);
[queuePcmWaveFileFromHTTPButton addTarget:self action:@selector(queuePcmWaveFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[queuePcmWaveFileFromHTTPButton setTitle:@"Queue PCM/WAVE from HTTP" forState:UIControlStateNormal];
size = CGSizeMake(90, 40);
playButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playButton.frame = CGRectMake(30, 400, size.width, size.height);
playButton.frame = CGRectMake(30, 380, size.width, size.height);
[playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside];
stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
stopButton.frame = CGRectMake((frame.size.width - size.width) - 30, 400, size.width, size.height);
stopButton.frame = CGRectMake((320 - size.width) - 30, 380, size.width, size.height);
[stopButton addTarget:self action:@selector(stopButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[stopButton setTitle:@"Stop" forState:UIControlStateNormal];
muteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
muteButton.frame = CGRectMake((frame.size.width - size.width) - 30, 430, size.width, size.height);
muteButton.frame = CGRectMake((320 - size.width) - 30, 410, size.width, size.height);
[muteButton addTarget:self action:@selector(muteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[muteButton setTitle:@"Mute" forState:UIControlStateNormal];
slider = [[UISlider alloc] initWithFrame:CGRectMake(20, 320, queuePcmWaveFileFromHTTPButton.frame.origin.y + queuePcmWaveFileFromHTTPButton.frame.size.height + 20, 20)];
slider = [[UISlider alloc] initWithFrame:CGRectMake(20, 320, 280, 20)];
slider.continuous = YES;
[slider addTarget:self action:@selector(sliderChanged) forControlEvents:UIControlEventValueChanged];
@@ -106,37 +106,44 @@
repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(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 = [[UISwitch alloc] initWithFrame:CGRectMake(320 - 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];
metadataLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 10, frame.size.width, 25)];
metadataLabel.textAlignment = NSTextAlignmentCenter;
metadataLabel.font = [UIFont boldSystemFontOfSize:17.0f];
label = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 40, frame.size.width, 25)];
label = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 10, frame.size.width, 25)];
label.textAlignment = NSTextAlignmentCenter;
statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + label.frame.size.height + 50, frame.size.width, 50)];
statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + label.frame.size.height + 8, frame.size.width, 50)];
statusLabel.textAlignment = NSTextAlignmentCenter;
meters = [[NSMutableArray alloc] init];
meter = [[UIView alloc] initWithFrame:CGRectMake(0, 450, 0, 20)];
meter.backgroundColor = [UIColor greenColor];
for (int i = 0; i < 256; i++)
{
UIView* freqMeter = [[UIView alloc] initWithFrame:CGRectMake(i, self.bounds.size.height, 1, 0)];
freqMeter.backgroundColor = [UIColor blueColor];
[self addSubview:freqMeter];
[meters addObject:freqMeter];
[self sendSubviewToBack:freqMeter];
}
[self addSubview:slider];
[self addSubview:playButton];
[self addSubview:playFromHTTPButton];
[self addSubview:playFromIcecastButton];
[self addSubview:playFromLocalFileButton];
[self addSubview:queueShortFileButton];
[self addSubview:queuePcmWaveFileFromHTTPButton];
[self addSubview:repeatSwitch];
[self addSubview:metadataLabel];
[self addSubview:label];
[self addSubview:statusLabel];
[self addSubview:stopButton];
@@ -186,17 +193,6 @@
return;
}
if (audioPlayer.currentlyPlayingQueueItemId == nil)
{
slider.value = 0;
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = @"";
return;
}
if (audioPlayer.duration != 0)
{
slider.minimumValue = 0;
@@ -211,44 +207,43 @@
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = [NSString stringWithFormat:@"Live stream %@", [self formatTimeFromSeconds:audioPlayer.progress]];
label.text = @"";
}
statusLabel.text = audioPlayer.state == STKAudioPlayerStateBuffering ? @"buffering" : @"";
CGFloat newWidth = 320 * (([audioPlayer averagePowerInDecibelsForChannel:1] + 60) / 60);
CGFloat newWidth = 320 * (([audioPlayer testPowerWithIndex:100] + 96) / 96);
meter.frame = CGRectMake(0, 460, newWidth, 20);
for (int i = 0; i < 256; i++)
{
UIView* freqMeter = [meters objectAtIndex:i];
CGFloat height = 200 * (([audioPlayer testPowerWithIndex:i] + 96) / 96);
freqMeter.frame = CGRectMake(freqMeter.frame.origin.x, self.bounds.size.height - height, 1, height);
}
}
-(void) playFromHTTPButtonTouched
{
[self.delegate audioPlayerViewPlayFromHTTPSelected:self];
metadataLabel.text = nil;
}
-(void) playFromIcecasButtonTouched
{
[self.delegate audioPlayerViewPlayFromIcecastSelected:self];
metadataLabel.text = nil;
}
-(void) playFromLocalFileButtonTouched
{
[self.delegate audioPlayerViewPlayFromLocalFileSelected:self];
metadataLabel.text = nil;
}
-(void) queueShortFileButtonTouched
{
[self.delegate audioPlayerViewQueueShortFileSelected:self];
metadataLabel.text = nil;
}
-(void) queuePcmWaveFileButtonTouched
{
[self.delegate audioPlayerViewQueuePcmWaveFileSelected:self];
metadataLabel.text = nil;
}
-(void) muteButtonPressed
@@ -386,11 +381,4 @@
NSLog(@"%@", line);
}
- (void)audioPlayer:(STKAudioPlayer *)audioPlayer didReadStreamMetadata:(NSDictionary *)dictionary
{
dispatch_async(dispatch_get_main_queue(), ^{
self->metadataLabel.text = dictionary[@"StreamTitle"];
});
}
@end
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>abstractpath.com.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -5,31 +5,16 @@
"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",
@@ -1,6 +0,0 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -1,31 +1,5 @@
{
"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",
@@ -34,12 +8,11 @@
"scale" : "2x"
},
{
"extent" : "full-screen",
"orientation" : "portrait",
"idiom" : "iphone",
"subtype" : "retina4",
"filename" : "TX6sV-2.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
@@ -69,26 +42,6 @@
"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" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>abstractpath.com.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
@@ -238,7 +238,7 @@
A1A49999189E765800E2A2E2 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
LastUpgradeCheck = 0500;
ORGANIZATIONNAME = "Thong Nguyen";
TargetAttributes = {
A1A499C1189E765800E2A2E2 = {
@@ -358,32 +358,18 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -396,7 +382,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
@@ -409,39 +395,26 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.9;
SDKROOT = macosx;
};
name = Release;
@@ -459,8 +432,8 @@
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
INFOPLIST_FILE = "ExampleAppMac/ExampleAppMac-Info.plist";
MACOSX_DEPLOYMENT_TARGET = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -479,8 +452,8 @@
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
INFOPLIST_FILE = "ExampleAppMac/ExampleAppMac-Info.plist";
MACOSX_DEPLOYMENT_TARGET = "";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -503,7 +476,6 @@
);
INFOPLIST_FILE = "ExampleAppMacTests/ExampleAppMacTests-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
@@ -523,7 +495,6 @@
GCC_PREFIX_HEADER = "ExampleAppMac/ExampleAppMac-Prefix.pch";
INFOPLIST_FILE = "ExampleAppMacTests/ExampleAppMacTests-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
@@ -10,29 +10,29 @@
<string>ExampleAppMac</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>3E9414865BAE5433092B9D136FFC1F054EA505C2</key>
<key>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</key>
<string>https://github.com/tumtumtum/StreamingKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>ExampleAppMac/ExampleAppMac.xcodeproj</string>
<string>ExampleAppMac/ExampleAppMac.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>3E9414865BAE5433092B9D136FFC1F054EA505C2</key>
<key>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</key>
<string>../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>https://github.com/tumtumtum/StreamingKit.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<integer>110</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>3E9414865BAE5433092B9D136FFC1F054EA505C2</string>
<string>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>3E9414865BAE5433092B9D136FFC1F054EA505C2</string>
<string>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</string>
<key>IDESourceControlWCCName</key>
<string>StreamingKit</string>
</dict>
+14 -62
View File
@@ -14,7 +14,6 @@
NSView* meter;
NSSlider* slider;
STKAudioPlayer* audioPlayer;
NSTextField* textField;
}
@end
@@ -22,67 +21,26 @@
-(void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSButton* playFromHTTPButton = [[NSButton alloc] init];
CGRect frame = [self.window.contentView frame];
NSButton* playFromHTTPButton = [[NSButton alloc] initWithFrame:CGRectMake(10, 10, frame.size.width - 20, 100)];
[playFromHTTPButton setTitle:@"Play from HTTP"];
[playFromHTTPButton setAction:@selector(playFromHTTP)];
NSButton* stopButton = [[NSButton alloc] init];
[stopButton setTitle:@"Stop"];
[stopButton setAction:@selector(stopPlaying)];
NSStackView *buttonStackView = [[NSStackView alloc] initWithFrame:self.window.contentView.frame];
[buttonStackView setDistribution:NSStackViewDistributionFillEqually];
[buttonStackView setSpacing:8];
[buttonStackView setOrientation:NSUserInterfaceLayoutOrientationHorizontal];
[buttonStackView addArrangedSubview:playFromHTTPButton];
[buttonStackView addArrangedSubview:stopButton];
slider = [[NSSlider alloc] init];
[slider setTranslatesAutoresizingMaskIntoConstraints:false];
slider = [[NSSlider alloc] initWithFrame:CGRectMake(10, 140, frame.size.width - 20, 20)];
[slider setAction:@selector(sliderChanged:)];
meter = [[NSView alloc] init];
[meter setTranslatesAutoresizingMaskIntoConstraints:false];
meter = [[NSView alloc] initWithFrame:CGRectMake(10, 200, 0, 20)];
[meter setLayer:[CALayer new]];
[meter setWantsLayer:YES];
meter.layer.backgroundColor = [NSColor greenColor].CGColor;
NSView *meterWrapper = [[NSView alloc] init];
[meterWrapper setTranslatesAutoresizingMaskIntoConstraints:false];
[meterWrapper addSubview:meter];
textField = [[NSTextField alloc] init];
[textField setTranslatesAutoresizingMaskIntoConstraints:false];
textField.stringValue = @"http://www.abstractpath.com/files/audiosamples/sample.mp3";
NSStackView *stackView = [[NSStackView alloc] initWithFrame:self.window.contentView.frame];
[stackView setTranslatesAutoresizingMaskIntoConstraints:false];
[stackView setDistribution:NSStackViewDistributionEqualSpacing];
[stackView setSpacing:8];
[stackView setOrientation:NSUserInterfaceLayoutOrientationVertical];
[stackView addArrangedSubview:textField];
[stackView addArrangedSubview:meterWrapper];
[stackView addArrangedSubview:slider];
[stackView addArrangedSubview:buttonStackView];
[[self.window contentView] addSubview:stackView];
[stackView.topAnchor constraintEqualToAnchor:self.window.contentView.topAnchor constant:16].active = true;
[stackView.bottomAnchor constraintEqualToAnchor:self.window.contentView.bottomAnchor constant:-16].active = true;
[stackView.rightAnchor constraintEqualToAnchor:self.window.contentView.rightAnchor constant:-16].active = true;
[stackView.leftAnchor constraintEqualToAnchor:self.window.contentView.leftAnchor constant:16].active = true;
[meter.topAnchor constraintEqualToAnchor:meterWrapper.topAnchor].active = true;
[meter.bottomAnchor constraintEqualToAnchor:meterWrapper.bottomAnchor].active = true;
[meter.leadingAnchor constraintEqualToAnchor:meterWrapper.leadingAnchor].active = true;
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions)
{
.enableVolumeMixer = NO,
.equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000}
}];
[[self.window contentView] addSubview:slider];
[[self.window contentView] addSubview:playFromHTTPButton];
[[self.window contentView] addSubview:meter];
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .enableVolumeMixer = NO, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} } ];
audioPlayer.delegate = self;
audioPlayer.meteringEnabled = YES;
audioPlayer.volume = 0.1;
@@ -100,13 +58,7 @@
-(void) playFromHTTP
{
[audioPlayer play:textField.stringValue];
audioPlayer.rate = 2;
}
- (void) stopPlaying
{
[audioPlayer stop];
[audioPlayer play:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
}
-(void) tick:(NSTimer*)timer
@@ -120,7 +72,7 @@
CGFloat meterWidth = 0;
if (audioPlayer.currentlyPlayingQueueItemId != nil)
if (audioPlayer.duration != 0)
{
slider.minValue = 0;
slider.maxValue = audioPlayer.duration;
@@ -1,17 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4439" systemVersion="13A451" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4439"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<action selector="orderFrontStandardAboutPanel:" destination="58" id="142"/>
<outlet property="delegate" destination="494" id="495"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder">
<connections>
<action selector="alignCenter:" destination="499" id="518"/>
<action selector="alignJustified:" destination="500" id="523"/>
<action selector="alignLeft:" destination="498" id="524"/>
<action selector="alignRight:" destination="501" id="521"/>
<action selector="arrangeInFront:" destination="5" id="39"/>
<action selector="capitalizeWord:" destination="466" id="467"/>
<action selector="centerSelectionInVisibleArea:" destination="210" id="245"/>
<action selector="checkSpelling:" destination="201" id="225"/>
<action selector="clearRecentDocuments:" destination="126" id="127"/>
<action selector="copy:" destination="197" id="224"/>
<action selector="copyFont:" destination="403" id="428"/>
<action selector="copyRuler:" destination="506" id="522"/>
<action selector="cut:" destination="199" id="228"/>
<action selector="delete:" destination="202" id="235"/>
<action selector="hide:" destination="134" id="367"/>
<action selector="hideOtherApplications:" destination="145" id="368"/>
<action selector="loosenKerning:" destination="419" id="435"/>
<action selector="lowerBaseline:" destination="410" id="427"/>
<action selector="lowercaseWord:" destination="465" id="468"/>
<action selector="makeBaseWritingDirectionLeftToRight:" destination="511" id="526"/>
<action selector="makeBaseWritingDirectionNatural:" destination="510" id="525"/>
<action selector="makeBaseWritingDirectionRightToLeft:" destination="512" id="527"/>
<action selector="makeTextWritingDirectionLeftToRight:" destination="516" id="529"/>
<action selector="makeTextWritingDirectionNatural:" destination="515" id="528"/>
<action selector="makeTextWritingDirectionRightToLeft:" destination="517" id="530"/>
<action selector="newDocument:" destination="82" id="373"/>
<action selector="openDocument:" destination="72" id="374"/>
<action selector="orderFrontColorPanel:" destination="401" id="433"/>
<action selector="orderFrontSubstitutionsPanel:" destination="457" id="458"/>
<action selector="paste:" destination="203" id="226"/>
<action selector="pasteAsPlainText:" destination="485" id="486"/>
<action selector="pasteFont:" destination="404" id="436"/>
<action selector="pasteRuler:" destination="507" id="519"/>
<action selector="performClose:" destination="73" id="193"/>
<action selector="performFindPanelAction:" destination="209" id="241"/>
<action selector="performFindPanelAction:" destination="208" id="487"/>
<action selector="performFindPanelAction:" destination="213" id="488"/>
<action selector="performFindPanelAction:" destination="221" id="489"/>
<action selector="performFindPanelAction:" destination="534" id="535"/>
<action selector="performMiniaturize:" destination="23" id="37"/>
<action selector="performZoom:" destination="239" id="240"/>
<action selector="print:" destination="78" id="86"/>
<action selector="raiseBaseline:" destination="409" id="426"/>
<action selector="redo:" destination="215" id="231"/>
<action selector="revertDocumentToSaved:" destination="112" id="364"/>
<action selector="runPageLayout:" destination="77" id="87"/>
<action selector="runToolbarCustomizationPalette:" destination="298" id="365"/>
<action selector="saveDocument:" destination="75" id="362"/>
<action selector="selectAll:" destination="198" id="232"/>
<action selector="showGuessPanel:" destination="204" id="230"/>
<action selector="showHelp:" destination="492" id="493"/>
<action selector="startSpeaking:" destination="196" id="233"/>
<action selector="stopSpeaking:" destination="195" id="227"/>
<action selector="subscript:" destination="408" id="429"/>
<action selector="superscript:" destination="407" id="430"/>
<action selector="tightenKerning:" destination="418" id="431"/>
<action selector="toggleAutomaticDashSubstitution:" destination="460" id="461"/>
<action selector="toggleAutomaticLinkDetection:" destination="354" id="357"/>
<action selector="toggleAutomaticQuoteSubstitution:" destination="351" id="356"/>
<action selector="toggleAutomaticSpellingCorrection:" destination="454" id="456"/>
<action selector="toggleAutomaticTextReplacement:" destination="462" id="463"/>
<action selector="toggleContinuousSpellChecking:" destination="219" id="222"/>
<action selector="toggleGrammarChecking:" destination="346" id="347"/>
<action selector="toggleRuler:" destination="505" id="520"/>
<action selector="toggleSmartInsertDelete:" destination="350" id="355"/>
<action selector="toggleToolbarShown:" destination="297" id="366"/>
<action selector="turnOffKerning:" destination="417" id="441"/>
<action selector="turnOffLigatures:" destination="413" id="440"/>
<action selector="underline:" destination="392" id="432"/>
<action selector="undo:" destination="207" id="223"/>
<action selector="unhideAllApplications:" destination="150" id="370"/>
<action selector="unscript:" destination="406" id="437"/>
<action selector="uppercaseWord:" destination="452" id="464"/>
<action selector="useAllLigatures:" destination="414" id="434"/>
<action selector="useStandardKerning:" destination="416" id="438"/>
<action selector="useStandardLigatures:" destination="412" id="439"/>
</connections>
</customObject>
<customObject id="-3" userLabel="Application">
<connections>
<action selector="terminate:" destination="136" id="449"/>
</connections>
</customObject>
<menu title="AMainMenu" systemMenu="main" id="29">
<items>
<menuItem title="ExampleAppMac" id="56">
@@ -19,9 +102,6 @@
<items>
<menuItem title="About ExampleAppMac" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="236">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
@@ -36,211 +116,95 @@
<menuItem isSeparatorItem="YES" id="144">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Hide ExampleAppMac" keyEquivalent="h" id="134">
<connections>
<action selector="hide:" target="-1" id="367"/>
</connections>
</menuItem>
<menuItem title="Hide ExampleAppMac" keyEquivalent="h" id="134"/>
<menuItem title="Hide Others" keyEquivalent="h" id="145">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="368"/>
</connections>
</menuItem>
<menuItem title="Show All" id="150">
<connections>
<action selector="unhideAllApplications:" target="-1" id="370"/>
</connections>
</menuItem>
<menuItem title="Show All" id="150"/>
<menuItem isSeparatorItem="YES" id="149">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Quit ExampleAppMac" keyEquivalent="q" id="136">
<connections>
<action selector="terminate:" target="-3" id="449"/>
</connections>
</menuItem>
<menuItem title="Quit ExampleAppMac" keyEquivalent="q" id="136"/>
</items>
</menu>
</menuItem>
<menuItem title="File" id="83">
<menu key="submenu" title="File" id="81">
<items>
<menuItem title="New" keyEquivalent="n" id="82">
<connections>
<action selector="newDocument:" target="-1" id="373"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="72">
<connections>
<action selector="openDocument:" target="-1" id="374"/>
</connections>
</menuItem>
<menuItem title="New" keyEquivalent="n" id="82"/>
<menuItem title="Open…" keyEquivalent="o" id="72"/>
<menuItem title="Open Recent" id="124">
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="125">
<items>
<menuItem title="Clear Menu" id="126">
<connections>
<action selector="clearRecentDocuments:" target="-1" id="127"/>
</connections>
</menuItem>
<menuItem title="Clear Menu" id="126"/>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="79">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Close" keyEquivalent="w" id="73">
<connections>
<action selector="performClose:" target="-1" id="193"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="75">
<connections>
<action selector="saveDocument:" target="-1" id="362"/>
</connections>
</menuItem>
<menuItem title="Close" keyEquivalent="w" id="73"/>
<menuItem title="Save…" keyEquivalent="s" id="75"/>
<menuItem title="Revert to Saved" id="112">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="364"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="74">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Page Setup..." keyEquivalent="P" id="77">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="87"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="78">
<connections>
<action selector="print:" target="-1" id="86"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="78"/>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="217">
<menu key="submenu" title="Edit" id="205">
<items>
<menuItem title="Undo" keyEquivalent="z" id="207">
<connections>
<action selector="undo:" target="-1" id="223"/>
</connections>
</menuItem>
<menuItem title="Undo" keyEquivalent="z" id="207"/>
<menuItem title="Redo" keyEquivalent="Z" id="215">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="redo:" target="-1" id="231"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="206">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Cut" keyEquivalent="x" id="199">
<connections>
<action selector="cut:" target="-1" id="228"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="197">
<connections>
<action selector="copy:" target="-1" id="224"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="203">
<connections>
<action selector="paste:" target="-1" id="226"/>
</connections>
</menuItem>
<menuItem title="Cut" keyEquivalent="x" id="199"/>
<menuItem title="Copy" keyEquivalent="c" id="197"/>
<menuItem title="Paste" keyEquivalent="v" id="203"/>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="485">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="486"/>
</connections>
</menuItem>
<menuItem title="Delete" id="202">
<connections>
<action selector="delete:" target="-1" id="235"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="198">
<connections>
<action selector="selectAll:" target="-1" id="232"/>
</connections>
</menuItem>
<menuItem title="Delete" id="202"/>
<menuItem title="Select All" keyEquivalent="a" id="198"/>
<menuItem isSeparatorItem="YES" id="214">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Find" id="218">
<menu key="submenu" title="Find" id="220">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
<connections>
<action selector="performFindPanelAction:" target="-1" id="241"/>
</connections>
</menuItem>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="209"/>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="534">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="535"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="208">
<connections>
<action selector="performFindPanelAction:" target="-1" id="487"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="208"/>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="488"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221">
<connections>
<action selector="performFindPanelAction:" target="-1" id="489"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="210">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221"/>
<menuItem title="Jump to Selection" keyEquivalent="j" id="210"/>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="216">
<menu key="submenu" title="Spelling and Grammar" id="200">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="204">
<connections>
<action selector="showGuessPanel:" target="-1" id="230"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="201">
<connections>
<action selector="checkSpelling:" target="-1" id="225"/>
</connections>
</menuItem>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="204"/>
<menuItem title="Check Document Now" keyEquivalent=";" id="201"/>
<menuItem isSeparatorItem="YES" id="453"/>
<menuItem title="Check Spelling While Typing" id="219">
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="346">
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="347"/>
</connections>
</menuItem>
<menuItem title="Check Spelling While Typing" id="219"/>
<menuItem title="Check Grammar With Spelling" id="346"/>
<menuItem title="Correct Spelling Automatically" id="454">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="456"/>
</connections>
</menuItem>
</items>
</menu>
@@ -250,38 +214,18 @@
<items>
<menuItem title="Show Substitutions" id="457">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="458"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="459"/>
<menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
</connections>
</menuItem>
<menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350"/>
<menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351"/>
<menuItem title="Smart Dashes" id="460">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="461"/>
</connections>
</menuItem>
<menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="462">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="463"/>
</connections>
</menuItem>
</items>
</menu>
@@ -292,21 +236,12 @@
<items>
<menuItem title="Make Upper Case" id="452">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="464"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="465">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="468"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="466">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="467"/>
</connections>
</menuItem>
</items>
</menu>
@@ -314,16 +249,8 @@
<menuItem title="Speech" id="211">
<menu key="submenu" title="Speech" id="212">
<items>
<menuItem title="Start Speaking" id="196">
<connections>
<action selector="startSpeaking:" target="-1" id="233"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="195">
<connections>
<action selector="stopSpeaking:" target="-1" id="227"/>
</connections>
</menuItem>
<menuItem title="Start Speaking" id="196"/>
<menuItem title="Stop Speaking" id="195"/>
</items>
</menu>
</menuItem>
@@ -338,37 +265,13 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="388">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="389">
<connections>
<action selector="orderFrontFontPanel:" target="420" id="424"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="390">
<connections>
<action selector="addFontTrait:" target="420" id="421"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="391">
<connections>
<action selector="addFontTrait:" target="420" id="422"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="392">
<connections>
<action selector="underline:" target="-1" id="432"/>
</connections>
</menuItem>
<menuItem title="Show Fonts" keyEquivalent="t" id="389"/>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="390"/>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="391"/>
<menuItem title="Underline" keyEquivalent="u" id="392"/>
<menuItem isSeparatorItem="YES" id="393"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="394">
<connections>
<action selector="modifyFont:" target="420" id="425"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="395">
<connections>
<action selector="modifyFont:" target="420" id="423"/>
</connections>
</menuItem>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="394"/>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="395"/>
<menuItem isSeparatorItem="YES" id="396"/>
<menuItem title="Kern" id="397">
<modifierMask key="keyEquivalentModifierMask"/>
@@ -376,27 +279,15 @@
<items>
<menuItem title="Use Default" id="416">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="438"/>
</connections>
</menuItem>
<menuItem title="Use None" id="417">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="441"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="418">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="431"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="419">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="435"/>
</connections>
</menuItem>
</items>
</menu>
@@ -407,21 +298,12 @@
<items>
<menuItem title="Use Default" id="412">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="439"/>
</connections>
</menuItem>
<menuItem title="Use None" id="413">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="440"/>
</connections>
</menuItem>
<menuItem title="Use All" id="414">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="434"/>
</connections>
</menuItem>
</items>
</menu>
@@ -432,55 +314,30 @@
<items>
<menuItem title="Use Default" id="406">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="437"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="407">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="430"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="408">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="429"/>
</connections>
</menuItem>
<menuItem title="Raise" id="409">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="426"/>
</connections>
</menuItem>
<menuItem title="Lower" id="410">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="427"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="400"/>
<menuItem title="Show Colors" keyEquivalent="C" id="401">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="433"/>
</connections>
</menuItem>
<menuItem title="Show Colors" keyEquivalent="C" id="401"/>
<menuItem isSeparatorItem="YES" id="402"/>
<menuItem title="Copy Style" keyEquivalent="c" id="403">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="428"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="404">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="436"/>
</connections>
</menuItem>
</items>
</menu>
@@ -489,27 +346,12 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="497">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="498">
<connections>
<action selector="alignLeft:" target="-1" id="524"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="499">
<connections>
<action selector="alignCenter:" target="-1" id="518"/>
</connections>
</menuItem>
<menuItem title="Align Left" keyEquivalent="{" id="498"/>
<menuItem title="Center" keyEquivalent="|" id="499"/>
<menuItem title="Justify" id="500">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="523"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="501">
<connections>
<action selector="alignRight:" target="-1" id="521"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="501"/>
<menuItem isSeparatorItem="YES" id="502"/>
<menuItem title="Writing Direction" id="503">
<modifierMask key="keyEquivalentModifierMask"/>
@@ -521,23 +363,14 @@
<menuItem id="510">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="525"/>
</connections>
</menuItem>
<menuItem id="511">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="526"/>
</connections>
</menuItem>
<menuItem id="512">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="527"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="513"/>
<menuItem title="Selection" enabled="NO" id="514">
@@ -546,23 +379,14 @@
<menuItem id="515">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="528"/>
</connections>
</menuItem>
<menuItem id="516">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="529"/>
</connections>
</menuItem>
<menuItem id="517">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="530"/>
</connections>
</menuItem>
</items>
</menu>
@@ -570,21 +394,12 @@
<menuItem isSeparatorItem="YES" id="504"/>
<menuItem title="Show Ruler" id="505">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="520"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="506">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="522"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="507">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="519"/>
</connections>
</menuItem>
</items>
</menu>
@@ -597,39 +412,20 @@
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="297">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="366"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="298">
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="298"/>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="19">
<menu key="submenu" title="Window" systemMenu="window" id="24">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="23">
<connections>
<action selector="performMiniaturize:" target="-1" id="37"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="239">
<connections>
<action selector="performZoom:" target="-1" id="240"/>
</connections>
</menuItem>
<menuItem title="Minimize" keyEquivalent="m" id="23"/>
<menuItem title="Zoom" id="239"/>
<menuItem isSeparatorItem="YES" id="92">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Bring All to Front" id="5">
<connections>
<action selector="arrangeInFront:" target="-1" id="39"/>
</connections>
</menuItem>
<menuItem title="Bring All to Front" id="5"/>
</items>
</menu>
</menuItem>
@@ -637,21 +433,17 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="491">
<items>
<menuItem title="ExampleAppMac Help" keyEquivalent="?" id="492">
<connections>
<action selector="showHelp:" target="-1" id="493"/>
</connections>
</menuItem>
<menuItem title="ExampleAppMac Help" keyEquivalent="?" id="492"/>
</items>
</menu>
</menuItem>
</items>
</menu>
<window title="ExampleAppMac" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1418"/>
<view key="contentView" id="372">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
@@ -662,6 +454,14 @@
<outlet property="window" destination="371" id="532"/>
</connections>
</customObject>
<customObject id="420" customClass="NSFontManager"/>
<customObject id="420" customClass="NSFontManager">
<connections>
<action selector="addFontTrait:" destination="390" id="421"/>
<action selector="addFontTrait:" destination="391" id="422"/>
<action selector="modifyFont:" destination="395" id="423"/>
<action selector="modifyFont:" destination="394" id="425"/>
<action selector="orderFrontFontPanel:" destination="389" id="424"/>
</connections>
</customObject>
</objects>
</document>
@@ -9,7 +9,7 @@
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
+3 -3
View File
@@ -4,7 +4,7 @@
Inspired by Matt Gallagher's AudioStreamer:
https://github.com/mattgallagher/AudioStreamer
Copyright (c) 2015 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Copyright (c) 2012 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 Thong Nguyen.
This product includes software developed by the <organization>.
4. Neither the name of the <organization> 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 THONG NGUYEN ''AS IS'' AND ANY
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+6 -6
View File
@@ -2,7 +2,7 @@
StreamingKit (formally Audjustable) is an audio playback and streaming library for iOS and Mac OSX. StreamingKit uses CoreAudio to decompress and playback audio (using hardware or software codecs) whilst providing a clean and simple object-oriented API.
The primary motivation of this project was to decouple the input data sources from the actual player logic in order to allow advanced customizable input handling such as HTTP progressive download based streaming, encryption/decryption, auto-recovery, dynamic-buffering. StreamingKit is the only streaming and playback library that supports dead-easy [gapless playback](https://github.com/tumtumtum/StreamingKit/wiki/Gapless-playback) between audio files of differing formats.
The primary motivation of this project was to decouple the input data sources from the actual player logic in order to allow advanced customizable input handling such as HTTP streaming, encryption/decryption, auto-recovery, dynamic-buffering. StreamingKit is the only streaming and playback library that supports dead-easy [gapless playback](https://github.com/tumtumtum/StreamingKit/wiki/Gapless-playback) between audio files of differing formats.
## Main Features
@@ -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, AutoRecoveringHTTP DataSources are provided).
* Easy to implement audio data sources (Local, HTTP, AutoRecoveryingHTTP 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.
@@ -34,7 +34,7 @@ There are two main classes. The `STKDataSource` class which is the abstract bas
```objective-c
STKAudioPlayer* audioPlayer = [[STKAudioPlayer alloc] init];
[audioPlayer play:@"http://www.abstractpath.com/files/audiosamples/sample.mp3"];
[audioPlayer play:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
```
### Gapless playback
@@ -42,8 +42,8 @@ STKAudioPlayer* audioPlayer = [[STKAudioPlayer alloc] init];
```objective-c
STKAudioPlayer* audioPlayer = [[STKAudioPlayer alloc] init];
[audioPlayer queue:@"http://www.abstractpath.com/files/audiosamples/sample.mp3"];
[audioPlayer queue:@"http://www.abstractpath.com/files/audiosamples/airplane.aac"];
[audioPlayer queue:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
[audioPlayer queue:@"http://fs.bloom.fm/oss/audiosamples/airplane.aac"];
```
@@ -63,4 +63,4 @@ STKAudioPlayer* audioPlayer = [[STKAudioPlayer alloc] init];
More documentation is available on the project [Wiki](https://github.com/tumtumtum/StreamingKit/wiki/_pages)
### Authors and Contributors
Copyright (c) 2012-2019, Thong Nguyen ([@tumtumtum](http://www.twitter.com/tumtumtum))
Copyright (c) 2012-2014, Thong Nguyen ([@tumtumtum](http://www.twitter.com/tumtumtum))
+16
View File
@@ -0,0 +1,16 @@
Pod::Spec.new do |s|
s.name = "StreamingKit"
s.version = "0.0.0"
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'
s.author = { "Thong Nguyen" => "tumtumtum@gmail.com" }
s.source = { :git => "https://github.com/tumtumtum/StreamingKit.git" }
s.platform = :ios
s.requires_arc = true
s.source_files = 'StreamingKit/StreamingKit/*.{h,m}'
s.ios.deployment_target = '4.3'
s.ios.frameworks = 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox'
s.osx.deployment_target = '10.7'
s.osx.frameworks = 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox', 'AudioUnit'
end
+4 -4
View File
@@ -1,16 +1,16 @@
Pod::Spec.new do |s|
s.name = "StreamingKit"
s.version = "0.1.31"
s.platform = :ios
s.ios.deployment_target = '5.0'
s.osx.deployment_target = '10.7'
s.version = "0.1.19"
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'
s.author = { "Thong Nguyen" => "tumtumtum@gmail.com" }
s.source = { :git => "https://github.com/tumtumtum/StreamingKit.git", :tag => s.version.to_s}
s.platform = :ios
s.requires_arc = true
s.source_files = 'StreamingKit/StreamingKit/*.{h,m}'
s.ios.deployment_target = '4.3'
s.ios.frameworks = 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox'
s.osx.deployment_target = '10.7'
s.osx.frameworks = 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox', 'AudioUnit'
end
@@ -10,29 +10,29 @@
<string>StreamingKit</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>3E9414865BAE5433092B9D136FFC1F054EA505C2</key>
<key>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</key>
<string>https://github.com/tumtumtum/StreamingKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>StreamingKit.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>3E9414865BAE5433092B9D136FFC1F054EA505C2</key>
<key>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</key>
<string>..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>https://github.com/tumtumtum/StreamingKit.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<integer>110</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>3E9414865BAE5433092B9D136FFC1F054EA505C2</string>
<string>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>3E9414865BAE5433092B9D136FFC1F054EA505C2</string>
<string>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</string>
<key>IDESourceControlWCCName</key>
<string>StreamingKit</string>
</dict>
@@ -7,18 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
40B6239322423B1E005D725D /* STKMacro.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B6239222423B1E005D725D /* STKMacro.h */; };
40B6239422423B1F005D725D /* STKMacro.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B6239222423B1E005D725D /* STKMacro.h */; };
40B6239822423F28005D725D /* STKSpinLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B6239722423F28005D725D /* STKSpinLock.h */; };
40B6239922423F28005D725D /* STKSpinLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B6239722423F28005D725D /* STKSpinLock.h */; };
5B949CD21A1140E4005675A0 /* STKAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4F1188D5E550010896F /* STKAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD31A1140E4005675A0 /* STKAutoRecoveringHTTPDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD41A1140E4005675A0 /* STKCoreFoundationDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4F5188D5E550010896F /* STKCoreFoundationDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD51A1140E4005675A0 /* STKDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4F7188D5E550010896F /* STKDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD61A1140E4005675A0 /* STKDataSourceWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4F9188D5E550010896F /* STKDataSourceWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD71A1140E4005675A0 /* STKHTTPDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4FB188D5E550010896F /* STKHTTPDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD81A1140E4005675A0 /* STKLocalFileDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD91A1140E4005675A0 /* STKQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BF65D0189A6582004DD08C /* STKQueueEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4996A189E744400E2A2E2 /* Cocoa.framework */; };
A1A49975189E744500E2A2E2 /* StreamingKitMac.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A49974189E744500E2A2E2 /* StreamingKitMac.m */; };
A1A4997B189E744500E2A2E2 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4D9188D57F60010896F /* XCTest.framework */; };
@@ -49,6 +37,8 @@
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FA188D5E550010896F /* STKDataSourceWrapper.m */; };
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */; };
A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */; };
A1F341041908183300CA7755 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F341031908183300CA7755 /* Accelerate.framework */; };
A1F341081908183A00CA7755 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F341071908183A00CA7755 /* Accelerate.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -95,8 +85,6 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
40B6239222423B1E005D725D /* STKMacro.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STKMacro.h; sourceTree = "<group>"; };
40B6239722423F28005D725D /* STKSpinLock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STKSpinLock.h; sourceTree = "<group>"; };
A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStreamingKitMac.a; sourceTree = BUILT_PRODUCTS_DIR; };
A1A4996A189E744400E2A2E2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; };
A1A4996D189E744500E2A2E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -139,6 +127,8 @@
A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKLocalFileDataSource.h; sourceTree = "<group>"; };
A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKLocalFileDataSource.m; sourceTree = "<group>"; };
A1E7C507188D62D20010896F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
A1F341031908183300CA7755 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
A1F341071908183A00CA7755 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -146,6 +136,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1F341081908183A00CA7755 /* Accelerate.framework in Frameworks */,
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -164,6 +155,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1F341041908183300CA7755 /* Accelerate.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -262,6 +254,8 @@
A1E7C4CA188D57F50010896F /* Frameworks */ = {
isa = PBXGroup;
children = (
A1F341071908183A00CA7755 /* Accelerate.framework */,
A1F341031908183300CA7755 /* Accelerate.framework */,
A1A499F6189E79EA00E2A2E2 /* AudioToolbox.framework */,
A1C9767618981BFE0057F881 /* AudioUnit.framework */,
A1E7C507188D62D20010896F /* UIKit.framework */,
@@ -276,8 +270,6 @@
A1E7C4CD188D57F50010896F /* StreamingKit */ = {
isa = PBXGroup;
children = (
A1BF65D3189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.h */,
A1BF65D4189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m */,
A1E7C4F1188D5E550010896F /* STKAudioPlayer.h */,
A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */,
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */,
@@ -292,10 +284,10 @@
A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */,
A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */,
A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */,
40B6239222423B1E005D725D /* STKMacro.h */,
A1BF65D0189A6582004DD08C /* STKQueueEntry.h */,
A1BF65D1189A6582004DD08C /* STKQueueEntry.m */,
40B6239722423F28005D725D /* STKSpinLock.h */,
A1BF65D3189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.h */,
A1BF65D4189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m */,
A1E7C4CE188D57F50010896F /* Supporting Files */,
);
path = StreamingKit;
@@ -330,29 +322,10 @@
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
5B949CD11A1140CF005675A0 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
40B6239822423F28005D725D /* STKSpinLock.h in Headers */,
5B949CD21A1140E4005675A0 /* STKAudioPlayer.h in Headers */,
5B949CD31A1140E4005675A0 /* STKAutoRecoveringHTTPDataSource.h in Headers */,
5B949CD41A1140E4005675A0 /* STKCoreFoundationDataSource.h in Headers */,
40B6239322423B1E005D725D /* STKMacro.h in Headers */,
5B949CD51A1140E4005675A0 /* STKDataSource.h in Headers */,
5B949CD61A1140E4005675A0 /* STKDataSourceWrapper.h in Headers */,
5B949CD71A1140E4005675A0 /* STKHTTPDataSource.h in Headers */,
5B949CD81A1140E4005675A0 /* STKLocalFileDataSource.h in Headers */,
5B949CD91A1140E4005675A0 /* STKQueueEntry.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1A49967189E744400E2A2E2 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
40B6239922423F28005D725D /* STKSpinLock.h in Headers */,
40B6239422423B1F005D725D /* STKMacro.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -401,7 +374,6 @@
A1E7C4C4188D57F50010896F /* Sources */,
A1E7C4C5188D57F50010896F /* Frameworks */,
A1E7C4C6188D57F50010896F /* CopyFiles */,
5B949CD11A1140CF005675A0 /* Headers */,
);
buildRules = (
);
@@ -437,7 +409,7 @@
isa = PBXProject;
attributes = {
CLASSPREFIX = STK;
LastUpgradeCheck = 1010;
LastUpgradeCheck = 0510;
ORGANIZATIONNAME = "Thong Nguyen";
};
buildConfigurationList = A1E7C4C3188D57F50010896F /* Build configuration list for PBXProject "StreamingKit" */;
@@ -590,7 +562,6 @@
A1A49988189E744500E2A2E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
@@ -604,7 +575,6 @@
);
MACOSX_DEPLOYMENT_TARGET = "";
PRODUCT_NAME = "$(TARGET_NAME)";
PUBLIC_HEADERS_FOLDER_PATH = include/StreamingKit;
SDKROOT = macosx;
};
name = Debug;
@@ -612,7 +582,6 @@
A1A49989189E744500E2A2E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -623,7 +592,6 @@
GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch";
MACOSX_DEPLOYMENT_TARGET = "";
PRODUCT_NAME = "$(TARGET_NAME)";
PUBLIC_HEADERS_FOLDER_PATH = include/StreamingKit;
SDKROOT = macosx;
};
name = Release;
@@ -645,7 +613,6 @@
);
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;
@@ -666,7 +633,6 @@
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;
@@ -681,31 +647,17 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -718,8 +670,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
@@ -733,38 +684,24 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
@@ -782,7 +719,6 @@
GCC_PREFIX_HEADER = "StreamingKit/StreamingKit-Prefix.pch";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
PUBLIC_HEADERS_FOLDER_PATH = include/StreamingKit;
SKIP_INSTALL = YES;
};
name = Debug;
@@ -799,7 +735,6 @@
GCC_PREFIX_HEADER = "StreamingKit/StreamingKit-Prefix.pch";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
PUBLIC_HEADERS_FOLDER_PATH = include/StreamingKit;
SKIP_INSTALL = YES;
};
name = Release;
@@ -819,7 +754,6 @@
"$(inherited)",
);
INFOPLIST_FILE = "StreamingKitTests/StreamingKitTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = xctest;
};
@@ -836,7 +770,6 @@
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;
};
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -8,14 +8,10 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSMutableArray (STKAudioPlayer)
-(void) enqueue:(id)obj;
-(void) skipQueue:(id)obj;
-(void) skipQueueWithQueue:(NSMutableArray*)queue;
-(nullable id) dequeue;
-(nullable id) peek;
-(id) dequeue;
-(id) peek;
@end
NS_ASSUME_NONNULL_END
+20 -34
View File
@@ -44,9 +44,7 @@
#include "UIKit/UIApplication.h"
#endif
NS_ASSUME_NONNULL_BEGIN
typedef NS_OPTIONS(NSInteger, STKAudioPlayerState)
typedef enum
{
STKAudioPlayerStateReady,
STKAudioPlayerStateRunning = 1,
@@ -56,9 +54,10 @@ typedef NS_OPTIONS(NSInteger, STKAudioPlayerState)
STKAudioPlayerStateStopped = (1 << 4),
STKAudioPlayerStateError = (1 << 5),
STKAudioPlayerStateDisposed = (1 << 6)
};
}
STKAudioPlayerState;
typedef NS_ENUM(NSInteger, STKAudioPlayerStopReason)
typedef enum
{
STKAudioPlayerStopReasonNone = 0,
STKAudioPlayerStopReasonEof,
@@ -66,9 +65,10 @@ typedef NS_ENUM(NSInteger, STKAudioPlayerStopReason)
STKAudioPlayerStopReasonPendingNext,
STKAudioPlayerStopReasonDisposed,
STKAudioPlayerStopReasonError = 0xffff
};
}
STKAudioPlayerStopReason;
typedef NS_ENUM(NSInteger, STKAudioPlayerErrorCode)
typedef enum
{
STKAudioPlayerErrorNone = 0,
STKAudioPlayerErrorDataSource,
@@ -77,13 +77,9 @@ typedef NS_ENUM(NSInteger, STKAudioPlayerErrorCode)
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
@@ -95,7 +91,7 @@ typedef struct
/// 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)
Float32 bufferSizeInSeconds;
UInt32 bufferSizeInSeconds;
/// Number of seconds of decompressed audio is required before playback first starts for each item (Default is 0.5 seconds. Must be larger than bufferSizeInSeconds)
Float32 secondsRequiredToStartPlaying;
/// Seconds after a seek is performed before data needs to come in (after which the state will change to playing/buffering)
@@ -105,8 +101,6 @@ typedef struct
}
STKAudioPlayerOptions;
#define STK_DISABLE_BUFFER (0xffffffff)
typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames);
@interface STKFrameFilterEntry : NSObject
@@ -135,9 +129,6 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// Raised when items queued items are cleared (usually because of a call to play, setDataSource or stop)
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didCancelQueuedItems:(NSArray*)queuedItems;
/// Raised when datasource read stream metadata. Called from the non-main thread.
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didReadStreamMetadata:(NSDictionary*)dictionary;
@end
@interface STKAudioPlayer : NSObject<STKDataSourceDelegate>
@@ -151,22 +142,20 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
@property (readonly) double duration;
/// Gets the current item progress in seconds
@property (readonly) double progress;
/// Gets or sets the playback rate (default is 1.0)
@property(readwrite) float rate;
// Gets or sets the playback overlap (default is 8.0)
@property(readwrite) float overlap;
/// Enables or disables peak and average decibel meteting
@property (readwrite) BOOL meteringEnabled;
/// Enables or disables the EQ
@property (readwrite) BOOL equalizerEnabled;
/// Enables or disables the spectrum analyzer (fft)
@property (readwrite) BOOL spectrumAnalyzerEnabled;
/// Returns an array of STKFrameFilterEntry objects representing the filters currently in use
@property (readonly, nullable) NSArray* frameFilters;
@property (readonly) 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, nullable) NSObject* mostRecentlyQueuedStillPendingItem;
@property (readonly) NSObject* mostRecentlyQueuedStillPendingItem;
/// Gets the current state of the player
@property (readwrite) STKAudioPlayerState state;
/// Gets the options provided to the player on startup
@@ -174,7 +163,7 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// Gets the reason why the player is stopped (if any)
@property (readonly) STKAudioPlayerStopReason stopReason;
/// Gets and sets the delegate used for receiving events from the STKAudioPlayer
@property (readwrite, weak) id<STKAudioPlayerDelegate> delegate;
@property (readwrite, unsafe_unretained) id<STKAudioPlayerDelegate> delegate;
/// Creates a datasource from a given URL.
/// URLs with FILE schemes will return an STKLocalFileDataSource.
@@ -182,14 +171,11 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// URLs with unrecognised schemes will return nil.
+(STKDataSource*) dataSourceFromURL:(NSURL*)url;
/// Returns canonical audio format used by STKFrameFilter blocks.
+(AudioStreamBasicDescription)canonicalAudioStreamBasicDescription;
/// Initializes a new STKAudioPlayer with the default options
-(instancetype) init;
-(id) init;
/// Initializes a new STKAudioPlayer with the given options
-(instancetype) initWithOptions:(STKAudioPlayerOptions)optionsIn;
-(id) 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
@@ -266,7 +252,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:(nullable NSString*)afterFilterWithName block:(STKFrameFilter)block;
-(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(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).
@@ -279,6 +265,6 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// 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
-(float) testPowerWithIndex:(int)index;
NS_ASSUME_NONNULL_END
@end
+280 -539
View File
File diff suppressed because it is too large Load Diff
@@ -36,8 +36,6 @@
#import "STKHTTPDataSource.h"
#import "STKDataSourceWrapper.h"
NS_ASSUME_NONNULL_BEGIN
typedef struct
{
int watchdogPeriodSeconds;
@@ -47,10 +45,8 @@ STKAutoRecoveringHTTPDataSourceOptions;
@interface STKAutoRecoveringHTTPDataSource : STKDataSourceWrapper
-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource;
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource;
@property (readonly) STKHTTPDataSource* innerDataSource;
@end
NS_ASSUME_NONNULL_END
@@ -101,33 +101,38 @@ static void PopulateOptionsWithDefault(STKAutoRecoveringHTTPDataSourceOptions* o
@implementation STKAutoRecoveringHTTPDataSource
@dynamic innerDataSource;
-(STKHTTPDataSource*) innerHTTPDataSource
{
return (STKHTTPDataSource*)self.innerDataSource;
}
-(instancetype) initWithDataSource:(STKDataSource *)innerDataSource
-(id) initWithDataSource:(STKDataSource *)innerDataSource
{
return [self initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource];
}
-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn
{
return [self initWithHTTPDataSource:innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions){}];
}
-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn
{
if (self = [super initWithDataSource:innerDataSourceIn]) {
if (self = [super initWithDataSource:innerDataSourceIn])
{
self.innerDataSource.delegate = self;
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
PopulateOptionsWithDefault(&optionsIn);
self->options = optionsIn;
NSString* hostname = innerDataSourceIn.url.host;
if (hostname.length) {
reachabilityRef = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
}
reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress);
}
return self;
@@ -135,16 +140,18 @@ static void PopulateOptionsWithDefault(STKAutoRecoveringHTTPDataSourceOptions* o
-(BOOL) startNotifierOnRunLoop:(NSRunLoop*)runLoop
{
if (reachabilityRef) {
SCNetworkReachabilityContext context = { 0, (__bridge void*)self, NULL, NULL, NULL };
if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) {
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, runLoop.getCFRunLoop, kCFRunLoopDefaultMode))
{
return YES;
}
BOOL retVal = NO;
SCNetworkReachabilityContext context = { 0, (__bridge void*)self, NULL, NULL, NULL };
if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
{
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, runLoop.getCFRunLoop, kCFRunLoopDefaultMode))
{
retVal = YES;
}
}
return NO;
return retVal;
}
-(BOOL) registerForEvents:(NSRunLoop*)runLoop
@@ -231,8 +238,6 @@ static void PopulateOptionsWithDefault(STKAutoRecoveringHTTPDataSourceOptions* o
{
SCNetworkReachabilityFlags flags;
if (! reachabilityRef) return YES; // Assume reachability, if unknown
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
return ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
@@ -34,8 +34,6 @@
#import "STKDataSource.h"
NS_ASSUME_NONNULL_BEGIN
@class STKCoreFoundationDataSource;
@interface CoreFoundationDataSourceClientInfo : NSObject
@@ -45,10 +43,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface STKCoreFoundationDataSource : STKDataSource
{
@public
CFReadStreamRef stream;
@protected
BOOL isInErrorState;
CFReadStreamRef stream;
NSRunLoop* eventsRunLoop;
}
@@ -64,5 +61,3 @@ NS_ASSUME_NONNULL_BEGIN
-(CFStreamStatus) status;
@end
NS_ASSUME_NONNULL_END
@@ -41,10 +41,8 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
switch (eventType)
{
case kCFStreamEventErrorOccurred:
{
[datasource errorOccured];
break;
}
case kCFStreamEventEndEncountered:
[datasource eof];
break;
@@ -137,6 +135,8 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
{
CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, NULL, NULL);
CFReadStreamUnscheduleFromRunLoop(stream, [eventsRunLoop getCFRunLoop], kCFRunLoopCommonModes);
eventsRunLoop = nil;
}
}
+1 -9
View File
@@ -35,26 +35,20 @@
#import <Foundation/Foundation.h>
#include <AudioToolbox/AudioToolbox.h>
NS_ASSUME_NONNULL_BEGIN
@class STKDataSource;
@protocol STKDataSourceDelegate<NSObject>
-(void) dataSourceDataAvailable:(STKDataSource*)dataSource;
-(void) dataSourceErrorOccured:(STKDataSource*)dataSource;
-(void) dataSourceEof:(STKDataSource*)dataSource;
-(void) dataSource:(STKDataSource*)dataSource didReadStreamMetadata:(NSDictionary*)metadata;
@end
@interface STKDataSource : NSObject
@property (readonly) BOOL supportsSeek;
@property (readonly) SInt64 position;
@property (readonly) SInt64 length;
@property (readonly) BOOL hasBytesAvailable;
@property (nonatomic, readwrite, assign) double durationHint;
@property (readwrite, unsafe_unretained, nullable) id<STKDataSourceDelegate> delegate;
@property (nonatomic, strong, nullable) NSURL *recordToFileUrl;
@property (readwrite, unsafe_unretained) id<STKDataSourceDelegate> delegate;
-(BOOL) registerForEvents:(NSRunLoop*)runLoop;
-(void) unregisterForEvents;
@@ -65,5 +59,3 @@ NS_ASSUME_NONNULL_BEGIN
-(AudioFileTypeID) audioFileTypeHint;
@end
NS_ASSUME_NONNULL_END
@@ -79,9 +79,4 @@
return 0;
}
-(BOOL) supportsSeek
{
return YES;
}
@end
@@ -34,14 +34,10 @@
#import "STKDataSource.h"
NS_ASSUME_NONNULL_BEGIN
@interface STKDataSourceWrapper : STKDataSource<STKDataSourceDelegate>
-(instancetype) initWithDataSource:(STKDataSource*)innerDataSource;
-(id) initWithDataSource:(STKDataSource*)innerDataSource;
@property (readonly) STKDataSource* innerDataSource;
@end
NS_ASSUME_NONNULL_END
@@ -40,7 +40,7 @@
@implementation STKDataSourceWrapper
-(instancetype) initWithDataSource:(STKDataSource*)innerDataSourceIn
-(id) initWithDataSource:(STKDataSource*)innerDataSourceIn
{
if (self = [super init])
{
@@ -117,9 +117,4 @@
[self.delegate dataSourceEof:self];
}
- (void)dataSource:(STKDataSource *)dataSource didReadStreamMetadata:(NSDictionary *)metadata
{
[self.delegate dataSource:self didReadStreamMetadata:metadata];
}
@end
+5 -10
View File
@@ -34,12 +34,10 @@
#import "STKCoreFoundationDataSource.h"
NS_ASSUME_NONNULL_BEGIN
@class STKHTTPDataSource;
typedef void(^STKURLBlock)(NSURL* url);
typedef NSURL* _Nonnull (^STKURLProvider)(void);
typedef NSURL*(^STKURLProvider)();
typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock callback);
@interface STKHTTPDataSource : STKCoreFoundationDataSource
@@ -48,13 +46,10 @@ typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek,
@property (readonly) UInt32 httpStatusCode;
+(AudioFileTypeID) audioFileTypeHintFromMimeType:(NSString*)fileExtension;
-(instancetype) initWithURL:(NSURL*)url;
-(instancetype) initWithURL:(NSURL*)url httpRequestHeaders:(NSDictionary*)httpRequestHeaders;
-(instancetype) initWithURLProvider:(STKURLProvider)urlProvider;
-(instancetype) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider;
-(nullable NSRunLoop*) eventsRunLoop;
-(id) initWithURL:(NSURL*)url;
-(id) initWithURLProvider:(STKURLProvider)urlProvider;
-(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider;
-(NSRunLoop*) eventsRunLoop;
-(void) reconnect;
@end
NS_ASSUME_NONNULL_END
+84 -425
View File
@@ -38,31 +38,17 @@
@interface STKHTTPDataSource()
{
@private
BOOL supportsSeek;
UInt32 httpStatusCode;
SInt64 seekStart;
SInt64 relativePosition;
SInt64 fileLength;
int discontinuous;
int requestSerialNumber;
int prefixBytesRead;
NSData* prefixBytes;
NSMutableData* iceHeaderData;
BOOL iceHeaderSearchComplete;
BOOL iceHeaderAvailable;
BOOL httpHeaderNotAvailable;
NSMutableData *_metadataData;
int _metadataOffset;
int _metadataBytesRead;
int _metadataStep;
int _metadataLength;
NSURL* currentUrl;
STKAsyncURLProvider asyncUrlProvider;
NSDictionary* httpHeaders;
AudioFileTypeID audioFileTypeHint;
NSDictionary* requestHeaders;
}
-(void) open;
@@ -70,20 +56,12 @@
@implementation STKHTTPDataSource
-(instancetype) initWithURL:(NSURL*)urlIn
-(id) initWithURL:(NSURL*)urlIn
{
currentUrl = urlIn;
return [self initWithURLProvider:^NSURL* { return urlIn; }];
}
-(instancetype) initWithURL:(NSURL *)urlIn httpRequestHeaders:(NSDictionary *)httpRequestHeaders
{
self = [self initWithURLProvider:^NSURL* { return urlIn; }];
self->requestHeaders = httpRequestHeaders;
return self;
}
-(instancetype) initWithURLProvider:(STKURLProvider)urlProviderIn
-(id) initWithURLProvider:(STKURLProvider)urlProviderIn
{
urlProviderIn = [urlProviderIn copy];
@@ -93,7 +71,7 @@
}];
}
-(instancetype) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn
-(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn
{
if (self = [super init])
{
@@ -132,8 +110,6 @@
@"audio/mpg": @(kAudioFileMP3Type),
@"audio/mpeg": @(kAudioFileMP3Type),
@"audio/wav": @(kAudioFileWAVEType),
@"audio/x-wav": @(kAudioFileWAVEType),
@"audio/vnd.wav": @(kAudioFileWAVEType),
@"audio/aifc": @(kAudioFileAIFCType),
@"audio/aiff": @(kAudioFileAIFFType),
@"audio/x-m4a": @(kAudioFileM4AType),
@@ -141,18 +117,10 @@
@"audio/aacp": @(kAudioFileAAC_ADTSType),
@"audio/m4a": @(kAudioFileM4AType),
@"audio/mp4": @(kAudioFileMPEG4Type),
@"video/mp4": @(kAudioFileMPEG4Type),
@"audio/caf": @(kAudioFileCAFType),
@"audio/x-caf": @(kAudioFileCAFType),
@"audio/aac": @(kAudioFileAAC_ADTSType),
@"audio/aacp": @(kAudioFileAAC_ADTSType),
@"audio/ac3": @(kAudioFileAC3Type),
@"audio/3gp": @(kAudioFile3GPType),
@"video/3gp": @(kAudioFile3GPType),
@"audio/3gpp": @(kAudioFile3GPType),
@"video/3gpp": @(kAudioFile3GPType),
@"audio/3gp2": @(kAudioFile3GP2Type),
@"video/3gp2": @(kAudioFile3GP2Type)
@"audio/3gp": @(kAudioFile3GPType)
};
});
@@ -171,242 +139,70 @@
return audioFileTypeHint;
}
-(NSDictionary*) parseIceHeader:(NSData*)headerData
{
NSMutableDictionary* retval = [[NSMutableDictionary alloc] init];
NSCharacterSet* characterSet = [NSCharacterSet characterSetWithCharactersInString:@"\r\n"];
NSString* fullString = [[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding];
NSArray* strings = [fullString componentsSeparatedByCharactersInSet:characterSet];
httpHeaders = [NSMutableDictionary dictionary];
for (NSString* s in strings)
{
if (s.length == 0)
{
continue;
}
if ([s hasPrefix:@"ICY "])
{
NSArray* parts = [s componentsSeparatedByString:@" "];
if (parts.count >= 2)
{
self->httpStatusCode = [parts[1] intValue];
}
continue;
}
NSRange range = [s rangeOfString:@":"];
if (range.location == NSNotFound)
{
continue;
}
NSString* key = [s substringWithRange: (NSRange){.location = 0, .length = range.location}];
NSString* value = [s substringFromIndex:range.location + 1];
[retval setValue:value forKey:key];
}
return retval;
}
-(BOOL) parseHttpHeader
{
if (!httpHeaderNotAvailable)
{
CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
if (response)
{
httpHeaders = (__bridge_transfer NSDictionary*)CFHTTPMessageCopyAllHeaderFields((CFHTTPMessageRef)response);
if (httpHeaders.count == 0)
{
httpHeaderNotAvailable = YES;
}
else
{
self->httpStatusCode = (UInt32)CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response);
}
CFRelease(response);
}
}
if (httpHeaderNotAvailable)
{
if (self->iceHeaderSearchComplete && !self->iceHeaderAvailable)
{
return YES;
}
if (!self->iceHeaderSearchComplete)
{
UInt8 byte;
UInt8 terminal1[] = { '\n', '\n' };
UInt8 terminal2[] = { '\r', '\n', '\r', '\n' };
if (iceHeaderData == nil)
{
iceHeaderData = [NSMutableData dataWithCapacity:1024];
}
while (true)
{
if (![self hasBytesAvailable])
{
break;
}
int read = [super readIntoBuffer:&byte withSize:1];
if (read <= 0)
{
break;
}
[iceHeaderData appendBytes:&byte length:read];
if (iceHeaderData.length >= sizeof(terminal1))
{
if (memcmp(&terminal1[0], [self->iceHeaderData bytes] + iceHeaderData.length - sizeof(terminal1), sizeof(terminal1)) == 0)
{
self->iceHeaderAvailable = YES;
self->iceHeaderSearchComplete = YES;
break;
}
}
if (iceHeaderData.length >= sizeof(terminal2))
{
if (memcmp(&terminal2[0], [self->iceHeaderData bytes] + iceHeaderData.length - sizeof(terminal2), sizeof(terminal2)) == 0)
{
self->iceHeaderAvailable = YES;
self->iceHeaderSearchComplete = YES;
break;
}
}
if (iceHeaderData.length >= 4)
{
if (memcmp([self->iceHeaderData bytes], "ICY ", 4) != 0 && memcmp([self->iceHeaderData bytes], "HTTP", 4) != 0)
{
self->iceHeaderAvailable = NO;
self->iceHeaderSearchComplete = YES;
prefixBytes = iceHeaderData;
return YES;
}
}
}
if (!self->iceHeaderSearchComplete)
{
return NO;
}
}
httpHeaders = [self parseIceHeader:self->iceHeaderData];
self->iceHeaderData = nil;
}
// check ICY headers
NSString* icyHeaders = [httpHeaders objectForKey:@"Icy-Metaint"] ?: [httpHeaders objectForKey:@"icy-metaint"];
if (icyHeaders != nil)
{
_metadataBytesRead = 0;
_metadataStep = [icyHeaders intValue];
_metadataOffset = _metadataStep;
}
if (([httpHeaders objectForKey:@"Accept-Ranges"] ?: [httpHeaders objectForKey:@"accept-ranges"]) != nil)
{
self->supportsSeek = ![[httpHeaders objectForKey:@"Accept-Ranges"] isEqualToString:@"none"];
}
if (self.httpStatusCode == 200)
{
if (seekStart == 0)
{
id value = [httpHeaders objectForKey:@"Content-Length"] ?: [httpHeaders objectForKey:@"content-length"];
fileLength = (SInt64)[value longLongValue];
}
NSString* contentType = [httpHeaders objectForKey:@"Content-Type"] ?: [httpHeaders objectForKey:@"content-type"] ;
AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType];
if (typeIdFromMimeType != 0)
{
audioFileTypeHint = typeIdFromMimeType;
}
}
else if (self.httpStatusCode == 206)
{
NSString* contentRange = [httpHeaders objectForKey:@"Content-Range"] ?: [httpHeaders objectForKey:@"content-range"];
NSArray* components = [contentRange componentsSeparatedByString:@"/"];
if (components.count == 2)
{
fileLength = [[components objectAtIndex:1] integerValue];
}
}
else if (self.httpStatusCode == 416)
{
if (self.length >= 0)
{
seekStart = self.length;
}
[self eof];
return NO;
}
else if (self.httpStatusCode >= 300)
{
[self errorOccured];
return NO;
}
return YES;
}
-(void) dataAvailable
{
if (stream == NULL)
{
if (stream == NULL) {
return;
}
if (self.httpStatusCode == 0)
{
if ([self parseHttpHeader])
CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
if (response)
{
if ([self hasBytesAvailable])
{
[super dataAvailable];
}
httpHeaders = (__bridge_transfer NSDictionary*)CFHTTPMessageCopyAllHeaderFields((CFHTTPMessageRef)response);
return;
}
else
{
return;
self->httpStatusCode = (UInt32)CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response);
CFRelease(response);
}
if (self.httpStatusCode == 200)
{
if (seekStart == 0)
{
fileLength = (SInt64)[[httpHeaders objectForKey:@"Content-Length"] longLongValue];
}
NSString* contentType = [httpHeaders objectForKey:@"Content-Type"];
AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType];
if (typeIdFromMimeType != 0)
{
audioFileTypeHint = typeIdFromMimeType;
}
}
else if (self.httpStatusCode == 206)
{
NSString* contentRange = [httpHeaders objectForKey:@"Content-Range"];
NSArray* components = [contentRange componentsSeparatedByString:@"/"];
if (components.count == 2)
{
fileLength = [[components objectAtIndex:1] integerValue];
}
}
else if (self.httpStatusCode == 416)
{
if (self.length >= 0)
{
seekStart = self.length;
}
[self eof];
return;
}
else if (self.httpStatusCode >= 300)
{
[self errorOccured];
return;
}
}
else
{
[super dataAvailable];
}
[super dataAvailable];
}
-(SInt64) position
@@ -427,7 +223,7 @@
eventsRunLoop = savedEventsRunLoop;
[self seekToOffset:self->supportsSeek ? self.position : 0];
[self seekToOffset:self.position];
}
-(void) seekToOffset:(SInt64)offset
@@ -446,127 +242,22 @@
self->isInErrorState = NO;
if (!self->supportsSeek && offset != self->relativePosition)
{
return;
}
[self openForSeek:YES];
}
-(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size
{
return [self privateReadIntoBuffer:buffer withSize:size];
}
#pragma mark - Custom buffer reading
-(int) privateReadIntoBuffer:(UInt8*)buffer withSize:(int)size
{
if (size == 0)
{
return 0;
}
if (prefixBytes != nil)
{
int count = MIN(size, (int)prefixBytes.length - prefixBytesRead);
[prefixBytes getBytes:buffer length:count];
prefixBytesRead += count;
if (prefixBytesRead >= prefixBytes.length)
{
prefixBytes = nil;
}
return count;
}
int read;
// read ICY stream metadata
// http://www.smackfu.com/stuff/programming/shoutcast.html
//
if(_metadataStep > 0)
{
// read audio stream before next metadata chunk
if(_metadataOffset > 0)
{
read = [super readIntoBuffer:buffer withSize:MIN(_metadataOffset, size)];
if(read > 0)
_metadataOffset -= read;
}
// read metadata
else
{
// first we need to read one byte with length
if(_metadataLength == 0)
{
// read only 1 byte
UInt8 metadataLengthByte;
read = [super readIntoBuffer:&metadataLengthByte withSize:1];
if(read > 0)
{
_metadataLength = metadataLengthByte * 16;
// prepare
if(_metadataLength > 0)
{
_metadataData = [NSMutableData dataWithLength:_metadataLength];
_metadataBytesRead = 0;
}
// reset
else
{
_metadataOffset = _metadataStep;
_metadataData = nil;
_metadataLength = 0;
}
// return 0, because no audio bytes read
relativePosition += read;
read = 0;
}
}
// read metadata bytes
else
{
read = [super readIntoBuffer:(_metadataData.mutableBytes + _metadataBytesRead)
withSize:_metadataLength - _metadataBytesRead];
if(read > 0)
{
_metadataBytesRead += read;
// done reading, so process it
if(_metadataBytesRead == _metadataLength)
{
if([self.delegate respondsToSelector:@selector(dataSource:didReadStreamMetadata:)])
[self.delegate dataSource:self didReadStreamMetadata:[self _processIcyMetadata:_metadataData]];
// reset
_metadataData = nil;
_metadataOffset = _metadataStep;
_metadataLength = 0;
_metadataBytesRead = 0;
}
// return 0, because no audio bytes read
relativePosition += read;
read = 0;
}
}
}
}
else
{
read = [super readIntoBuffer:buffer withSize:size];
}
int read = (int)CFReadStreamRead(stream, buffer, size);
if (read < 0)
{
return read;
}
relativePosition += read;
@@ -591,7 +282,7 @@
{
return;
}
self->currentUrl = url;
if (url == nil)
@@ -601,26 +292,16 @@
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (__bridge CFURLRef)self->currentUrl, kCFHTTPVersion1_1);
if (self->seekStart > 0 && self->supportsSeek)
if (seekStart > 0)
{
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Range"), (__bridge CFStringRef)[NSString stringWithFormat:@"bytes=%lld-", self->seekStart]);
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Range"), (__bridge CFStringRef)[NSString stringWithFormat:@"bytes=%lld-", seekStart]);
self->discontinuous = YES;
discontinuous = YES;
}
for (NSString* key in self->requestHeaders)
{
NSString* value = [self->requestHeaders objectForKey:key];
CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)value);
}
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Accept"), CFSTR("*/*"));
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Icy-MetaData"), CFSTR("1"));
stream = CFReadStreamCreateForHTTPRequest(NULL, message);
self->stream = CFReadStreamCreateForHTTPRequest(NULL, message);
if (self->stream == nil)
if (stream == nil)
{
CFRelease(message);
@@ -628,10 +309,8 @@
return;
}
CFReadStreamSetProperty(self->stream, (__bridge CFStringRef)NSStreamNetworkServiceTypeBackground, (__bridge CFStringRef)NSStreamNetworkServiceTypeBackground);
if (!CFReadStreamSetProperty(self->stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue))
if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue))
{
CFRelease(message);
@@ -641,18 +320,25 @@
}
// Proxy support
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(self->stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFRelease(proxySettings);
// SSL support
if ([self->currentUrl.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)
{
NSDictionary* sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
(NSString*)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel,
[NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
nil];
CFReadStreamSetProperty(self->stream, kCFStreamPropertySSLSettings, (__bridge CFTypeRef)sslSettings);
(NSString*)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel,
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots,
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
[NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
[NSNull null], kCFStreamSSLPeerName,
nil];
CFReadStreamSetProperty(stream, kCFStreamPropertySSLSettings, (__bridge CFTypeRef)sslSettings);
}
[self reregisterForEvents];
@@ -660,12 +346,13 @@
self->httpStatusCode = 0;
// Open
if (!CFReadStreamOpen(self->stream))
if (!CFReadStreamOpen(stream))
{
CFRelease(self->stream);
CFRelease(stream);
CFRelease(message);
self->stream = NULL;
stream = 0;
[self errorOccured];
@@ -693,32 +380,4 @@
return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position];
}
-(BOOL) supportsSeek
{
return self->supportsSeek;
}
#pragma mark - Private
- (NSDictionary*)_processIcyMetadata:(NSData*)data
{
NSMutableDictionary *metadata = [NSMutableDictionary new];
NSString *metadataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray *pairs = [metadataString componentsSeparatedByString:@";"];
for(NSString *pair in pairs)
{
NSArray *components = [pair componentsSeparatedByString:@"="];
if(components.count < 2)
continue;
NSString *key = components[0];
NSString *value = [pair substringWithRange:NSMakeRange(key.length + 2, pair.length - (key.length + 2) - 1)];
[metadata setValue:value forKey:key];
}
return metadata;
}
@end
@@ -34,14 +34,10 @@
#import "STKCoreFoundationDataSource.h"
NS_ASSUME_NONNULL_BEGIN
@interface STKLocalFileDataSource : STKCoreFoundationDataSource
+(AudioFileTypeID) audioFileTypeHintFromFileExtension:(NSString*)fileExtension;
@property (readonly, copy) NSString* filePath;
-(instancetype) initWithFilePath:(NSString*)filePath;
-(id) initWithFilePath:(NSString*)filePath;
@end
NS_ASSUME_NONNULL_END
@@ -47,7 +47,7 @@
@implementation STKLocalFileDataSource
@synthesize filePath;
-(instancetype) initWithFilePath:(NSString*)filePathIn
-(id) initWithFilePath:(NSString*)filePathIn
{
if (self = [super init])
{
-29
View File
@@ -1,29 +0,0 @@
//
// STKMacro.h
// StreamingKit
//
// Created by Diego Stamigni on 20/03/2019.
// Copyright © 2019 Thong Nguyen. All rights reserved.
//
#pragma once
#import <objc/runtime.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) \
([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#endif
#define DEPLOYMENT_TARGET_HIGHER_THAN_10 TARGET_OS_WATCH || \
TARGET_OS_TV || \
(TARGET_OS_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) || \
(!TARGET_OS_IOS && __MAC_OS_X_VERSION_MIN_ALLOWED >= __MAC_10_12)
#define BASE_SDK_HIGHER_THAN_10 (TARGET_OS_WATCH || \
TARGET_OS_TV || \
(TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0) || \
(!TARGET_OS_IOS && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12))
#define DEVICE_HIGHER_THAN_10 objc_getClass("NSDimension")
+4 -9
View File
@@ -7,15 +7,13 @@
//
#import "STKDataSource.h"
#import "STKSpinLock.h"
#import "libkern/OSAtomic.h"
#import "AudioToolbox/AudioToolbox.h"
NS_ASSUME_NONNULL_BEGIN
@interface STKQueueEntry : NSObject
{
@public
os_unfair_lock spinLock;
OSSpinLock spinLock;
BOOL parsedHeader;
Float64 sampleRate;
@@ -30,14 +28,13 @@ NS_ASSUME_NONNULL_BEGIN
volatile int processedPacketsCount;
volatile int processedPacketsSizeTotal;
AudioStreamBasicDescription audioStreamBasicDescription;
double durationHint;
}
@property (readonly) UInt64 audioDataLengthInBytes;
@property (readwrite, retain) NSObject* queueItemId;
@property (readwrite, retain) STKDataSource* dataSource;
-(instancetype) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId;
-(id) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId;
-(void) reset;
-(double) duration;
@@ -45,6 +42,4 @@ NS_ASSUME_NONNULL_BEGIN
-(double) calculatedBitRate;
-(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription;
@end
NS_ASSUME_NONNULL_END
@end
+9 -12
View File
@@ -14,16 +14,15 @@
@implementation STKQueueEntry
-(instancetype) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn
-(id) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn
{
if (self = [super init])
{
self->spinLock = OS_UNFAIR_LOCK_INIT;
self->spinLock = OS_SPINLOCK_INIT;
self.dataSource = dataSourceIn;
self.queueItemId = queueItemIdIn;
self->lastFrameQueued = -1;
self->durationHint = dataSourceIn.durationHint;
}
return self;
@@ -31,11 +30,11 @@
-(void) reset
{
setLock(&self->spinLock);
OSSpinLockLock(&self->spinLock);
self->framesQueued = 0;
self->framesPlayed = 0;
self->lastFrameQueued = -1;
lockUnlock(&self->spinLock);
OSSpinLockUnlock(&self->spinLock);
}
-(double) calculatedBitRate
@@ -46,7 +45,7 @@
{
if (processedPacketsCount > STK_BIT_RATE_ESTIMATION_MIN_PACKETS_PREFERRED || (audioStreamBasicDescription.mBytesPerFrame == 0 && processedPacketsCount > STK_BIT_RATE_ESTIMATION_MIN_PACKETS_MIN))
{
double averagePacketByteSize = (double)processedPacketsSizeTotal / (double)processedPacketsCount;
double averagePacketByteSize = processedPacketsSizeTotal / processedPacketsCount;
retval = averagePacketByteSize / packetDuration * 8;
@@ -61,8 +60,6 @@
-(double) duration
{
if (durationHint > 0.0) return durationHint;
if (self->sampleRate <= 0)
{
return 0;
@@ -109,9 +106,9 @@
-(Float64) progressInFrames
{
setLock(&self->spinLock);
Float64 retval = (self->seekTime + self->audioStreamBasicDescription.mSampleRate) + self->framesPlayed;
lockUnlock(&self->spinLock);
OSSpinLockLock(&self->spinLock);
Float64 retval = self->seekTime + self->framesPlayed;
OSSpinLockUnlock(&self->spinLock);
return retval;
}
@@ -121,4 +118,4 @@
return [[self queueItemId] description];
}
@end
@end
-77
View File
@@ -1,77 +0,0 @@
//
// STKSpinLock.h
// StreamingKit
//
// Created by Diego Stamigni on 20/03/2019.
// Copyright © 2019 Thong Nguyen. All rights reserved.
//
#pragma once
#import "STKMacro.h"
#include <dlfcn.h>
#if BASE_SDK_HIGHER_THAN_10
#import <os/lock.h>
#else
#define OS_UNFAIR_LOCK_INIT ((os_unfair_lock){0})
typedef struct _os_unfair_lock_s {
uint32_t _os_unfair_lock_opaque;
} os_unfair_lock, *os_unfair_lock_t;
#endif
#if !DEPLOYMENT_TARGET_HIGHER_THAN_10
#import <libkern/OSAtomic.h>
static void (*os_unfair_lock_lock_ptr)(void *lock) = NULL;
static void (*os_unfair_lock_unlock_ptr)(void *lock) = NULL;
#endif
static void setLock(os_unfair_lock *lock)
{
#if DEPLOYMENT_TARGET_HIGHER_THAN_10
os_unfair_lock_lock(lock);
#else
if (DEVICE_HIGHER_THAN_10)
{
if (os_unfair_lock_lock_ptr == NULL)
{
os_unfair_lock_lock_ptr = dlsym(dlopen(NULL, RTLD_NOW | RTLD_GLOBAL), "os_unfair_lock_lock");
}
if (os_unfair_lock_lock_ptr != NULL)
{
os_unfair_lock_lock_ptr(lock);
return;
}
}
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
OSSpinLockLock((void *)lock);
#endif
}
static void lockUnlock(os_unfair_lock *lock)
{
#if DEPLOYMENT_TARGET_HIGHER_THAN_10
os_unfair_lock_unlock(lock);
#else
if (DEVICE_HIGHER_THAN_10)
{
if (os_unfair_lock_unlock_ptr == NULL)
{
os_unfair_lock_unlock_ptr = dlsym(dlopen(NULL, RTLD_NOW | RTLD_GLOBAL), "os_unfair_lock_unlock");
}
if (os_unfair_lock_unlock_ptr != NULL)
{
os_unfair_lock_unlock_ptr(lock);
return;
}
}
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
OSSpinLockUnlock((void *)lock);
#endif
}
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>abstractpath.com.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>