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
This commit is contained in:
parent
257532c6c9
commit
48ce1f9e67
|
|
@ -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>
|
||||
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
{
|
||||
NSURL* url = [NSURL URLWithString:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
|
||||
|
||||
STKAutoRecoveringHttpDataSource* dataSource = [[STKAutoRecoveringHttpDataSource alloc] initWithHttpDataSource:(STKHttpDataSource*)[audioPlayer dataSourceFromURL:url]];
|
||||
STKAutoRecoveringHTTPDataSource* dataSource = [[STKAutoRecoveringHTTPDataSource alloc] initWithHTTPDataSource:(STKHTTPDataSource*)[audioPlayer dataSourceFromURL:url]];
|
||||
|
||||
[audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@
|
|||
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 */
|
||||
|
|
@ -56,16 +56,16 @@
|
|||
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; };
|
||||
|
|
@ -128,16 +128,16 @@
|
|||
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 */,
|
||||
A1E7C4CE188D57F50010896F /* Supporting Files */,
|
||||
|
|
@ -256,10 +256,10 @@
|
|||
A1E7C501188D5E550010896F /* STKCoreFoundationDataSource.m in Sources */,
|
||||
A1E7C4FF188D5E550010896F /* STKAudioPlayer.m in Sources */,
|
||||
A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */,
|
||||
A1E7C504188D5E550010896F /* STKHttpDataSource.m in Sources */,
|
||||
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */,
|
||||
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */,
|
||||
A1E7C502188D5E550010896F /* STKDataSource.m in Sources */,
|
||||
A1E7C500188D5E550010896F /* STKAutoRecoveringHttpDataSource.m in Sources */,
|
||||
A1E7C500188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ AudioPlayerErrorCode;
|
|||
-(void) queueDataSource:(STKDataSource*)dataSource withQueueItemId:(NSObject*)queueItemId;
|
||||
-(void) setDataSource:(STKDataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId;
|
||||
-(void) seekToTime:(double)value;
|
||||
-(void) clearQueue;
|
||||
-(void) pause;
|
||||
-(void) resume;
|
||||
-(void) stop;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#import "STKAudioPlayer.h"
|
||||
#import "AudioToolbox/AudioToolbox.h"
|
||||
#import "STKHttpDataSource.h"
|
||||
#import "STKHTTPDataSource.h"
|
||||
#import "STKLocalFileDataSource.h"
|
||||
#import "libkern/OSAtomic.h"
|
||||
|
||||
|
|
@ -445,9 +445,9 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
self.state = newState;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
[self.delegate audioPlayer:self stateChanged:self.state];
|
||||
});
|
||||
{
|
||||
[self.delegate audioPlayer:self stateChanged:self.state];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -599,7 +599,7 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
}
|
||||
else
|
||||
{
|
||||
retval = [[STKHttpDataSource alloc] initWithURL:url];
|
||||
retval = [[STKHTTPDataSource alloc] initWithURL:url];
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
|
@ -635,13 +635,16 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
|
||||
[upcomingQueue removeAllObjects];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
if (array.count > 0)
|
||||
{
|
||||
if ([self.delegate respondsToSelector:@selector(audioPlayer:didCancelQueuedItems:)])
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
[self.delegate audioPlayer:self didCancelQueuedItems:array];
|
||||
}
|
||||
});
|
||||
if ([self.delegate respondsToSelector:@selector(audioPlayer:didCancelQueuedItems:)])
|
||||
{
|
||||
[self.delegate audioPlayer:self didCancelQueuedItems:array];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
}
|
||||
|
|
@ -1209,24 +1212,24 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
if (runLoop)
|
||||
{
|
||||
CFRunLoopPerformBlock([runLoop getCFRunLoop], NSDefaultRunLoopMode, ^
|
||||
{
|
||||
pthread_mutex_lock(&playerMutex);
|
||||
|
||||
if (audioQueue)
|
||||
{
|
||||
[self stopAudioQueueWithReason:@"handlePropertyChangeForQueue`2"];
|
||||
}
|
||||
|
||||
if (currentlyPlayingEntry)
|
||||
{
|
||||
self->stopReason = AudioPlayerStopReasonEof;
|
||||
self.internalState = AudioPlayerInternalStateStopped;
|
||||
|
||||
[self processFinishedPlaying:currentlyPlayingEntry];
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
});
|
||||
{
|
||||
pthread_mutex_lock(&playerMutex);
|
||||
|
||||
if (audioQueue)
|
||||
{
|
||||
[self stopAudioQueueWithReason:@"handlePropertyChangeForQueue`2"];
|
||||
}
|
||||
|
||||
if (currentlyPlayingEntry)
|
||||
{
|
||||
self->stopReason = AudioPlayerStopReasonEof;
|
||||
self.internalState = AudioPlayerInternalStateStopped;
|
||||
|
||||
[self processFinishedPlaying:currentlyPlayingEntry];
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
});
|
||||
|
||||
CFRunLoopWakeUp([runLoop getCFRunLoop]);
|
||||
}
|
||||
|
|
@ -1371,6 +1374,13 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
audioQueue = nil;
|
||||
}
|
||||
|
||||
if (currentlyPlayingEntry == nil)
|
||||
{
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
currentAudioStreamBasicDescription = currentlyPlayingEntry->audioStreamBasicDescription;
|
||||
|
||||
error = AudioQueueNewOutput(¤tAudioStreamBasicDescription, AudioQueueOutputCallbackProc, (__bridge void*)self, NULL, NULL, 0, &audioQueue);
|
||||
|
|
@ -1381,9 +1391,9 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
{
|
||||
[self.delegate audioPlayer:self didEncounterError:AudioPlayerErrorQueueCreationFailed];
|
||||
});
|
||||
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1397,7 +1407,7 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
});
|
||||
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1497,7 +1507,7 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
{
|
||||
[self.delegate audioPlayer:self didEncounterError:AudioPlayerErrorQueueCreationFailed];
|
||||
});
|
||||
|
||||
|
||||
pthread_mutex_unlock(&playerMutex);
|
||||
|
||||
return;
|
||||
|
|
@ -1755,7 +1765,7 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
[self.delegate audioPlayer:self didStartPlayingQueueItemId:playingQueueItemId];
|
||||
[self.delegate audioPlayer:self didStartPlayingQueueItemId:playingQueueItemId];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -2082,6 +2092,8 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
|
||||
currentEntry.bytesBuffered = 0;
|
||||
currentEntry.firstFrameIndex = [self currentTimeInFrames];
|
||||
|
||||
[self clearQueue];
|
||||
}
|
||||
|
||||
-(BOOL) startAudioQueue
|
||||
|
|
@ -2337,15 +2349,37 @@ static void AudioQueueIsRunningCallbackProc(void* userData, AudioQueueRef audioQ
|
|||
|
||||
[self logInfo:[NSString stringWithFormat:@"dataSourceEofLastByteIndex: %lld, %lld", audioPacketsReadCount, audioPacketsPlayedCount]];
|
||||
|
||||
if (audioPacketsReadCount == 0 && audioPacketsPlayedCount == audioPacketsReadCount)
|
||||
if (audioPacketsReadCount == 0 && audioPacketsPlayedCount == audioPacketsReadCount && currentlyReadingEntry == currentlyPlayingEntry)
|
||||
{
|
||||
[self logInfo:@"dataSourceEof shutting down audio queue"];
|
||||
[self logInfo:@"dataSourceEof seeked to end"];
|
||||
|
||||
if (audioQueue)
|
||||
{
|
||||
self.internalState = AudioPlayerInternalStateFlushingAndStoppingButStillPlaying;
|
||||
|
||||
AudioQueueStop(audioQueue, NO);
|
||||
if ([self audioQueueIsRunning])
|
||||
{
|
||||
[self logInfo:@"dataSourceEof stopping audio queue asynchronously"];
|
||||
|
||||
AudioQueueStop(audioQueue, NO);
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logInfo:@"dataSourceEof finished playing"];
|
||||
|
||||
if (audioQueue)
|
||||
{
|
||||
[self stopAudioQueueWithReason:@"dataSourceEof finished playing"];
|
||||
}
|
||||
|
||||
if (currentlyPlayingEntry)
|
||||
{
|
||||
self->stopReason = AudioPlayerStopReasonEof;
|
||||
self.internalState = AudioPlayerInternalStateStopped;
|
||||
|
||||
[self processFinishedPlaying:currentlyPlayingEntry];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -40,12 +40,12 @@
|
|||
#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)
|
||||
|
||||
@interface STKAutoRecoveringHttpDataSource()
|
||||
@interface STKAutoRecoveringHTTPDataSource()
|
||||
{
|
||||
int reconnectAttempts;
|
||||
BOOL waitingForNetwork;
|
||||
|
|
@ -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])
|
||||
{
|
||||
|
|
@ -148,7 +148,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
|
||||
-(void) dealloc
|
||||
{
|
||||
NSLog(@"STKAutoRecoveringHttpDataSource dealloc");
|
||||
NSLog(@"STKAutoRecoveringHTTPDataSource dealloc");
|
||||
|
||||
self.innerDataSource.delegate = nil;
|
||||
|
||||
|
|
@ -44,10 +44,13 @@
|
|||
@interface STKCoreFoundationDataSource : STKDataSource
|
||||
{
|
||||
@protected
|
||||
BOOL isInErrorState;
|
||||
CFReadStreamRef stream;
|
||||
NSRunLoop* eventsRunLoop;
|
||||
}
|
||||
|
||||
@property (readonly) BOOL isInErrorState;
|
||||
|
||||
-(BOOL) reregisterForEvents;
|
||||
|
||||
-(void) dataAvailable;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,15 +34,20 @@
|
|||
|
||||
#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;
|
||||
|
||||
@end
|
||||
|
|
@ -32,10 +32,10 @@
|
|||
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;
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
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,7 +76,7 @@
|
|||
relativePosition = 0;
|
||||
fileLength = -1;
|
||||
|
||||
self->urlProvider = [urlProviderIn copy];
|
||||
self->asyncUrlProvider = [asyncUrlProviderIn copy];
|
||||
|
||||
[self open];
|
||||
|
||||
|
|
@ -78,7 +88,7 @@
|
|||
|
||||
-(void) dealloc
|
||||
{
|
||||
NSLog(@"STKHttpDataSource dealloc");
|
||||
NSLog(@"STKHTTPDataSource dealloc");
|
||||
}
|
||||
|
||||
-(NSURL*) url
|
||||
|
|
@ -148,7 +158,7 @@
|
|||
}
|
||||
|
||||
NSString* contentType = [httpHeaders objectForKey:@"Content-Type"];
|
||||
AudioFileTypeID typeIdFromMimeType = [STKHttpDataSource audioFileTypeHintFromMimeType:contentType];
|
||||
AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType];
|
||||
|
||||
if (typeIdFromMimeType != 0)
|
||||
{
|
||||
|
|
@ -193,8 +203,9 @@
|
|||
relativePosition = 0;
|
||||
seekStart = (int)offset;
|
||||
|
||||
[self open];
|
||||
[self reregisterForEvents];
|
||||
self->isInErrorState = NO;
|
||||
|
||||
[self openForSeek:YES];
|
||||
}
|
||||
|
||||
-(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size
|
||||
|
|
@ -218,75 +229,95 @@
|
|||
|
||||
-(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=%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;
|
||||
}
|
||||
|
||||
self->isInErrorState = NO;
|
||||
|
||||
if (self->eventsRunLoop)
|
||||
{
|
||||
[self reregisterForEvents];
|
||||
}
|
||||
|
||||
CFRelease(message);
|
||||
});
|
||||
}
|
||||
|
||||
-(NSString*) description
|
||||
{
|
||||
return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position];
|
||||
}
|
||||
Loading…
Reference in New Issue