Compare commits

..

74 Commits

Author SHA1 Message Date
Thong Nguyen 1c78dc5867 Changed canonical format to fixed point for all platforms. Added metering view on ExampleAppMac 2014-02-02 14:19:12 +00:00
Thong Nguyen 4df5a84569 Added OSX build targets and ExampleAppMac. Added AudioUnit as a dependent framework in podspec 2014-02-02 13:14:37 +00:00
Thong Nguyen 70368a09ba Added pendingQueue, pendingQueueCount, mostRecentlyQueuedStillPendingItem. Added more documentation comments. Changed STKAudioPlayerInternalState to be private/hidden 2014-02-02 12:48:24 +00:00
Thong Nguyen 018da7a2eb Slight layout fix for AudioPlayerView 2014-02-01 23:29:39 +00:00
Thong Nguyen d347e5e80c Added mute/unmute support 2014-02-01 23:24:06 +00:00
Thong Nguyen 4d73784338 Added audio frame filtering and level metering support using Audio Units 2014-02-01 23:04:55 +00:00
Thong Nguyen 98c7d9b8f0 STKAudioPlayer:dataSourceFromURL uses case insensitive scheme compare 2014-02-01 00:29:02 +00:00
Thong Nguyen 56b2dd4ace Better range/length handling in STKHTTPDataSource. Handles out-of-range requests gracefully 2014-02-01 00:23:23 +00:00
Thong Nguyen a9b1e143a0 queueDataSource shold let playback thread automatically start the audio unit 2014-01-31 23:19:29 +00:00
Thong Nguyen c4a7251d19 Fixed potential crash when OutputRenderCallback is called with no items in the queue or playing 2014-01-31 23:07:49 +00:00
Thong Nguyen ae63d04b87 Don't stop audio player immediately when finished playing---wait until next runloop 2014-01-31 23:02:19 +00:00
Thong Nguyen dd7165b3d2 Fixed player somtimes waiting in buffering state for very small files 2014-01-31 22:58:07 +00:00
Thong Nguyen 8c94b9ba5c Added WAV file test to test app 2014-01-31 22:45:17 +00:00
Thong Nguyen c2fe2c68b2 Started adding framefilter support for EQ etc. Fixed seek bug with WAV files 2014-01-31 22:18:09 +00:00
Thong Nguyen 83bc40d5fc More documentation. STKAutoRecoveringHTTPDataSource is now default for HTTP 2014-01-31 20:46:41 +00:00
Thong Nguyen b903ee58cc Formatting fixes 2014-01-31 20:39:51 +00:00
Thong Nguyen 70fe37cd4a Added missing status checks 2014-01-31 20:35:44 +00:00
Thong Nguyen f321f1a0d7 More code tidy-ups 2014-01-31 20:33:15 +00:00
Thong Nguyen a0a9553631 Big refactor to remove remanents of AudioQueue code. Added safety locks when working with 64bit floats and ints across threads 2014-01-31 20:20:20 +00:00
Thong Nguyen ddc6cf4b2f Fixed newly set datasource is not immediately loaded because render callback changes resets the STKAudioPlayerInternalStatePendingNext state 2014-01-31 15:12:30 +00:00
Thong Nguyen 22e954a5e2 Added AudioUnit based progress/seek and queueing support 2014-01-31 14:40:20 +00:00
Thong Nguyen e7a952d248 Progress and seek now supported 2014-01-31 12:22:22 +00:00
Thong Nguyen 511185c929 More Audio Units work 2014-01-30 18:22:31 +00:00
Thong Nguyen 15b18069e3 Started removing legacy AudioQueue code 2014-01-30 12:46:41 +00:00
Thong Nguyen 6df11418f7 Started removing legacy AudioQueue code 2014-01-30 12:46:26 +00:00
Thong Nguyen cdb6f27a53 Disabled input IO when creating Audio Unit 2014-01-29 22:40:34 +00:00
Thong Nguyen b8528e30c5 Added remote control event handling to AppDelegate so that example app will show play icon in status bar 2014-01-29 22:30:52 +00:00
Thong Nguyen d5e531c602 Removed AudioUnit kAudioUnitScope_Output init code 2014-01-29 22:26:31 +00:00
Thong Nguyen 8d61f3a3e3 Removed AudioUnit kAudioUnitScope_Output init code 2014-01-29 22:25:25 +00:00
Thong Nguyen b0466171f6 Removed AudioUnit kAudioUnitScope_Output init code 2014-01-29 22:22:23 +00:00
Thong Nguyen 10d799a35f Got basic playback mostly working using AudioUnits 2014-01-29 22:09:38 +00:00
Thong Nguyen 08eaa7e85b Some more test work with using Audio Units 2014-01-29 18:41:29 +00:00
Thong Nguyen cd0dd97ebf Started experimenting with using AudioUnits rather than AudioQueues 2014-01-29 09:38:24 +00:00
Thong Nguyen b2eeb76c90 Fix STKAutoRecoveringHTTPDataSource not passing on unregisterForEvents. Fix STKCoreFoundationDataSource not unregisteringForEvents on dealloc 2014-01-29 09:27:51 +00:00
Thong Nguyen 5a6d93d7c1 Started experimenting with using AudioUnits rather than AudioQueues 2014-01-28 20:53:03 +00:00
Thong Nguyen 8dd611c2ac Prefixed all enum names and values 2014-01-28 14:04:58 +00:00
Thong Nguyen 4a0f944550 Removed some logging 2014-01-28 13:55:00 +00:00
Thong Nguyen f60e16c804 Tidied up some field types. Changed duration to return progress if progress is larger than duration and there is a duration 2014-01-27 21:33:10 +00:00
Thong Nguyen f3f52cf1cd Allow progress to be returned if the duration is 0 2014-01-27 19:46:35 +00:00
Thong Nguyen 53667f8a35 New lower-latecy rebuffering support 2014-01-27 19:38:32 +00:00
Thong Nguyen 6beebca443 Fixed deadlock on stopThread and dataSourceEof not always setting currentlReadingEntry to nil 2014-01-27 16:28:38 +00:00
Thong Nguyen 6af12221e5 Fixed potential crash in handleAudioPackets 2014-01-27 16:22:51 +00:00
Thong Nguyen ca80243083 Optimised seekToTime to avoid using the player thread mutex to allow smoother scrubbing 2014-01-27 02:00:01 +00:00
Thong Nguyen 804aa9dd6e All stopAudioQueue calls are now directed via the playback thread to reduce the need to have locks inside handleAudioQueueOutput. Added autorelease pool around regular processRunLoop call to fix STKDataSources not being freed (amongst other things). Fixed sometimes seeking to the very end of a slow loading track causes the didFinishPlayingQueueItemId event to not be raised 2014-01-27 01:23:18 +00:00
Thong Nguyen 0fdb461d90 Fixed bug in last commit that cuased playback to pause when seeking a file that's already fully buffered 2014-01-27 00:26:36 +00:00
Thong Nguyen 313a55a5ca Added more stable duration calculations 2014-01-26 23:57:00 +00:00
Thong Nguyen ba8b29d106 Fixed progress not correct when skipping a new track and the new track takes a while to buffer 2014-01-26 22:56:24 +00:00
Thong Nguyen 5b629665d6 createAudioQueue creates queues that start off paused by defualt to keep correct time if buffering is required befor the first buffers are rendered 2014-01-26 22:09:21 +00:00
Thong Nguyen 7608a42d29 Fixed dispose call hanging if player or audio thread are doing sync calls to the UI thread. Better rebuffering on 2G 2014-01-26 20:37:06 +00:00
Thong Nguyen 381795fed6 Fixed potential deadlock with clearQueue invokes callback on playback thread that may be blocking/waiting on audio packets 2014-01-26 15:43:39 +00:00
Thong Nguyen bd1d3c9aea A lot more support and fixups for rebuffering including new AudioPlayerStateBuffering state 2014-01-26 15:30:16 +00:00
Thong Nguyen 6ada345b17 Added better rebuffering handling. Pauses while rebuffering and doesn't start until there's a decent number of frames available 2014-01-26 01:04:24 +00:00
Thong Nguyen e495130219 More STKAutoRecoveringHTTPDataSource improvements 2014-01-25 14:30:41 +00:00
Thong Nguyen e843a0b730 Refactor and optimisation of STKHTTPDataSource and STKAutoRecoveringHTTPDataSource 2014-01-25 14:11:32 +00:00
Thong Nguyen b7f87aea98 Fixed next file won't start playing if queued on just before current one finishes 2014-01-25 13:59:11 +00:00
Thong Nguyen ca7abd75c1 Changed DataSources to open on-demand and also for callback registration to be performed before opening 2014-01-25 13:27:25 +00:00
Thong Nguyen 951f905516 Quite a big refactor to fix simplify and fix numerous threading and playback/position/buffering issues. Also all events are now synchronously raised to the UI thread via the playback thread which helps prevent lagged queued operations amongst other things 2014-01-24 19:11:52 +00:00
Thong Nguyen bd8e6a5da9 Fixes for errors when user skips to near the end of a track and another track is queued 2014-01-23 19:15:32 +00:00
Thong Nguyen 48ce1f9e67 Renamed all Http classes to HTTP. Udpated STKHTTPDataSource to accept asynchronous URL providers. Chnaged STKAudioPlaye to always flush upcoming queue when currently playing track is seeked 2014-01-23 16:23:18 +00:00
Thong Nguyen 257532c6c9 Added progress text to example app. Fixed finishedEvent not always being raised when user seeks to the last byte of the track 2014-01-23 12:43:22 +00:00
Thong Nguyen f85464236a Fix potential race/crash in createAudioQueue 2014-01-23 11:47:47 +00:00
Thong Nguyen b47771ae48 Formatting tidy-ups 2014-01-22 23:36:59 +00:00
Thong Nguyen 48e082ab88 Better default buffer sizes 2014-01-22 23:34:45 +00:00
Thong Nguyen b68e813750 Better default buffer sizes. Some code formatting tidy-ups 2014-01-22 23:33:49 +00:00
Thong Nguyen b4948882e4 Fixed async AudioQueue stop method for determing if a queued item has finished not taking into account upcoming queued items that aren't being decoded because they're incompatible 2014-01-22 22:52:51 +00:00
Thong Nguyen c100cb7202 Using a better mechanism for picking up when the last file on the queue is finished. Dont async-stop the AudioQueue unless it's nearing the end (handled in handleAudioQueueOutput rathe than dataSourceEof) 2014-01-22 22:41:24 +00:00
Thong Nguyen 593a08a04f Using a better mechanism for picking up when the last file on the queue is finished. Dont async-stop the AudioQueue unless it's nearing the end (handled in handleAudioQueueOutput rathe than dataSourceEof) 2014-01-22 22:40:23 +00:00
Thong Nguyen 1c9bd328e7 Removed test code and fixed an issue with not properly checking if the current queue should be stopped cause it's the last in the queue 2014-01-22 19:43:36 +00:00
Thong Nguyen dde738dffd Fixed finished event not raised if item is only item in queue. New timeline method of checking whether item has finished playing won't work if item is the only or last item in the queue as handleAudioQueueOutput isn't called once last packet is played (it's gets called if other items are queued). If no items are queued, the queue is stopped and the queue property event is used to figure out if its finished playing 2014-01-22 19:34:17 +00:00
Thong Nguyen a9bd3557a5 Changed progress to by more accurate by using AudioTime/timelines rather than bytes buffered 2014-01-22 16:52:47 +00:00
Thong Nguyen 431dd5d7f3 Moved AudioPlayerDefaultNumberOfAudioQueueBuffers define into source file from header 2014-01-22 10:25:30 +00:00
Thong Nguyen aaaed1f33f Added arm64 build back into StreamingKit. Moved private stuff out of STKAudioPlayer header files 2014-01-22 10:24:33 +00:00
Thong Nguyen 3563fb7ea1 Fixed STKHttpDataSource not copying urlProvider block 2014-01-22 09:38:37 +00:00
Thong Nguyen c9ba30b692 Removed iOS7 specific calls. Changed default target to iOS 4.3 2014-01-21 15:48:12 +00:00
45 changed files with 7529 additions and 1863 deletions
@@ -23,6 +23,7 @@
A1115967188D6AEE00641365 /* AudioPlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1115966188D6AEE00641365 /* AudioPlayerView.m */; };
A111596C188D6C8100641365 /* sample.m4a in Resources */ = {isa = PBXBuildFile; fileRef = A111596B188D6C8100641365 /* sample.m4a */; };
A111596F188D6DB100641365 /* SampleQueueId.m in Sources */ = {isa = PBXBuildFile; fileRef = A111596E188D6DB100641365 /* SampleQueueId.m */; };
A142571D189079BE005F0129 /* airplane.aac in Resources */ = {isa = PBXBuildFile; fileRef = A142571C18907861005F0129 /* airplane.aac */; };
A1EBEE64188DE34500681B04 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1EBEE63188DE34500681B04 /* SystemConfiguration.framework */; };
/* End PBXBuildFile section */
@@ -59,6 +60,7 @@
A111596B188D6C8100641365 /* sample.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; name = sample.m4a; path = Resources/sample.m4a; sourceTree = "<group>"; };
A111596D188D6DB100641365 /* SampleQueueId.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SampleQueueId.h; sourceTree = "<group>"; };
A111596E188D6DB100641365 /* SampleQueueId.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SampleQueueId.m; sourceTree = "<group>"; };
A142571C18907861005F0129 /* airplane.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = airplane.aac; sourceTree = "<group>"; };
A1EBEE63188DE34500681B04 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
@@ -168,6 +170,7 @@
A111596A188D6C4B00641365 /* Resources */ = {
isa = PBXGroup;
children = (
A142571C18907861005F0129 /* airplane.aac */,
A111596B188D6C8100641365 /* sample.m4a */,
);
name = Resources;
@@ -251,6 +254,7 @@
A111593F188D686000641365 /* InfoPlist.strings in Resources */,
A111596C188D6C8100641365 /* sample.m4a in Resources */,
A1115947188D686000641365 /* Images.xcassets in Resources */,
A142571D189079BE005F0129 /* airplane.aac in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -401,11 +405,14 @@
A111595E188D686000641365 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch";
INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -414,11 +421,14 @@
A111595F188D686000641365 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch";
INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
+36 -6
View File
@@ -9,7 +9,7 @@
#import "AppDelegate.h"
#import "STKAudioPlayer.h"
#import "AudioPlayerView.h"
#import "STKAutoRecoveringHttpDataSource.h"
#import "STKAutoRecoveringHTTPDataSource.h"
#import "SampleQueueId.h"
#import <AVFoundation/AVFoundation.h>
@@ -32,11 +32,16 @@
self.window.backgroundColor = [UIColor whiteColor];
audioPlayer = [[STKAudioPlayer alloc] init];
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:STKAudioPlayerOptionFlushQueueOnSeek];
audioPlayer.meteringEnabled = YES;
AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds];
audioPlayerView.delegate = self;
audioPlayerView.audioPlayer = audioPlayer;
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[self.window addSubview:audioPlayerView];
@@ -45,22 +50,47 @@
return YES;
}
-(BOOL) canBecomeFirstResponder
{
return YES;
}
-(void) audioPlayerViewPlayFromHTTPSelected:(AudioPlayerView*)audioPlayerView
{
NSURL* url = [NSURL URLWithString:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
STKAutoRecoveringHttpDataSource* dataSource = [[STKAutoRecoveringHttpDataSource alloc] initWithHttpDataSource:(STKHttpDataSource*)[audioPlayer dataSourceFromURL:url]];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
[audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
}
-(void) audioPlayerViewPlayFromLocalFileSelected:(AudioPlayerView*)audioPlayerView
-(void) audioPlayerViewQueueShortFileSelected:(AudioPlayerView*)audioPlayerView
{
NSString * path = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"m4a"];
NSString* path = [[NSBundle mainBundle] pathForResource:@"airplane" ofType:@"aac"];
NSURL* url = [NSURL fileURLWithPath:path];
[audioPlayer setDataSource:[audioPlayer dataSourceFromURL:url] withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
[audioPlayer queueDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
}
-(void) audioPlayerViewPlayFromLocalFileSelected:(AudioPlayerView*)audioPlayerView
{
NSString* path = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"m4a"];
NSURL* url = [NSURL fileURLWithPath:path];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
[audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
}
-(void) audioPlayerViewQueuePcmWaveFileSelected:(AudioPlayerView*)audioPlayerView
{
NSURL* url = [NSURL URLWithString:@"http://fs.bloom.fm/oss/audiosamples/perfectly.wav"];
STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url];
[audioPlayer queueDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
}
@end
+10
View File
@@ -39,17 +39,27 @@
@protocol AudioPlayerViewDelegate<NSObject>
-(void) audioPlayerViewPlayFromHTTPSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewQueueShortFileSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewPlayFromLocalFileSelected:(AudioPlayerView*)audioPlayerView;
-(void) audioPlayerViewQueuePcmWaveFileSelected:(AudioPlayerView*)audioPlayerView;
@end
@interface AudioPlayerView : UIView<STKAudioPlayerDelegate>
{
@private
NSTimer* timer;
UILabel* label;
UILabel* statusLabel;
UISlider* slider;
UISwitch* repeatSwitch;
UIButton* muteButton;
UIButton* playButton;
UIButton* stopButton;
UIButton* playFromHTTPButton;
UIButton* queueShortFileButton;
UIButton* queuePcmWaveFileFromHTTPButton;
UIButton* playFromLocalFileButton;
UIView* meter;
}
@property (readwrite, retain) STKAudioPlayer* audioPlayer;
+142 -26
View File
@@ -53,31 +53,78 @@
if (self)
{
CGSize size = CGSizeMake(180, 50);
CGSize size = CGSizeMake(220, 50);
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.15, 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];
playFromLocalFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.15 + 50, 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];
playButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playButton.frame = CGRectMake((320 - size.width) / 2, 350, size.width, size.height);
[playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside];
queueShortFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
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];
slider = [[UISlider alloc] initWithFrame:CGRectMake(20, 290, 280, 20)];
queuePcmWaveFileFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
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, 380, size.width, size.height);
[playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside];
stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
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((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, 280, 20)];
slider.continuous = YES;
[slider addTarget:self action:@selector(sliderChanged) forControlEvents:UIControlEventValueChanged];
size = CGSizeMake(80, 50);
repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake((320 - size.width) / 2, frame.size.height * 0.15 + 180, size.width, size.height)];
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 + 8, frame.size.width, 50)];
statusLabel.textAlignment = NSTextAlignmentCenter;
meter = [[UIView alloc] initWithFrame:CGRectMake(0, 450, 0, 20)];
meter.backgroundColor = [UIColor greenColor];
[self addSubview:slider];
[self addSubview:playButton];
[self addSubview:playFromHTTPButton];
[self addSubview:playFromLocalFileButton];
[self addSubview:queueShortFileButton];
[self addSubview:queuePcmWaveFileFromHTTPButton];
[self addSubview:repeatSwitch];
[self addSubview:label];
[self addSubview:statusLabel];
[self addSubview:stopButton];
[self addSubview:meter];
[self addSubview:muteButton];
[self setupTimer];
[self updateControls];
}
@@ -99,24 +146,44 @@
-(void) setupTimer
{
timer = [NSTimer timerWithTimeInterval:0.25 target:self selector:@selector(tick) userInfo:nil repeats:YES];
timer = [NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(tick) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void) tick
{
if (!audioPlayer || audioPlayer.duration == 0)
if (!audioPlayer)
{
slider.value = 0;
label.text = @"";
statusLabel.text = @"";
return;
}
slider.minimumValue = 0;
slider.maximumValue = audioPlayer.duration;
if (audioPlayer.duration != 0)
{
slider.minimumValue = 0;
slider.maximumValue = audioPlayer.duration;
slider.value = audioPlayer.progress;
label.text = [NSString stringWithFormat:@"%@ - %@", [self formatTimeFromSeconds:audioPlayer.progress], [self formatTimeFromSeconds:audioPlayer.duration]];
}
else
{
slider.value = 0;
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = @"";
}
statusLabel.text = audioPlayer.state == STKAudioPlayerStateBuffering ? @"buffering" : @"";
slider.value = audioPlayer.progress;
CGFloat newWidth = 320 * (([audioPlayer averagePowerInDecibelsForChannel:1] + 60) / 60);
meter.frame = CGRectMake(0, 460, newWidth, 20);
}
-(void) playFromHTTPButtonTouched
@@ -129,14 +196,43 @@
[self.delegate audioPlayerViewPlayFromLocalFileSelected:self];
}
-(void) queueShortFileButtonTouched
{
[self.delegate audioPlayerViewQueueShortFileSelected:self];
}
-(void) queuePcmWaveFileButtonTouched
{
[self.delegate audioPlayerViewQueuePcmWaveFileSelected:self];
}
-(void) muteButtonPressed
{
audioPlayer.muted = !audioPlayer.muted;
if (audioPlayer.muted)
{
[muteButton setTitle:@"Unmute" forState:UIControlStateNormal];
}
else
{
[muteButton setTitle:@"Mute" forState:UIControlStateNormal];
}
}
-(void) stopButtonPressed
{
[audioPlayer stop];
}
-(void) playButtonPressed
{
if (!audioPlayer)
{
return;
}
if (audioPlayer.state == AudioPlayerStatePaused)
if (audioPlayer.state == STKAudioPlayerStatePaused)
{
[audioPlayer resume];
}
@@ -146,24 +242,36 @@
}
}
-(NSString*) formatTimeFromSeconds:(int)totalSeconds
{
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
return [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
}
-(void) updateControls
{
if (audioPlayer == nil)
{
[playButton setTitle:@"Play" forState:UIControlStateNormal];
[playButton setTitle:@"" forState:UIControlStateNormal];
}
else if (audioPlayer.state == AudioPlayerStatePaused)
else if (audioPlayer.state == STKAudioPlayerStatePaused)
{
[playButton setTitle:@"Resume" forState:UIControlStateNormal];
}
else if (audioPlayer.state == AudioPlayerStatePlaying)
else if (audioPlayer.state & STKAudioPlayerStatePlaying)
{
[playButton setTitle:@"Pause" forState:UIControlStateNormal];
}
else
{
[playButton setTitle:@"Play" forState:UIControlStateNormal];
[playButton setTitle:@"" forState:UIControlStateNormal];
}
[self tick];
}
-(void) setAudioPlayer:(STKAudioPlayer*)value
@@ -184,12 +292,12 @@
return audioPlayer;
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(AudioPlayerState)state
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(STKAudioPlayerState)state previousState:(STKAudioPlayerState)previousState
{
[self updateControls];
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didEncounterError:(AudioPlayerErrorCode)errorCode
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer unexpectedError:(STKAudioPlayerErrorCode)errorCode
{
[self updateControls];
}
@@ -209,14 +317,17 @@
// This queues on the currently playing track to be buffered and played immediately after (gapless)
SampleQueueId* queueId = (SampleQueueId*)queueItemId;
if (repeatSwitch.on)
{
SampleQueueId* queueId = (SampleQueueId*)queueItemId;
NSLog(@"Requeuing: %@", [queueId.url description]);
NSLog(@"Requeuing: %@", [queueId.url description]);
[self->audioPlayer queueDataSource:[self->audioPlayer dataSourceFromURL:queueId.url] withQueueItemId:[[SampleQueueId alloc] initWithUrl:queueId.url andCount:queueId.count + 1]];
[self->audioPlayer queueDataSource:[STKAudioPlayer dataSourceFromURL:queueId.url] withQueueItemId:[[SampleQueueId alloc] initWithUrl:queueId.url andCount:queueId.count + 1]];
}
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(AudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(STKAudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration
{
[self updateControls];
@@ -225,4 +336,9 @@
NSLog(@"Finished: %@", [queueId.url description]);
}
-(void) audioPlayer:(STKAudioPlayer *)audioPlayer logInfo:(NSString *)line
{
NSLog(@"%@", line);
}
@end
+5
View File
@@ -36,4 +36,9 @@
return [((SampleQueueId*)object).url isEqual: self.url] && ((SampleQueueId*)object).count == self.count;
}
-(NSString*) description
{
return [self.url description];
}
@end
Binary file not shown.
@@ -0,0 +1,535 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
A1A499A5189E765800E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499A4189E765800E2A2E2 /* Cocoa.framework */; };
A1A499AF189E765800E2A2E2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A1A499AD189E765800E2A2E2 /* InfoPlist.strings */; };
A1A499B1189E765800E2A2E2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A499B0189E765800E2A2E2 /* main.m */; };
A1A499B5189E765800E2A2E2 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = A1A499B3189E765800E2A2E2 /* Credits.rtf */; };
A1A499B8189E765800E2A2E2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A499B7189E765800E2A2E2 /* AppDelegate.m */; };
A1A499BB189E765800E2A2E2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A1A499B9189E765800E2A2E2 /* MainMenu.xib */; };
A1A499BD189E765800E2A2E2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A1A499BC189E765800E2A2E2 /* Images.xcassets */; };
A1A499C4189E765800E2A2E2 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499C3189E765800E2A2E2 /* XCTest.framework */; };
A1A499C5189E765800E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499A4189E765800E2A2E2 /* Cocoa.framework */; };
A1A499CD189E765800E2A2E2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A1A499CB189E765800E2A2E2 /* InfoPlist.strings */; };
A1A499CF189E765800E2A2E2 /* ExampleAppMacTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A499CE189E765800E2A2E2 /* ExampleAppMacTests.m */; };
A1A499EC189E793300E2A2E2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499A9189E765800E2A2E2 /* Foundation.framework */; };
A1A499F0189E793D00E2A2E2 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499EF189E793D00E2A2E2 /* CoreAudio.framework */; };
A1A499F2189E799400E2A2E2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499F1189E799400E2A2E2 /* AudioToolbox.framework */; };
A1A499F3189E799F00E2A2E2 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499ED189E793700E2A2E2 /* AudioUnit.framework */; };
A1A499F5189E79CB00E2A2E2 /* CoreAudioKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499F4189E79CB00E2A2E2 /* CoreAudioKit.framework */; };
A1A499F9189E7A3500E2A2E2 /* libStreamingKitMac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499F8189E7A3500E2A2E2 /* libStreamingKitMac.a */; };
A1A499FA189E7A5600E2A2E2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499F1189E799400E2A2E2 /* AudioToolbox.framework */; };
A1A499FC189E7A6D00E2A2E2 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499FB189E7A6D00E2A2E2 /* SystemConfiguration.framework */; };
A1A499FD189E7BFC00E2A2E2 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A499ED189E793700E2A2E2 /* AudioUnit.framework */; };
A1A49A01189E82EC00E2A2E2 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A49A00189E82EC00E2A2E2 /* QuartzCore.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
A1A499C6189E765800E2A2E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A1A49999189E765800E2A2E2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = A1A499A0189E765800E2A2E2;
remoteInfo = ExampleAppMac;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
A1A499A1189E765800E2A2E2 /* ExampleAppMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleAppMac.app; sourceTree = BUILT_PRODUCTS_DIR; };
A1A499A4189E765800E2A2E2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
A1A499A7189E765800E2A2E2 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
A1A499A8189E765800E2A2E2 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
A1A499A9189E765800E2A2E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
A1A499AC189E765800E2A2E2 /* ExampleAppMac-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleAppMac-Info.plist"; sourceTree = "<group>"; };
A1A499AE189E765800E2A2E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
A1A499B0189E765800E2A2E2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
A1A499B2189E765800E2A2E2 /* ExampleAppMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ExampleAppMac-Prefix.pch"; sourceTree = "<group>"; };
A1A499B4189E765800E2A2E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
A1A499B6189E765800E2A2E2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
A1A499B7189E765800E2A2E2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
A1A499BA189E765800E2A2E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
A1A499BC189E765800E2A2E2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
A1A499C2189E765800E2A2E2 /* ExampleAppMacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleAppMacTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A1A499C3189E765800E2A2E2 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
A1A499CA189E765800E2A2E2 /* ExampleAppMacTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleAppMacTests-Info.plist"; sourceTree = "<group>"; };
A1A499CC189E765800E2A2E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
A1A499CE189E765800E2A2E2 /* ExampleAppMacTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleAppMacTests.m; sourceTree = "<group>"; };
A1A499EA189E76BD00E2A2E2 /* libStreamingKitMac.a */ = {isa = PBXFileReference; lastKnownFileType = file; name = libStreamingKitMac.a; path = ../StreamingKit/build/Debug/libStreamingKitMac.a; sourceTree = "<group>"; };
A1A499ED189E793700E2A2E2 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
A1A499EF189E793D00E2A2E2 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
A1A499F1189E799400E2A2E2 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
A1A499F4189E79CB00E2A2E2 /* CoreAudioKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; };
A1A499F8189E7A3500E2A2E2 /* libStreamingKitMac.a */ = {isa = PBXFileReference; lastKnownFileType = file; name = libStreamingKitMac.a; path = ../StreamingKit/build/Debug/libStreamingKitMac.a; sourceTree = "<group>"; };
A1A499FB189E7A6D00E2A2E2 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
A1A499FE189E82DD00E2A2E2 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
A1A49A00189E82EC00E2A2E2 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
A1A4999E189E765800E2A2E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1A49A01189E82EC00E2A2E2 /* QuartzCore.framework in Frameworks */,
A1A499FD189E7BFC00E2A2E2 /* AudioUnit.framework in Frameworks */,
A1A499FC189E7A6D00E2A2E2 /* SystemConfiguration.framework in Frameworks */,
A1A499FA189E7A5600E2A2E2 /* AudioToolbox.framework in Frameworks */,
A1A499F9189E7A3500E2A2E2 /* libStreamingKitMac.a in Frameworks */,
A1A499F0189E793D00E2A2E2 /* CoreAudio.framework in Frameworks */,
A1A499EC189E793300E2A2E2 /* Foundation.framework in Frameworks */,
A1A499A5189E765800E2A2E2 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1A499BF189E765800E2A2E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1A499F5189E79CB00E2A2E2 /* CoreAudioKit.framework in Frameworks */,
A1A499F3189E799F00E2A2E2 /* AudioUnit.framework in Frameworks */,
A1A499F2189E799400E2A2E2 /* AudioToolbox.framework in Frameworks */,
A1A499C5189E765800E2A2E2 /* Cocoa.framework in Frameworks */,
A1A499C4189E765800E2A2E2 /* XCTest.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A1A49998189E765800E2A2E2 = {
isa = PBXGroup;
children = (
A1A499AA189E765800E2A2E2 /* ExampleAppMac */,
A1A499C8189E765800E2A2E2 /* ExampleAppMacTests */,
A1A499A3189E765800E2A2E2 /* Frameworks */,
A1A499A2189E765800E2A2E2 /* Products */,
);
sourceTree = "<group>";
};
A1A499A2189E765800E2A2E2 /* Products */ = {
isa = PBXGroup;
children = (
A1A499A1189E765800E2A2E2 /* ExampleAppMac.app */,
A1A499C2189E765800E2A2E2 /* ExampleAppMacTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
A1A499A3189E765800E2A2E2 /* Frameworks */ = {
isa = PBXGroup;
children = (
A1A49A00189E82EC00E2A2E2 /* QuartzCore.framework */,
A1A499FE189E82DD00E2A2E2 /* CoreGraphics.framework */,
A1A499FB189E7A6D00E2A2E2 /* SystemConfiguration.framework */,
A1A499F8189E7A3500E2A2E2 /* libStreamingKitMac.a */,
A1A499F4189E79CB00E2A2E2 /* CoreAudioKit.framework */,
A1A499F1189E799400E2A2E2 /* AudioToolbox.framework */,
A1A499EF189E793D00E2A2E2 /* CoreAudio.framework */,
A1A499ED189E793700E2A2E2 /* AudioUnit.framework */,
A1A499EA189E76BD00E2A2E2 /* libStreamingKitMac.a */,
A1A499A4189E765800E2A2E2 /* Cocoa.framework */,
A1A499C3189E765800E2A2E2 /* XCTest.framework */,
A1A499A6189E765800E2A2E2 /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
A1A499A6189E765800E2A2E2 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
A1A499A7189E765800E2A2E2 /* AppKit.framework */,
A1A499A8189E765800E2A2E2 /* CoreData.framework */,
A1A499A9189E765800E2A2E2 /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
A1A499AA189E765800E2A2E2 /* ExampleAppMac */ = {
isa = PBXGroup;
children = (
A1A499B6189E765800E2A2E2 /* AppDelegate.h */,
A1A499B7189E765800E2A2E2 /* AppDelegate.m */,
A1A499B9189E765800E2A2E2 /* MainMenu.xib */,
A1A499BC189E765800E2A2E2 /* Images.xcassets */,
A1A499AB189E765800E2A2E2 /* Supporting Files */,
);
path = ExampleAppMac;
sourceTree = "<group>";
};
A1A499AB189E765800E2A2E2 /* Supporting Files */ = {
isa = PBXGroup;
children = (
A1A499AC189E765800E2A2E2 /* ExampleAppMac-Info.plist */,
A1A499AD189E765800E2A2E2 /* InfoPlist.strings */,
A1A499B0189E765800E2A2E2 /* main.m */,
A1A499B2189E765800E2A2E2 /* ExampleAppMac-Prefix.pch */,
A1A499B3189E765800E2A2E2 /* Credits.rtf */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
A1A499C8189E765800E2A2E2 /* ExampleAppMacTests */ = {
isa = PBXGroup;
children = (
A1A499CE189E765800E2A2E2 /* ExampleAppMacTests.m */,
A1A499C9189E765800E2A2E2 /* Supporting Files */,
);
path = ExampleAppMacTests;
sourceTree = "<group>";
};
A1A499C9189E765800E2A2E2 /* Supporting Files */ = {
isa = PBXGroup;
children = (
A1A499CA189E765800E2A2E2 /* ExampleAppMacTests-Info.plist */,
A1A499CB189E765800E2A2E2 /* InfoPlist.strings */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
A1A499A0189E765800E2A2E2 /* ExampleAppMac */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1A499D2189E765800E2A2E2 /* Build configuration list for PBXNativeTarget "ExampleAppMac" */;
buildPhases = (
A1A4999D189E765800E2A2E2 /* Sources */,
A1A4999E189E765800E2A2E2 /* Frameworks */,
A1A4999F189E765800E2A2E2 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = ExampleAppMac;
productName = ExampleAppMac;
productReference = A1A499A1189E765800E2A2E2 /* ExampleAppMac.app */;
productType = "com.apple.product-type.application";
};
A1A499C1189E765800E2A2E2 /* ExampleAppMacTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1A499D5189E765800E2A2E2 /* Build configuration list for PBXNativeTarget "ExampleAppMacTests" */;
buildPhases = (
A1A499BE189E765800E2A2E2 /* Sources */,
A1A499BF189E765800E2A2E2 /* Frameworks */,
A1A499C0189E765800E2A2E2 /* Resources */,
);
buildRules = (
);
dependencies = (
A1A499C7189E765800E2A2E2 /* PBXTargetDependency */,
);
name = ExampleAppMacTests;
productName = ExampleAppMacTests;
productReference = A1A499C2189E765800E2A2E2 /* ExampleAppMacTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
A1A49999189E765800E2A2E2 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
ORGANIZATIONNAME = "Thong Nguyen";
TargetAttributes = {
A1A499C1189E765800E2A2E2 = {
TestTargetID = A1A499A0189E765800E2A2E2;
};
};
};
buildConfigurationList = A1A4999C189E765800E2A2E2 /* Build configuration list for PBXProject "ExampleAppMac" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = A1A49998189E765800E2A2E2;
productRefGroup = A1A499A2189E765800E2A2E2 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
A1A499A0189E765800E2A2E2 /* ExampleAppMac */,
A1A499C1189E765800E2A2E2 /* ExampleAppMacTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
A1A4999F189E765800E2A2E2 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A499AF189E765800E2A2E2 /* InfoPlist.strings in Resources */,
A1A499BD189E765800E2A2E2 /* Images.xcassets in Resources */,
A1A499B5189E765800E2A2E2 /* Credits.rtf in Resources */,
A1A499BB189E765800E2A2E2 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1A499C0189E765800E2A2E2 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A499CD189E765800E2A2E2 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
A1A4999D189E765800E2A2E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A499B8189E765800E2A2E2 /* AppDelegate.m in Sources */,
A1A499B1189E765800E2A2E2 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1A499BE189E765800E2A2E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A499CF189E765800E2A2E2 /* ExampleAppMacTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
A1A499C7189E765800E2A2E2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = A1A499A0189E765800E2A2E2 /* ExampleAppMac */;
targetProxy = A1A499C6189E765800E2A2E2 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
A1A499AD189E765800E2A2E2 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
A1A499AE189E765800E2A2E2 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
A1A499B3189E765800E2A2E2 /* Credits.rtf */ = {
isa = PBXVariantGroup;
children = (
A1A499B4189E765800E2A2E2 /* en */,
);
name = Credits.rtf;
sourceTree = "<group>";
};
A1A499B9189E765800E2A2E2 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
A1A499BA189E765800E2A2E2 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
A1A499CB189E765800E2A2E2 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
A1A499CC189E765800E2A2E2 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
A1A499D0189E765800E2A2E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
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.9;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
A1A499D1189E765800E2A2E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = 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.9;
SDKROOT = macosx;
};
name = Release;
};
A1A499D3189E765800E2A2E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleAppMac/ExampleAppMac-Prefix.pch";
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
INFOPLIST_FILE = "ExampleAppMac/ExampleAppMac-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
A1A499D4189E765800E2A2E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleAppMac/ExampleAppMac-Prefix.pch";
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
INFOPLIST_FILE = "ExampleAppMac/ExampleAppMac-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Release;
};
A1A499D6189E765800E2A2E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ExampleAppMac.app/Contents/MacOS/ExampleAppMac";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleAppMac/ExampleAppMac-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "ExampleAppMacTests/ExampleAppMacTests-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
A1A499D7189E765800E2A2E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ExampleAppMac.app/Contents/MacOS/ExampleAppMac";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ExampleAppMac/ExampleAppMac-Prefix.pch";
INFOPLIST_FILE = "ExampleAppMacTests/ExampleAppMacTests-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
A1A4999C189E765800E2A2E2 /* Build configuration list for PBXProject "ExampleAppMac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1A499D0189E765800E2A2E2 /* Debug */,
A1A499D1189E765800E2A2E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A1A499D2189E765800E2A2E2 /* Build configuration list for PBXNativeTarget "ExampleAppMac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1A499D3189E765800E2A2E2 /* Debug */,
A1A499D4189E765800E2A2E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A1A499D5189E765800E2A2E2 /* Build configuration list for PBXNativeTarget "ExampleAppMacTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1A499D6189E765800E2A2E2 /* Debug */,
A1A499D7189E765800E2A2E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = A1A49999189E765800E2A2E2 /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:ExampleAppMac.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>B1180E29-F9F8-4232-A985-F8E21716EF14</string>
<key>IDESourceControlProjectName</key>
<string>ExampleAppMac</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</key>
<string>https://github.com/tumtumtum/StreamingKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>ExampleAppMac/ExampleAppMac.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<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>110</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>DD310C30-B3D0-4BD7-9565-9F29F09CC4F8</string>
<key>IDESourceControlWCCName</key>
<string>StreamingKit</string>
</dict>
</array>
</dict>
</plist>
+16
View File
@@ -0,0 +1,16 @@
//
// AppDelegate.h
// ExampleAppMac
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "STKAudioPlayer.h"
@interface AppDelegate : NSObject <NSApplicationDelegate, STKAudioPlayerDelegate>
@property (assign) IBOutlet NSWindow *window;
@end
+120
View File
@@ -0,0 +1,120 @@
//
// AppDelegate.m
// ExampleAppMac
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "AppDelegate.h"
#import "STKAudioPlayer.h"
@interface AppDelegate()
{
NSView* meter;
NSSlider* slider;
STKAudioPlayer* audioPlayer;
}
@end
@implementation AppDelegate
-(void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
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)];
slider = [[NSSlider alloc] initWithFrame:CGRectMake(10, 140, frame.size.width - 20, 20)];
[slider setAction:@selector(sliderChanged:)];
meter = [[NSView alloc] initWithFrame:CGRectMake(10, 200, 0, 20)];
[meter setLayer:[CALayer new]];
[meter setWantsLayer:YES];
meter.layer.backgroundColor = [NSColor greenColor].CGColor;
[[self.window contentView] addSubview:slider];
[[self.window contentView] addSubview:playFromHTTPButton];
[[self.window contentView] addSubview:meter];
audioPlayer = [[STKAudioPlayer alloc] init];
audioPlayer.delegate = self;
audioPlayer.meteringEnabled = YES;
[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(tick:) userInfo:nil repeats:YES];
}
-(void) playFromHTTP
{
[audioPlayer play:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
}
-(void) tick:(NSTimer*)timer
{
if (!audioPlayer)
{
slider.doubleValue = 0;
return;
}
CGFloat meterWidth = 0;
if (audioPlayer.duration != 0)
{
slider.minValue = 0;
slider.maxValue = audioPlayer.duration;
slider.doubleValue = audioPlayer.progress;
meterWidth = [self.window.contentView frame].size.width - 20;
meterWidth *= (([audioPlayer averagePowerInDecibelsForChannel:0] + 60) / 60);
}
else
{
slider.doubleValue = 0;
slider.minValue = 0;
slider.maxValue = 0;
meterWidth = 0;
}
CGRect frame = meter.frame;
frame.size.width = meterWidth;
meter.frame = frame;
}
-(void) sliderChanged:(NSSlider*)sliderIn
{
[audioPlayer seekToTime:sliderIn.doubleValue];
}
-(void) updateControls
{
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didStartPlayingQueueItemId:(NSObject*)queueItemId
{
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject*)queueItemId
{
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(STKAudioPlayerState)state previousState:(STKAudioPlayerState)previousState
{
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(STKAudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration
{
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer unexpectedError:(STKAudioPlayerErrorCode)errorCode
{
}
@end
@@ -0,0 +1,467 @@
<?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="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">
<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">
<menu key="submenu" title="ExampleAppMac" systemMenu="apple" id="57">
<items>
<menuItem title="About ExampleAppMac" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="236">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Preferences…" keyEquivalent="," id="129"/>
<menuItem isSeparatorItem="YES" id="143">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Services" id="131">
<menu key="submenu" title="Services" systemMenu="services" id="130"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="144">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Hide ExampleAppMac" keyEquivalent="h" id="134"/>
<menuItem title="Hide Others" keyEquivalent="h" id="145">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
</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"/>
</items>
</menu>
</menuItem>
<menuItem title="File" id="83">
<menu key="submenu" title="File" id="81">
<items>
<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"/>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="79">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</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"/>
</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"/>
</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"/>
<menuItem title="Redo" keyEquivalent="Z" id="215">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="206">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</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"/>
</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"/>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="534">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
</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"/>
</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"/>
<menuItem title="Check Document Now" keyEquivalent=";" id="201"/>
<menuItem isSeparatorItem="YES" id="453"/>
<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"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="348">
<menu key="submenu" title="Substitutions" id="349">
<items>
<menuItem title="Show Substitutions" id="457">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="459"/>
<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"/>
</menuItem>
<menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
</menuItem>
<menuItem title="Text Replacement" id="462">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="450">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="451">
<items>
<menuItem title="Make Upper Case" id="452">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Make Lower Case" id="465">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Capitalize" id="466">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="211">
<menu key="submenu" title="Speech" id="212">
<items>
<menuItem title="Start Speaking" id="196"/>
<menuItem title="Stop Speaking" id="195"/>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="375">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="376">
<items>
<menuItem title="Font" id="377">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="388">
<items>
<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"/>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="395"/>
<menuItem isSeparatorItem="YES" id="396"/>
<menuItem title="Kern" id="397">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="415">
<items>
<menuItem title="Use Default" id="416">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Use None" id="417">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Tighten" id="418">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Loosen" id="419">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="398">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="411">
<items>
<menuItem title="Use Default" id="412">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Use None" id="413">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Use All" id="414">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="399">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="405">
<items>
<menuItem title="Use Default" id="406">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Superscript" id="407">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Subscript" id="408">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Raise" id="409">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Lower" id="410">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="400"/>
<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"/>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="404">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="496">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="497">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="498"/>
<menuItem title="Center" keyEquivalent="|" id="499"/>
<menuItem title="Justify" id="500">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="501"/>
<menuItem isSeparatorItem="YES" id="502"/>
<menuItem title="Writing Direction" id="503">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="508">
<items>
<menuItem title="Paragraph" enabled="NO" id="509">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="510">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="511">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="512">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="513"/>
<menuItem title="Selection" enabled="NO" id="514">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="515">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="516">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="517">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="504"/>
<menuItem title="Show Ruler" id="505">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="506">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="507">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="295">
<menu key="submenu" title="View" id="296">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="297">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
</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"/>
<menuItem title="Zoom" id="239"/>
<menuItem isSeparatorItem="YES" id="92">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Bring All to Front" id="5"/>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="490">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="491">
<items>
<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" 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="2560" height="1418"/>
<view key="contentView" id="372">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
<customObject id="494" customClass="AppDelegate">
<connections>
<outlet property="window" destination="371" id="532"/>
</connections>
</customObject>
<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>
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2014 Thong Nguyen. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
@@ -0,0 +1,9 @@
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif
@@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,29 @@
{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw9840\paperh8400
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
\f0\b\fs24 \cf0 Engineering:
\b0 \
Some people\
\
\b Human Interface Design:
\b0 \
Some other people\
\
\b Testing:
\b0 \
Hopefully not nobody\
\
\b Documentation:
\b0 \
Whoever\
\
\b With special thanks to:
\b0 \
Mom\
}
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
+14
View File
@@ -0,0 +1,14 @@
//
// main.m
// ExampleAppMac
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[])
{
return NSApplicationMain(argc, argv);
}
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
@@ -0,0 +1,34 @@
//
// ExampleAppMacTests.m
// ExampleAppMacTests
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface ExampleAppMacTests : XCTestCase
@end
@implementation ExampleAppMacTests
- (void)setUp
{
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample
{
XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
}
@end
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
+1 -1
View File
@@ -9,5 +9,5 @@ Pod::Spec.new do |s|
s.platform = :ios
s.requires_arc = true
s.source_files = 'StreamingKit/StreamingKit/*.{h,m}'
s.frameworks = 'AVFoundation', 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox'
s.frameworks = 'AVFoundation', 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox', 'AudioUnit'
end
+1 -1
View File
@@ -9,5 +9,5 @@ Pod::Spec.new do |s|
s.platform = :ios
s.requires_arc = true
s.source_files = 'StreamingKit/StreamingKit/*.{h,m}'
s.frameworks = 'AVFoundation', 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox'
s.frameworks = 'AVFoundation', 'SystemConfiguration', 'CFNetwork', 'CoreFoundation', 'AudioToolbox', 'AudioUnit'
end
+3
View File
@@ -4,6 +4,9 @@
<FileRef
location = "group:ExampleApp/ExampleApp.xcodeproj">
</FileRef>
<FileRef
location = "group:StreamingKit/../ExampleAppMac/ExampleAppMac.xcodeproj">
</FileRef>
<FileRef
location = "group:StreamingKit/StreamingKit.xcodeproj">
</FileRef>
@@ -7,23 +7,60 @@
objects = {
/* Begin PBXBuildFile section */
A1E7C4CC188D57F50010896F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4CB188D57F50010896F /* Foundation.framework */; };
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 */; };
A1A4997C189E744500E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4996A189E744400E2A2E2 /* Cocoa.framework */; };
A1A4997F189E744500E2A2E2 /* libStreamingKitMac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */; };
A1A49985189E744500E2A2E2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A1A49983189E744500E2A2E2 /* InfoPlist.strings */; };
A1A49987189E744500E2A2E2 /* StreamingKitMacTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A49986189E744500E2A2E2 /* StreamingKitMacTests.m */; };
A1A4998E189E745900E2A2E2 /* STKAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */; };
A1A4998F189E745C00E2A2E2 /* STKAutoRecoveringHTTPDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F4188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m */; };
A1A49991189E746000E2A2E2 /* STKCoreFoundationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F6188D5E550010896F /* STKCoreFoundationDataSource.m */; };
A1A49992189E746300E2A2E2 /* STKDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F8188D5E550010896F /* STKDataSource.m */; };
A1A49993189E746500E2A2E2 /* STKDataSourceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FA188D5E550010896F /* STKDataSourceWrapper.m */; };
A1A49994189E746900E2A2E2 /* STKHTTPDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */; };
A1A49995189E746B00E2A2E2 /* STKLocalFileDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */; };
A1A49996189E746E00E2A2E2 /* STKQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = A1BF65D1189A6582004DD08C /* STKQueueEntry.m */; };
A1A49997189E747000E2A2E2 /* NSMutableArray+STKAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A1BF65D4189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m */; };
A1BF65D2189A6582004DD08C /* STKQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = A1BF65D1189A6582004DD08C /* STKQueueEntry.m */; };
A1BF65D5189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A1BF65D4189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m */; };
A1E7C4DA188D57F60010896F /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4D9188D57F60010896F /* XCTest.framework */; };
A1E7C4DB188D57F60010896F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4CB188D57F50010896F /* Foundation.framework */; };
A1E7C4E0188D57F60010896F /* libStreamingKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4C8188D57F50010896F /* libStreamingKit.a */; };
A1E7C4E6188D57F60010896F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A1E7C4E4188D57F60010896F /* InfoPlist.strings */; };
A1E7C4E8188D57F60010896F /* StreamingKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4E7188D57F60010896F /* StreamingKitTests.m */; };
A1E7C4FF188D5E550010896F /* STKAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */; };
A1E7C500188D5E550010896F /* STKAutoRecoveringHttpDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F4188D5E550010896F /* STKAutoRecoveringHttpDataSource.m */; };
A1E7C500188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F4188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m */; };
A1E7C501188D5E550010896F /* STKCoreFoundationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F6188D5E550010896F /* STKCoreFoundationDataSource.m */; };
A1E7C502188D5E550010896F /* STKDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4F8188D5E550010896F /* STKDataSource.m */; };
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FA188D5E550010896F /* STKDataSourceWrapper.m */; };
A1E7C504188D5E550010896F /* STKHttpDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FC188D5E550010896F /* STKHttpDataSource.m */; };
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */; };
A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */; };
A1E7C508188D62D20010896F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C507188D62D20010896F /* UIKit.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
A1A4997D189E744500E2A2E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A1E7C4C0188D57F50010896F /* Project object */;
proxyType = 1;
remoteGlobalIDString = A1A49968189E744400E2A2E2;
remoteInfo = StreamingKitMac;
};
A1A499E6189E769A00E2A2E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A1A499E1189E769A00E2A2E2 /* ExampleAppMac.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A1A499A1189E765800E2A2E2;
remoteInfo = ExampleAppMac;
};
A1A499E8189E769A00E2A2E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A1A499E1189E769A00E2A2E2 /* ExampleAppMac.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A1A499C2189E765800E2A2E2;
remoteInfo = ExampleAppMacTests;
};
A1E7C4DE188D57F60010896F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A1E7C4C0188D57F50010896F /* Project object */;
@@ -46,6 +83,25 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
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; };
A1A4996E189E744500E2A2E2 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
A1A4996F189E744500E2A2E2 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
A1A49972189E744500E2A2E2 /* StreamingKitMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StreamingKitMac-Prefix.pch"; sourceTree = "<group>"; };
A1A49973189E744500E2A2E2 /* StreamingKitMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StreamingKitMac.h; sourceTree = "<group>"; };
A1A49974189E744500E2A2E2 /* StreamingKitMac.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StreamingKitMac.m; sourceTree = "<group>"; };
A1A4997A189E744500E2A2E2 /* StreamingKitMacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StreamingKitMacTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A1A49982189E744500E2A2E2 /* StreamingKitMacTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "StreamingKitMacTests-Info.plist"; sourceTree = "<group>"; };
A1A49984189E744500E2A2E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
A1A49986189E744500E2A2E2 /* StreamingKitMacTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StreamingKitMacTests.m; sourceTree = "<group>"; };
A1A499E1189E769A00E2A2E2 /* ExampleAppMac.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ExampleAppMac.xcodeproj; path = ../ExampleAppMac/ExampleAppMac.xcodeproj; sourceTree = "<group>"; };
A1A499F6189E79EA00E2A2E2 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
A1BF65D0189A6582004DD08C /* STKQueueEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKQueueEntry.h; sourceTree = "<group>"; };
A1BF65D1189A6582004DD08C /* STKQueueEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKQueueEntry.m; sourceTree = "<group>"; };
A1BF65D3189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+STKAudioPlayer.h"; sourceTree = "<group>"; };
A1BF65D4189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+STKAudioPlayer.m"; sourceTree = "<group>"; };
A1C9767618981BFE0057F881 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
A1E7C4C8188D57F50010896F /* libStreamingKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStreamingKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
A1E7C4CB188D57F50010896F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
A1E7C4CF188D57F50010896F /* StreamingKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StreamingKit-Prefix.pch"; sourceTree = "<group>"; };
@@ -56,28 +112,44 @@
A1E7C4E7188D57F60010896F /* StreamingKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StreamingKitTests.m; sourceTree = "<group>"; };
A1E7C4F1188D5E550010896F /* STKAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKAudioPlayer.h; sourceTree = "<group>"; };
A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKAudioPlayer.m; sourceTree = "<group>"; };
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHttpDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKAutoRecoveringHttpDataSource.h; sourceTree = "<group>"; };
A1E7C4F4188D5E550010896F /* STKAutoRecoveringHttpDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKAutoRecoveringHttpDataSource.m; sourceTree = "<group>"; };
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKAutoRecoveringHTTPDataSource.h; sourceTree = "<group>"; };
A1E7C4F4188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKAutoRecoveringHTTPDataSource.m; sourceTree = "<group>"; };
A1E7C4F5188D5E550010896F /* STKCoreFoundationDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKCoreFoundationDataSource.h; sourceTree = "<group>"; };
A1E7C4F6188D5E550010896F /* STKCoreFoundationDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKCoreFoundationDataSource.m; sourceTree = "<group>"; };
A1E7C4F7188D5E550010896F /* STKDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKDataSource.h; sourceTree = "<group>"; };
A1E7C4F8188D5E550010896F /* STKDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKDataSource.m; sourceTree = "<group>"; };
A1E7C4F9188D5E550010896F /* STKDataSourceWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKDataSourceWrapper.h; sourceTree = "<group>"; };
A1E7C4FA188D5E550010896F /* STKDataSourceWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKDataSourceWrapper.m; sourceTree = "<group>"; };
A1E7C4FB188D5E550010896F /* STKHttpDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKHttpDataSource.h; sourceTree = "<group>"; };
A1E7C4FC188D5E550010896F /* STKHttpDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKHttpDataSource.m; sourceTree = "<group>"; };
A1E7C4FB188D5E550010896F /* STKHTTPDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKHTTPDataSource.h; sourceTree = "<group>"; };
A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKHTTPDataSource.m; sourceTree = "<group>"; };
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; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
A1A49966189E744400E2A2E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1A49977189E744500E2A2E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1A4997C189E744500E2A2E2 /* Cocoa.framework in Frameworks */,
A1A4997B189E744500E2A2E2 /* XCTest.framework in Frameworks */,
A1A4997F189E744500E2A2E2 /* libStreamingKitMac.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1E7C4C5188D57F50010896F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1E7C508188D62D20010896F /* UIKit.framework in Frameworks */,
A1E7C4CC188D57F50010896F /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -94,13 +166,71 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A1A4996C189E744500E2A2E2 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
A1A4996D189E744500E2A2E2 /* Foundation.framework */,
A1A4996E189E744500E2A2E2 /* CoreData.framework */,
A1A4996F189E744500E2A2E2 /* AppKit.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
A1A49970189E744500E2A2E2 /* StreamingKitMac */ = {
isa = PBXGroup;
children = (
A1A49973189E744500E2A2E2 /* StreamingKitMac.h */,
A1A49974189E744500E2A2E2 /* StreamingKitMac.m */,
A1A49971189E744500E2A2E2 /* Supporting Files */,
);
path = StreamingKitMac;
sourceTree = "<group>";
};
A1A49971189E744500E2A2E2 /* Supporting Files */ = {
isa = PBXGroup;
children = (
A1A49972189E744500E2A2E2 /* StreamingKitMac-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
A1A49980189E744500E2A2E2 /* StreamingKitMacTests */ = {
isa = PBXGroup;
children = (
A1A49986189E744500E2A2E2 /* StreamingKitMacTests.m */,
A1A49981189E744500E2A2E2 /* Supporting Files */,
);
path = StreamingKitMacTests;
sourceTree = "<group>";
};
A1A49981189E744500E2A2E2 /* Supporting Files */ = {
isa = PBXGroup;
children = (
A1A49982189E744500E2A2E2 /* StreamingKitMacTests-Info.plist */,
A1A49983189E744500E2A2E2 /* InfoPlist.strings */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
A1A499E2189E769A00E2A2E2 /* Products */ = {
isa = PBXGroup;
children = (
A1A499E7189E769A00E2A2E2 /* ExampleAppMac.app */,
A1A499E9189E769A00E2A2E2 /* ExampleAppMacTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
A1E7C4BF188D57F50010896F = {
isa = PBXGroup;
children = (
A1E7C4CD188D57F50010896F /* StreamingKit */,
A1E7C4E1188D57F60010896F /* StreamingKitTests */,
A1A49970189E744500E2A2E2 /* StreamingKitMac */,
A1A49980189E744500E2A2E2 /* StreamingKitMacTests */,
A1E7C4CA188D57F50010896F /* Frameworks */,
A1E7C4C9188D57F50010896F /* Products */,
A1A499E1189E769A00E2A2E2 /* ExampleAppMac.xcodeproj */,
);
sourceTree = "<group>";
};
@@ -109,6 +239,8 @@
children = (
A1E7C4C8188D57F50010896F /* libStreamingKit.a */,
A1E7C4D8188D57F60010896F /* StreamingKitTests.xctest */,
A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */,
A1A4997A189E744500E2A2E2 /* StreamingKitMacTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -116,9 +248,13 @@
A1E7C4CA188D57F50010896F /* Frameworks */ = {
isa = PBXGroup;
children = (
A1A499F6189E79EA00E2A2E2 /* AudioToolbox.framework */,
A1C9767618981BFE0057F881 /* AudioUnit.framework */,
A1E7C507188D62D20010896F /* UIKit.framework */,
A1E7C4CB188D57F50010896F /* Foundation.framework */,
A1E7C4D9188D57F60010896F /* XCTest.framework */,
A1A4996A189E744400E2A2E2 /* Cocoa.framework */,
A1A4996C189E744500E2A2E2 /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -128,18 +264,22 @@
children = (
A1E7C4F1188D5E550010896F /* STKAudioPlayer.h */,
A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */,
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHttpDataSource.h */,
A1E7C4F4188D5E550010896F /* STKAutoRecoveringHttpDataSource.m */,
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */,
A1E7C4F4188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m */,
A1E7C4F5188D5E550010896F /* STKCoreFoundationDataSource.h */,
A1E7C4F6188D5E550010896F /* STKCoreFoundationDataSource.m */,
A1E7C4F7188D5E550010896F /* STKDataSource.h */,
A1E7C4F8188D5E550010896F /* STKDataSource.m */,
A1E7C4F9188D5E550010896F /* STKDataSourceWrapper.h */,
A1E7C4FA188D5E550010896F /* STKDataSourceWrapper.m */,
A1E7C4FB188D5E550010896F /* STKHttpDataSource.h */,
A1E7C4FC188D5E550010896F /* STKHttpDataSource.m */,
A1E7C4FB188D5E550010896F /* STKHTTPDataSource.h */,
A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */,
A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */,
A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */,
A1BF65D0189A6582004DD08C /* STKQueueEntry.h */,
A1BF65D1189A6582004DD08C /* STKQueueEntry.m */,
A1BF65D3189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.h */,
A1BF65D4189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m */,
A1E7C4CE188D57F50010896F /* Supporting Files */,
);
path = StreamingKit;
@@ -173,7 +313,52 @@
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
A1A49967189E744400E2A2E2 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
A1A49968189E744400E2A2E2 /* StreamingKitMac */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1A4998C189E744500E2A2E2 /* Build configuration list for PBXNativeTarget "StreamingKitMac" */;
buildPhases = (
A1A49965189E744400E2A2E2 /* Sources */,
A1A49966189E744400E2A2E2 /* Frameworks */,
A1A49967189E744400E2A2E2 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = StreamingKitMac;
productName = StreamingKitMac;
productReference = A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */;
productType = "com.apple.product-type.library.static";
};
A1A49979189E744500E2A2E2 /* StreamingKitMacTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1A4998D189E744500E2A2E2 /* Build configuration list for PBXNativeTarget "StreamingKitMacTests" */;
buildPhases = (
A1A49976189E744500E2A2E2 /* Sources */,
A1A49977189E744500E2A2E2 /* Frameworks */,
A1A49978189E744500E2A2E2 /* Resources */,
);
buildRules = (
);
dependencies = (
A1A4997E189E744500E2A2E2 /* PBXTargetDependency */,
);
name = StreamingKitMacTests;
productName = StreamingKitMacTests;
productReference = A1A4997A189E744500E2A2E2 /* StreamingKitMacTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
A1E7C4C7188D57F50010896F /* StreamingKit */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1E7C4EB188D57F60010896F /* Build configuration list for PBXNativeTarget "StreamingKit" */;
@@ -229,15 +414,48 @@
mainGroup = A1E7C4BF188D57F50010896F;
productRefGroup = A1E7C4C9188D57F50010896F /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = A1A499E2189E769A00E2A2E2 /* Products */;
ProjectRef = A1A499E1189E769A00E2A2E2 /* ExampleAppMac.xcodeproj */;
},
);
projectRoot = "";
targets = (
A1E7C4C7188D57F50010896F /* StreamingKit */,
A1E7C4D7188D57F60010896F /* StreamingKitTests */,
A1A49968189E744400E2A2E2 /* StreamingKitMac */,
A1A49979189E744500E2A2E2 /* StreamingKitMacTests */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
A1A499E7189E769A00E2A2E2 /* ExampleAppMac.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = ExampleAppMac.app;
remoteRef = A1A499E6189E769A00E2A2E2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
A1A499E9189E769A00E2A2E2 /* ExampleAppMacTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = ExampleAppMacTests.xctest;
remoteRef = A1A499E8189E769A00E2A2E2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
A1A49978189E744500E2A2E2 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A49985189E744500E2A2E2 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1E7C4D6188D57F60010896F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -249,6 +467,31 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
A1A49965189E744400E2A2E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A4998F189E745C00E2A2E2 /* STKAutoRecoveringHTTPDataSource.m in Sources */,
A1A49994189E746900E2A2E2 /* STKHTTPDataSource.m in Sources */,
A1A49991189E746000E2A2E2 /* STKCoreFoundationDataSource.m in Sources */,
A1A49995189E746B00E2A2E2 /* STKLocalFileDataSource.m in Sources */,
A1A49997189E747000E2A2E2 /* NSMutableArray+STKAudioPlayer.m in Sources */,
A1A4998E189E745900E2A2E2 /* STKAudioPlayer.m in Sources */,
A1A49993189E746500E2A2E2 /* STKDataSourceWrapper.m in Sources */,
A1A49992189E746300E2A2E2 /* STKDataSource.m in Sources */,
A1A49975189E744500E2A2E2 /* StreamingKitMac.m in Sources */,
A1A49996189E746E00E2A2E2 /* STKQueueEntry.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1A49976189E744500E2A2E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1A49987189E744500E2A2E2 /* StreamingKitMacTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A1E7C4C4188D57F50010896F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -256,10 +499,12 @@
A1E7C501188D5E550010896F /* STKCoreFoundationDataSource.m in Sources */,
A1E7C4FF188D5E550010896F /* STKAudioPlayer.m in Sources */,
A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */,
A1E7C504188D5E550010896F /* STKHttpDataSource.m in Sources */,
A1BF65D2189A6582004DD08C /* STKQueueEntry.m in Sources */,
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */,
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */,
A1E7C502188D5E550010896F /* STKDataSource.m in Sources */,
A1E7C500188D5E550010896F /* STKAutoRecoveringHttpDataSource.m in Sources */,
A1BF65D5189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m in Sources */,
A1E7C500188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -274,6 +519,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
A1A4997E189E744500E2A2E2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = A1A49968189E744400E2A2E2 /* StreamingKitMac */;
targetProxy = A1A4997D189E744500E2A2E2 /* PBXContainerItemProxy */;
};
A1E7C4DF188D57F60010896F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = A1E7C4C7188D57F50010896F /* StreamingKit */;
@@ -282,6 +532,14 @@
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
A1A49983189E744500E2A2E2 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
A1A49984189E744500E2A2E2 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
A1E7C4E4188D57F60010896F /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
@@ -293,6 +551,86 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
A1A49988189E744500E2A2E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Debug;
};
A1A49989189E744500E2A2E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Release;
};
A1A4998A189E744500E2A2E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "StreamingKitMacTests/StreamingKitMacTests-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
A1A4998B189E744500E2A2E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch";
INFOPLIST_FILE = "StreamingKitMacTests/StreamingKitMacTests-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
A1E7C4E9188D57F60010896F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -325,7 +663,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
@@ -357,7 +695,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
@@ -366,6 +704,7 @@
A1E7C4EC188D57F60010896F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
DSTROOT = /tmp/StreamingKit.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -382,6 +721,7 @@
A1E7C4ED188D57F60010896F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
DSTROOT = /tmp/StreamingKit.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -436,6 +776,22 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
A1A4998C189E744500E2A2E2 /* Build configuration list for PBXNativeTarget "StreamingKitMac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1A49988189E744500E2A2E2 /* Debug */,
A1A49989189E744500E2A2E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
A1A4998D189E744500E2A2E2 /* Build configuration list for PBXNativeTarget "StreamingKitMacTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1A4998A189E744500E2A2E2 /* Debug */,
A1A4998B189E744500E2A2E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
A1E7C4C3188D57F50010896F /* Build configuration list for PBXProject "StreamingKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -452,6 +808,7 @@
A1E7C4ED188D57F60010896F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A1E7C4EE188D57F60010896F /* Build configuration list for PBXNativeTarget "StreamingKitTests" */ = {
isa = XCConfigurationList;
@@ -460,6 +817,7 @@
A1E7C4F0188D57F60010896F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
@@ -0,0 +1,17 @@
//
// NSMutableArray+STKAudioPlayer.h
// StreamingKit
//
// Created by Thong Nguyen on 30/01/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSMutableArray (STKAudioPlayer)
-(void) enqueue:(id)obj;
-(void) skipQueue:(id)obj;
-(void) skipQueueWithQueue:(NSMutableArray*)queue;
-(id) dequeue;
-(id) peek;
@end
@@ -0,0 +1,50 @@
//
// NSMutableArray+STKAudioPlayer.m
// StreamingKit
//
// Created by Thong Nguyen on 30/01/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "NSMutableArray+STKAudioPlayer.h"
@implementation NSMutableArray (STKAudioPlayer)
-(void) enqueue:(id)obj
{
[self insertObject:obj atIndex:0];
}
-(void) skipQueue:(id)obj
{
[self addObject:obj];
}
-(void) skipQueueWithQueue:(NSMutableArray*)queue
{
for (id item in queue)
{
[self addObject:item];
}
}
-(id) dequeue
{
if ([self count] == 0)
{
return nil;
}
id retval = [self lastObject];
[self removeLastObject];
return retval;
}
-(id) peek
{
return [self lastObject];
}
@end
File diff suppressed because it is too large Load Diff
+122 -65
View File
@@ -2,12 +2,12 @@
AudioPlayer.m
Created by Thong Nguyen on 14/05/2012.
https://github.com/tumtumtum/audjustable
https://github.com/tumtumtum/StreamingKit
Inspired by Matt Gallagher's AudioStreamer:
https://github.com/mattgallagher/AudioStreamer
Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -44,113 +44,170 @@
#include "UIKit/UIApplication.h"
#endif
#define AudioPlayerDefaultNumberOfAudioQueueBuffers (10 * 1024)
typedef enum
{
STKAudioPlayerStateReady,
STKAudioPlayerStateRunning = 1,
STKAudioPlayerStatePlaying = (1 << 1) | STKAudioPlayerStateRunning,
STKAudioPlayerStateBuffering = (1 << 2) | STKAudioPlayerStateRunning,
STKAudioPlayerStatePaused = (1 << 3) | STKAudioPlayerStateRunning,
STKAudioPlayerStateStopped = (1 << 4),
STKAudioPlayerStateError = (1 << 5),
STKAudioPlayerStateDisposed = (1 << 6)
}
STKAudioPlayerState;
typedef enum
{
AudioPlayerInternalStateInitialised = 0,
AudioPlayerInternalStateRunning = 1,
AudioPlayerInternalStatePlaying = (1 << 1) | AudioPlayerInternalStateRunning,
AudioPlayerInternalStateStartingThread = (1 << 2) | AudioPlayerInternalStateRunning,
AudioPlayerInternalStateWaitingForData = (1 << 3) | AudioPlayerInternalStateRunning,
AudioPlayerInternalStateWaitingForQueueToStart = (1 << 4) | AudioPlayerInternalStateRunning,
AudioPlayerInternalStatePaused = (1 << 5) | AudioPlayerInternalStateRunning,
AudioPlayerInternalStateRebuffering = (1 << 6) | AudioPlayerInternalStateRunning,
AudioPlayerInternalStateStopping = (1 << 7),
AudioPlayerInternalStateStopped = (1 << 8),
AudioPlayerInternalStateDisposed = (1 << 9),
AudioPlayerInternalStateError = (1 << 10)
STKAudioPlayerStopReasonNone = 0,
STKAudioPlayerStopReasonEof,
STKAudioPlayerStopReasonUserAction,
STKAudioPlayerStopReasonError = 0xffff
}
AudioPlayerInternalState;
STKAudioPlayerStopReason;
typedef enum
{
AudioPlayerStateReady,
AudioPlayerStateRunning = 1,
AudioPlayerStatePlaying = (1 << 1) | AudioPlayerStateRunning,
AudioPlayerStatePaused = (1 << 2) | AudioPlayerStateRunning,
AudioPlayerStateStopped = (1 << 3),
AudioPlayerStateError = (1 << 4),
AudioPlayerStateDisposed = (1 << 5)
STKAudioPlayerErrorNone = 0,
STKAudioPlayerErrorDataSource,
STKAudioPlayerErrorStreamParseBytesFailed,
STKAudioPlayerErrorAudioSystemError,
STKAudioPlayerErrorCodecError,
STKAudioPlayerErrorDataNotFound,
STKAudioPlayerErrorOther = 0xffff
}
AudioPlayerState;
STKAudioPlayerErrorCode;
typedef enum
{
AudioPlayerStopReasonNoStop = 0,
AudioPlayerStopReasonEof,
AudioPlayerStopReasonUserAction,
AudioPlayerStopReasonUserActionFlushStop
STKAudioPlayerOptionNone = 0,
STKAudioPlayerOptionFlushQueueOnSeek = 1
}
AudioPlayerStopReason;
STKAudioPlayerOptions;
typedef enum
{
AudioPlayerErrorNone = 0,
AudioPlayerErrorDataSource,
AudioPlayerErrorStreamParseBytesFailed,
AudioPlayerErrorDataNotFound,
AudioPlayerErrorQueueStartFailed,
AudioPlayerErrorQueuePauseFailed,
AudioPlayerErrorUnknownBuffer,
AudioPlayerErrorQueueStopFailed,
AudioPlayerErrorQueueCreationFailed,
AudioPlayerErrorOther = -1
}
AudioPlayerErrorCode;
@class STKDataSource;
@class STKAudioPlayer;
@protocol STKAudioPlayerDelegate <NSObject>
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(AudioPlayerState)state;
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didEncounterError:(AudioPlayerErrorCode)errorCode;
/// Raised when an item has started playing
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didStartPlayingQueueItemId:(NSObject*)queueItemId;
/// Raised when an item has finished buffering (may or may not be the currently playing item)
/// This event may be raised multiple times for the same item if seek is invoked on the player
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject*)queueItemId;
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(AudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration;
/// Raised when the state of the player has changed
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(STKAudioPlayerState)state previousState:(STKAudioPlayerState)previousState;
/// Raised when an item has finished playing
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(STKAudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration;
/// Raised when an unexpected and possibly unrecoverable error has occured (usually best to recreate the STKAudioPlauyer)
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer unexpectedError:(STKAudioPlayerErrorCode)errorCode;
@optional
/// Optionally implemented to get logging information from the STKAudioPlayer (used internally for debugging)
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer logInfo:(NSString*)line;
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer internalStateChanged:(AudioPlayerInternalState)state;
-(void) audioPlayer: (STKAudioPlayer*)audioPlayer didCancelQueuedItems:(NSArray*)queuedItems;
/// Raised when items queued items are cleared (usually because of a call to play, setDataSource or stop)
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didCancelQueuedItems:(NSArray*)queuedItems;
@end
@class STKQueueEntry;
typedef struct
{
AudioQueueBufferRef ref;
int bufferIndex;
}
AudioQueueBufferRefLookupEntry;
typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames);
@interface STKAudioPlayer : NSObject<STKDataSourceDelegate>
/// Gets or sets the player muted state
@property (readwrite) BOOL muted;
/// Gets the current item duration in seconds
@property (readonly) double duration;
/// Gets the current item progress in seconds
@property (readonly) double progress;
@property (readwrite) AudioPlayerState state;
@property (readonly) AudioPlayerStopReason stopReason;
@property (readwrite, unsafe_unretained) id<STKAudioPlayerDelegate> delegate;
/// Enables or disables peak and average decibel meteting
@property (readwrite) BOOL meteringEnabled;
/// Returns an array of STKFrameFilterEntry objects representing the filters currently in use
@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) NSObject* mostRecentlyQueuedStillPendingItem;
/// Gets the current state of the player
@property (readwrite) STKAudioPlayerState state;
/// Gets the options provided to the player on startup
@property (readonly) STKAudioPlayerOptions options;
/// 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, unsafe_unretained) id<STKAudioPlayerDelegate> delegate;
/// Creates a datasource from a given URL.
/// URLs with FILE schemes will return an STKLocalFileDataSource.
/// URLs with HTTP schemes will return an STKHTTPDataSource wrapped within an STKAutoRecoveringHTTPDataSource.
/// URLs with unrecognised schemes will return nil.
+(STKDataSource*) dataSourceFromURL:(NSURL*)url;
/// Initializes a new STKAudioPlayer with the default options
-(id) init;
-(id) initWithNumberOfAudioQueueBuffers:(int)numberOfAudioQueueBuffers andReadBufferSize:(int)readBufferSizeIn;
-(STKDataSource*) dataSourceFromURL:(NSURL*)url;
/// Initializes a new STKAudioPlayer with the given options
-(id) initWithOptions:(STKAudioPlayerOptions)optionsIn;
/// Plays an item from the given URL (all pending queued items are removed)
-(void) play:(NSString*)urlString;
/// Plays an item from the given URL (all pending queued items are removed)
-(void) playWithURL:(NSURL*)url;
/// Plays the given item (all pending queued items are removed)
-(void) playWithDataSource:(STKDataSource*)dataSource;
/// Queues a DataSource with te given Item ID for playback
-(void) queueDataSource:(STKDataSource*)dataSource withQueueItemId:(NSObject*)queueItemId;
/// Plays the given item (all pending queued items are removed)
-(void) setDataSource:(STKDataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId;
/// Seeks to a specific time (in seconds)
-(void) seekToTime:(double)value;
/// Clears any upcoming items already queued for playback (does not stop the current item).
/// The didCancelItems event will be raised for the items removed from the queue.
-(void) clearQueue;
/// Pauses playback
-(void) pause;
/// Resumes playback from pause
-(void) resume;
/// Stops playback of the current file, flushes all the buffers and removes any pending queued items
-(void) stop;
-(void) flushStop;
/// Mutes playback
-(void) mute;
/// Unmutes playback
-(void) unmute;
/// Disposes the STKAudioPlayer and frees up all resources before returning
-(void) dispose;
/// The QueueItemId of the currently playing item
-(NSObject*) currentlyPlayingQueueItemId;
-(void) updateMeters;
/// Removes a frame filter with the given name
-(void) removeFrameFilterWithName:(NSString*)name;
/// Appends a frame filter with the given name and filter block to the end of the filter chain
-(void) appendFrameFilterWithName:(NSString*)name block:(STKFrameFilter)block;
/// Appends a frame filter with the given name and filter block just after the filter with the given name.
/// If the given name is nil, the filter will be inserted at the beginning of the filter change
-(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(NSString*)afterFilterWithName block:(STKFrameFilter)block;
/// Reads the peak power in decibals for the given channel (0 or 1).
/// Return values are between -60 (low) and 0 (high).
-(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber;
/// Reads the average power in decibals for the given channel (0 or 1)
/// Return values are between -60 (low) and 0 (high).
-(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber;
@end
File diff suppressed because it is too large Load Diff
@@ -4,7 +4,7 @@
Created by Thong Nguyen on 16/10/2012.
https://github.com/tumtumtum/audjustable
Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -33,13 +33,13 @@
**********************************************************************************/
#import "STKDataSource.h"
#import "STKHttpDataSource.h"
#import "STKHTTPDataSource.h"
#import "STKDataSourceWrapper.h"
@interface STKAutoRecoveringHttpDataSource : STKDataSourceWrapper
@interface STKAutoRecoveringHTTPDataSource : STKDataSourceWrapper
-(id) initWithHttpDataSource:(STKHttpDataSource*)innerDataSource;
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource;
@property (readonly) STKHttpDataSource* innerDataSource;
@property (readonly) STKHTTPDataSource* innerDataSource;
@end
@@ -4,7 +4,7 @@
Created by Thong Nguyen on 16/10/2012.
https://github.com/tumtumtum/audjustable
Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -40,14 +40,14 @@
#import <netdb.h>
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import "STKAutoRecoveringHttpDataSource.h"
#import "STKAutoRecoveringHTTPDataSource.h"
#define MAX_IMMEDIATE_RECONNECT_ATTEMPTS (8)
#define MAX_ATTEMPTS_WITH_SERVER_ERROR (MAX_IMMEDIATE_RECONNECT_ATTEMPTS + 2)
#define MAX_IMMEDIATE_RECONNECT_ATTEMPTS (2)
@interface STKAutoRecoveringHttpDataSource()
@interface STKAutoRecoveringHTTPDataSource()
{
int reconnectAttempts;
int serial;
int waitSeconds;
BOOL waitingForNetwork;
SCNetworkReachabilityRef reachabilityRef;
}
@@ -60,25 +60,25 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
{
@autoreleasepool
{
STKAutoRecoveringHttpDataSource* dataSource = (__bridge STKAutoRecoveringHttpDataSource*)info;
STKAutoRecoveringHTTPDataSource* dataSource = (__bridge STKAutoRecoveringHTTPDataSource*)info;
[dataSource reachabilityChanged];
}
}
@implementation STKAutoRecoveringHttpDataSource
@implementation STKAutoRecoveringHTTPDataSource
-(STKHttpDataSource*) innerHttpDataSource
-(STKHTTPDataSource*) innerHTTPDataSource
{
return (STKHttpDataSource*)self.innerDataSource;
return (STKHTTPDataSource*)self.innerDataSource;
}
-(id) initWithDataSource:(STKDataSource *)innerDataSource
{
return [self initWithHttpDataSource:(STKHttpDataSource*)innerDataSource];
return [self initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource];
}
-(id) initWithHttpDataSource:(STKHttpDataSource*)innerDataSourceIn
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn
{
if (self = [super initWithDataSource:innerDataSourceIn])
{
@@ -122,6 +122,8 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
-(void) unregisterForEvents
{
[super unregisterForEvents];
[self stopNotifier];
}
@@ -130,7 +132,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
if (reachabilityRef != NULL)
{
SCNetworkReachabilitySetCallback(reachabilityRef, NULL, NULL);
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, [self.innerDataSource.eventsRunLoop getCFRunLoop], kCFRunLoopDefaultMode);
}
}
@@ -148,7 +150,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
-(void) dealloc
{
NSLog(@"STKAutoRecoveringHttpDataSource dealloc");
NSLog(@"STKAutoRecoveringHTTPDataSource dealloc");
self.innerDataSource.delegate = nil;
@@ -168,24 +170,35 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
{
waitingForNetwork = NO;
[self attemptReconnect];
[self attemptReconnectWithSerial:@(serial)];
}
}
-(void) dataSourceDataAvailable:(STKDataSource*)dataSource
{
reconnectAttempts = 0;
serial++;
waitSeconds = 1;
[super dataSourceDataAvailable:dataSource];
}
-(void) attemptReconnect
-(void) attemptReconnectWithSerial:(NSNumber*)serialIn
{
reconnectAttempts++;
if (serialIn.intValue != self->serial)
{
return;
}
NSLog(@"attemptReconnect %lld/%lld", self.position, self.length);
[self seekToOffset:self.position];
}
-(void) attemptReconnectWithTimer:(NSTimer*)timer
{
[self attemptReconnectWithSerial:(NSNumber*)timer.userInfo];
}
-(void) processRetryOnError
{
if (![self hasGotNetworkConnection])
@@ -195,23 +208,29 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
return;
}
if (!(self.innerDataSource.httpStatusCode >= 200 && self.innerDataSource.httpStatusCode <= 299) && reconnectAttempts >= MAX_ATTEMPTS_WITH_SERVER_ERROR)
waitingForNetwork = NO;
NSRunLoop* runLoop = self.innerDataSource.eventsRunLoop;
if (runLoop == nil)
{
[super dataSourceErrorOccured:self];
}
else if (reconnectAttempts > MAX_IMMEDIATE_RECONNECT_ATTEMPTS)
{
[self performSelector:@selector(attemptReconnect) withObject:nil afterDelay:5];
[self performSelector:@selector(attemptReconnectWithSerial:) withObject:@(serial) afterDelay:waitSeconds];
}
else
{
[self attemptReconnect];
NSTimer* timer = [NSTimer timerWithTimeInterval:waitSeconds target:self selector:@selector(attemptReconnectWithTimer:) userInfo:@(serial) repeats:NO];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
}
waitSeconds = MIN(waitSeconds + 1, 5);
}
-(void) dataSourceEof:(STKDataSource*)dataSource
{
if ([self position] != [self length])
NSLog(@"dataSourceEof");
if ([self position] < [self length])
{
[self processRetryOnError];
@@ -223,6 +242,8 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
-(void) dataSourceErrorOccured:(STKDataSource*)dataSource
{
NSLog(@"dataSourceErrorOccured");
if (self.innerDataSource.httpStatusCode == 416 /* Range out of bounds */)
{
[super dataSourceEof:dataSource];
@@ -231,13 +252,11 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
{
[self processRetryOnError];
}
}
-(NSString*) description
{
return [NSString stringWithFormat:@"Auto-recovering HTTP data source with file length: %lld and position: %lld", self.length, self.position];
return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position];
}
@end
@@ -44,14 +44,19 @@
@interface STKCoreFoundationDataSource : STKDataSource
{
@protected
BOOL isInErrorState;
CFReadStreamRef stream;
NSRunLoop* eventsRunLoop;
}
@property (readonly) BOOL isInErrorState;
-(BOOL) reregisterForEvents;
-(void) open;
-(void) dataAvailable;
-(void) eof;
-(void) errorOccured;
-(CFStreamStatus) status;
@end
@@ -60,6 +60,11 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
@implementation STKCoreFoundationDataSource
-(BOOL) isInErrorState
{
return self->isInErrorState;
}
-(void) dataAvailable
{
[self.delegate dataSourceDataAvailable:self];
@@ -72,6 +77,8 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
-(void) errorOccured
{
self->isInErrorState = YES;
[self.delegate dataSourceErrorOccured:self];
}
@@ -79,7 +86,10 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
{
if (stream)
{
[self unregisterForEvents];
if (eventsRunLoop)
{
[self unregisterForEvents];
}
[self close];
@@ -98,6 +108,10 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
}
}
-(void) open
{
}
-(void) seekToOffset:(long long)offset
{
}
@@ -133,19 +147,21 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
-(BOOL) registerForEvents:(NSRunLoop*)runLoop
{
eventsRunLoop = runLoop;
if (stream)
{
CFStreamClientContext context = {0, (__bridge void*)self, NULL, NULL, NULL};
CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, ReadStreamCallbackProc, &context);
CFReadStreamScheduleWithRunLoop(stream, [eventsRunLoop getCFRunLoop], kCFRunLoopCommonModes);
if (!stream)
{
[self open];
return YES;
}
CFStreamClientContext context = {0, (__bridge void*)self, NULL, NULL, NULL};
return NO;
CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, ReadStreamCallbackProc, &context);
CFReadStreamScheduleWithRunLoop(stream, [eventsRunLoop getCFRunLoop], kCFRunLoopCommonModes);
return YES;
}
-(BOOL) hasBytesAvailable
@@ -158,4 +174,14 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve
return CFReadStreamHasBytesAvailable(stream);
}
-(CFStreamStatus) status
{
if (stream)
{
return CFReadStreamGetStatus(stream);
}
return 0;
}
@end
@@ -34,15 +34,21 @@
#import "STKCoreFoundationDataSource.h"
typedef NSURL*(^URLProvider)();
@class STKHTTPDataSource;
@interface STKHttpDataSource : STKCoreFoundationDataSource
typedef void(^STKURLBlock)(NSURL* url);
typedef NSURL*(^STKURLProvider)();
typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock callback);
@interface STKHTTPDataSource : STKCoreFoundationDataSource
@property (readonly, retain) NSURL* url;
@property (readwrite) UInt32 httpStatusCode;
+(AudioFileTypeID) audioFileTypeHintFromMimeType:(NSString*)fileExtension;
-(id) initWithURL:(NSURL*)url;
-(id) initWithURLProvider:(URLProvider)urlProvider;
-(id) initWithURLProvider:(STKURLProvider)urlProvider;
-(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider;
-(NSRunLoop*) eventsRunLoop;
@end
@@ -32,18 +32,18 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**********************************************************************************/
#import "STKHttpDataSource.h"
#import "STKHTTPDataSource.h"
#import "STKLocalFileDataSource.h"
@interface STKHttpDataSource()
@interface STKHTTPDataSource()
{
@private
int seekStart;
int relativePosition;
long long seekStart;
long long relativePosition;
long long fileLength;
int discontinuous;
NSURL* currentUrl;
URLProvider urlProvider;
STKAsyncURLProvider asyncUrlProvider;
NSDictionary* httpHeaders;
AudioFileTypeID audioFileTypeHint;
}
@@ -51,14 +51,24 @@
@end
@implementation STKHttpDataSource
@implementation STKHTTPDataSource
-(id) initWithURL:(NSURL*)urlIn
{
return [self initWithURLProvider:^NSURL* { return urlIn; }];
}
-(id) initWithURLProvider:(URLProvider)urlProviderIn
-(id) initWithURLProvider:(STKURLProvider)urlProviderIn
{
urlProviderIn = [urlProviderIn copy];
return [self initWithAsyncURLProvider:^(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock block)
{
block(urlProviderIn());
}];
}
-(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn
{
if (self = [super init])
{
@@ -66,9 +76,7 @@
relativePosition = 0;
fileLength = -1;
self->urlProvider = urlProviderIn;
[self open];
self->asyncUrlProvider = [asyncUrlProviderIn copy];
audioFileTypeHint = [STKLocalFileDataSource audioFileTypeHintFromFileExtension:self->currentUrl.pathExtension];
}
@@ -78,7 +86,7 @@
-(void) dealloc
{
NSLog(@"STKHttpDataSource dealloc");
NSLog(@"STKHTTPDataSource dealloc");
}
-(NSURL*) url
@@ -130,40 +138,61 @@
-(void) dataAvailable
{
if (fileLength < 0)
{
CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
if (self.httpStatusCode == 0)
{
CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
httpHeaders = (__bridge_transfer NSDictionary*)CFHTTPMessageCopyAllHeaderFields((CFHTTPMessageRef)response);
self.httpStatusCode = CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response);
CFRelease(response);
if (self.httpStatusCode == 200)
{
if (seekStart == 0)
{
fileLength = (long long)[[httpHeaders objectForKey:@"Content-Length"] integerValue];
}
NSString* contentType = [httpHeaders objectForKey:@"Content-Type"];
AudioFileTypeID typeIdFromMimeType = [STKHttpDataSource audioFileTypeHintFromMimeType:contentType];
if (typeIdFromMimeType != 0)
{
audioFileTypeHint = typeIdFromMimeType;
}
}
else
{
[self errorOccured];
return;
}
}
[super dataAvailable];
if (self.httpStatusCode == 200)
{
if (seekStart == 0)
{
fileLength = (long long)[[httpHeaders objectForKey:@"Content-Length"] integerValue];
}
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;
}
}
[super dataAvailable];
}
-(long long) position
@@ -188,13 +217,16 @@
CFReadStreamClose(stream);
CFRelease(stream);
}
NSAssert([NSRunLoop currentRunLoop] == eventsRunLoop, @"Seek called on wrong thread");
stream = 0;
relativePosition = 0;
seekStart = (int)offset;
seekStart = offset;
[self open];
[self reregisterForEvents];
self->isInErrorState = NO;
[self openForSeek:YES];
}
-(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size
@@ -218,75 +250,99 @@
-(void) open
{
self->currentUrl = urlProvider();
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (__bridge CFURLRef)self->currentUrl, kCFHTTPVersion1_1);
if (seekStart > 0)
{
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Range"), (__bridge CFStringRef)[NSString stringWithFormat:@"bytes=%d-", seekStart]);
discontinuous = YES;
}
stream = CFReadStreamCreateForHTTPRequest(NULL, message);
if (stream == nil)
{
CFRelease(message);
[self errorOccured];
return;
}
if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue))
{
CFRelease(message);
[self errorOccured];
return;
}
// Proxy support
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFRelease(proxySettings);
// SSL support
if ([self->currentUrl.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)
{
NSDictionary* sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
(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);
}
// Open
if (!CFReadStreamOpen(stream))
{
CFRelease(stream);
CFRelease(message);
[self errorOccured];
return;
}
CFRelease(message);
return [self openForSeek:NO];
}
- (NSString *)description
-(void) openForSeek:(BOOL)forSeek
{
asyncUrlProvider(self, forSeek, ^(NSURL* url)
{
self->currentUrl = url;
if (url == nil)
{
return;
}
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (__bridge CFURLRef)self->currentUrl, kCFHTTPVersion1_1);
if (seekStart > 0)
{
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Range"), (__bridge CFStringRef)[NSString stringWithFormat:@"bytes=%lld-", seekStart]);
discontinuous = YES;
}
stream = CFReadStreamCreateForHTTPRequest(NULL, message);
if (stream == nil)
{
CFRelease(message);
[self errorOccured];
return;
}
if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue))
{
CFRelease(message);
[self errorOccured];
return;
}
// Proxy support
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFRelease(proxySettings);
// SSL support
if ([self->currentUrl.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)
{
NSDictionary* sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
(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];
self.httpStatusCode = 0;
// Open
if (!CFReadStreamOpen(stream))
{
CFRelease(stream);
CFRelease(message);
[self errorOccured];
return;
}
self->isInErrorState = NO;
CFRelease(message);
});
}
-(NSRunLoop*) eventsRunLoop
{
return self->eventsRunLoop;
}
-(NSString*) description
{
return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position];
}
@@ -53,8 +53,6 @@
{
self.filePath = filePathIn;
[self open];
audioFileTypeHint = [STKLocalFileDataSource audioFileTypeHintFromFileExtension:filePathIn.pathExtension];
}
@@ -107,6 +105,8 @@
{
if (stream)
{
[self unregisterForEvents];
CFReadStreamClose(stream);
stream = 0;
@@ -115,26 +115,23 @@
-(void) open
{
NSURL* url = [[NSURL alloc] initFileURLWithPath:self.filePath];
if (stream)
{
[self unregisterForEvents];
CFReadStreamClose(stream);
CFRelease(stream);
stream = 0;
}
NSURL* url = [[NSURL alloc] initFileURLWithPath:self.filePath];
stream = CFReadStreamCreateWithFile(NULL, (__bridge CFURLRef)url);
NSError *fileError;
NSFileManager *manager = [[NSFileManager alloc] init];
NSString *path = [NSString stringWithUTF8String:[url fileSystemRepresentation]];
NSDictionary *attributes = [manager attributesOfItemAtPath:path
error:&fileError];
NSError* fileError;
NSFileManager* manager = [[NSFileManager alloc] init];
NSDictionary* attributes = [manager attributesOfItemAtPath:filePath error:&fileError];
if (fileError)
{
@@ -145,13 +142,14 @@
}
NSNumber* number = [attributes objectForKey:@"NSFileSize"];
if (number)
{
length = number.longLongValue;
}
[self reregisterForEvents];
CFReadStreamOpen(stream);
}
@@ -200,7 +198,6 @@
[self close];
[self open];
[self reregisterForEvents];
}
if (CFReadStreamSetProperty(stream, kCFStreamPropertyFileCurrentOffset, (__bridge CFTypeRef)[NSNumber numberWithLongLong:offset]) != TRUE)
+46
View File
@@ -0,0 +1,46 @@
//
// STKQueueEntry.h
// StreamingKit
//
// Created by Thong Nguyen on 30/01/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "STKDataSource.h"
#import "libkern/OSAtomic.h"
#import "AudioToolbox/AudioToolbox.h"
@interface STKQueueEntry : NSObject
{
@public
OSSpinLock spinLock;
BOOL parsedHeader;
Float64 sampleRate;
double packetDuration;
UInt64 audioDataOffset;
UInt64 audioDataByteCount;
UInt32 packetBufferSize;
volatile Float64 seekTime;
volatile int64_t framesQueued;
volatile int64_t framesPlayed;
volatile int64_t lastFrameQueued;
volatile int processedPacketsCount;
volatile int processedPacketsSizeTotal;
AudioStreamBasicDescription audioStreamBasicDescription;
}
@property (readonly) UInt64 audioDataLengthInBytes;
@property (readwrite, retain) NSObject* queueItemId;
@property (readwrite, retain) STKDataSource* dataSource;
-(id) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId;
-(void) reset;
-(double) duration;
-(Float64) progressInFrames;
-(double) calculatedBitRate;
-(void) updateAudioDataSource;
-(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription;
@end
+128
View File
@@ -0,0 +1,128 @@
//
// STKQueueEntry.m
// StreamingKit
//
// Created by Thong Nguyen on 30/01/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "STKQueueEntry.h"
#import "STKDataSource.h"
#define STK_BIT_RATE_ESTIMATION_MIN_PACKETS (64)
@implementation STKQueueEntry
-(id) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn
{
if (self = [super init])
{
self.dataSource = dataSourceIn;
self.queueItemId = queueItemIdIn;
self->lastFrameQueued = -1;
}
return self;
}
-(void) reset
{
OSSpinLockLock(&self->spinLock);
self->framesQueued = 0;
self->framesPlayed = 0;
self->lastFrameQueued = -1;
OSSpinLockUnlock(&self->spinLock);
}
-(double) calculatedBitRate
{
double retval;
if (packetDuration && processedPacketsCount > STK_BIT_RATE_ESTIMATION_MIN_PACKETS)
{
double averagePacketByteSize = processedPacketsSizeTotal / processedPacketsCount;
retval = averagePacketByteSize / packetDuration * 8;
return retval;
}
retval = (audioStreamBasicDescription.mBytesPerFrame * audioStreamBasicDescription.mSampleRate) * 8;
return retval;
}
-(void) updateAudioDataSource
{
if ([self.dataSource conformsToProtocol:@protocol(AudioDataSource)])
{
double calculatedBitrate = [self calculatedBitRate];
id<AudioDataSource> audioDataSource = (id<AudioDataSource>)self.dataSource;
audioDataSource.averageBitRate = calculatedBitrate;
audioDataSource.audioDataOffset = audioDataOffset;
}
}
-(double) duration
{
if (self->sampleRate <= 0)
{
return 0;
}
UInt64 audioDataLengthInBytes = [self audioDataLengthInBytes];
double calculatedBitRate = [self calculatedBitRate];
if (calculatedBitRate < 1.0 || self.dataSource.length == 0)
{
return 0;
}
return audioDataLengthInBytes / (calculatedBitRate / 8);
}
-(UInt64) audioDataLengthInBytes
{
if (audioDataByteCount)
{
return audioDataByteCount;
}
else
{
if (!self.dataSource.length)
{
return 0;
}
return self.dataSource.length - audioDataOffset;
}
}
-(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription
{
if (self->audioStreamBasicDescription.mSampleRate == 0)
{
return NO;
}
return (memcmp(&(self->audioStreamBasicDescription), basicDescription, sizeof(*basicDescription)) == 0);
}
-(Float64) progressInFrames
{
OSSpinLockLock(&self->spinLock);
Float64 retval = self->seekTime + self->framesPlayed;
OSSpinLockUnlock(&self->spinLock);
return retval;
}
-(NSString*) description
{
return [[self queueItemId] description];
}
@end
@@ -0,0 +1,9 @@
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif
@@ -0,0 +1,13 @@
//
// StreamingKitMac.h
// StreamingKitMac
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface StreamingKitMac : NSObject
@end
@@ -0,0 +1,13 @@
//
// StreamingKitMac.m
// StreamingKitMac
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "StreamingKitMac.h"
@implementation StreamingKitMac
@end
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
@@ -0,0 +1,34 @@
//
// StreamingKitMacTests.m
// StreamingKitMacTests
//
// Created by Thong Nguyen on 02/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface StreamingKitMacTests : XCTestCase
@end
@implementation StreamingKitMacTests
- (void)setUp
{
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample
{
XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
}
@end
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */