diff --git a/ExampleApp/ExampleApp/AppDelegate.m b/ExampleApp/ExampleApp/AppDelegate.m index 058d86c..d0680af 100644 --- a/ExampleApp/ExampleApp/AppDelegate.m +++ b/ExampleApp/ExampleApp/AppDelegate.m @@ -68,6 +68,15 @@ [audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]]; } +-(void) audioPlayerViewPlayFromIcecastSelected:(AudioPlayerView *)audioPlayerView +{ + NSURL* url = [NSURL URLWithString:@"http://shoutmedia.abc.net.au:10326"]; + + STKDataSource* dataSource = [STKAudioPlayer dataSourceFromURL:url]; + + [audioPlayer setDataSource:dataSource withQueueItemId:[[SampleQueueId alloc] initWithUrl:url andCount:0]]; +} + -(void) audioPlayerViewQueueShortFileSelected:(AudioPlayerView*)audioPlayerView { NSString* path = [[NSBundle mainBundle] pathForResource:@"airplane" ofType:@"aac"]; diff --git a/ExampleApp/ExampleApp/AudioPlayerView.h b/ExampleApp/ExampleApp/AudioPlayerView.h index b91952e..6b92125 100644 --- a/ExampleApp/ExampleApp/AudioPlayerView.h +++ b/ExampleApp/ExampleApp/AudioPlayerView.h @@ -39,6 +39,7 @@ @protocol AudioPlayerViewDelegate -(void) audioPlayerViewPlayFromHTTPSelected:(AudioPlayerView*)audioPlayerView; +-(void) audioPlayerViewPlayFromIcecastSelected:(AudioPlayerView*)audioPlayerView; -(void) audioPlayerViewQueueShortFileSelected:(AudioPlayerView*)audioPlayerView; -(void) audioPlayerViewPlayFromLocalFileSelected:(AudioPlayerView*)audioPlayerView; -(void) audioPlayerViewQueuePcmWaveFileSelected:(AudioPlayerView*)audioPlayerView; @@ -57,6 +58,7 @@ UIButton* playButton; UIButton* stopButton; UIButton* playFromHTTPButton; + UIButton* playFromIcecastButton; UIButton* queueShortFileButton; UIButton* queuePcmWaveFileFromHTTPButton; UIButton* playFromLocalFileButton; diff --git a/ExampleApp/ExampleApp/AudioPlayerView.m b/ExampleApp/ExampleApp/AudioPlayerView.m index 3e65b6c..20019a5 100644 --- a/ExampleApp/ExampleApp/AudioPlayerView.m +++ b/ExampleApp/ExampleApp/AudioPlayerView.m @@ -61,39 +61,44 @@ playFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10, size.width, size.height); [playFromHTTPButton addTarget:self action:@selector(playFromHTTPButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [playFromHTTPButton setTitle:@"Play from HTTP" forState:UIControlStateNormal]; + + playFromIcecastButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + playFromIcecastButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 50, size.width, size.height); + [playFromIcecastButton addTarget:self action:@selector(playFromIcecasButtonTouched) forControlEvents:UIControlEventTouchUpInside]; + [playFromIcecastButton setTitle:@"Play from Icecast" forState:UIControlStateNormal]; playFromLocalFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 50, size.width, size.height); + playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 100, size.width, size.height); [playFromLocalFileButton addTarget:self action:@selector(playFromLocalFileButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [playFromLocalFileButton setTitle:@"Play from Local File" forState:UIControlStateNormal]; queueShortFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 100, size.width, size.height); + queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 150, size.width, size.height); [queueShortFileButton addTarget:self action:@selector(queueShortFileButtonTouched) forControlEvents:UIControlEventTouchUpInside]; [queueShortFileButton setTitle:@"Queue short file" forState:UIControlStateNormal]; queuePcmWaveFileFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 150, size.width, size.height); + queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 280, 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.frame = CGRectMake(30, 400, 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.frame = CGRectMake((320 - size.width) - 30, 400, size.width, size.height); [stopButton addTarget:self action:@selector(stopButtonPressed) forControlEvents:UIControlEventTouchUpInside]; [stopButton setTitle:@"Stop" forState:UIControlStateNormal]; muteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - muteButton.frame = CGRectMake((320 - size.width) - 30, 410, size.width, size.height); + muteButton.frame = CGRectMake((320 - size.width) - 30, 420, 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 = [[UISlider alloc] initWithFrame:CGRectMake(20, 320, queuePcmWaveFileFromHTTPButton.frame.origin.y + queuePcmWaveFileFromHTTPButton.frame.size.height + 20, 20)]; slider.continuous = YES; [slider addTarget:self action:@selector(sliderChanged) forControlEvents:UIControlEventValueChanged]; @@ -106,11 +111,11 @@ [enableEqSwitch addTarget:self action:@selector(onEnableEqSwitch) forControlEvents:UIControlEventAllTouchEvents]; - label = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 10, frame.size.width, 25)]; + label = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 40, 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 = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + label.frame.size.height + 50, frame.size.width, 50)]; statusLabel.textAlignment = NSTextAlignmentCenter; @@ -121,6 +126,7 @@ [self addSubview:slider]; [self addSubview:playButton]; [self addSubview:playFromHTTPButton]; + [self addSubview:playFromIcecastButton]; [self addSubview:playFromLocalFileButton]; [self addSubview:queueShortFileButton]; [self addSubview:queuePcmWaveFileFromHTTPButton]; @@ -203,6 +209,11 @@ [self.delegate audioPlayerViewPlayFromHTTPSelected:self]; } +-(void) playFromIcecasButtonTouched +{ + [self.delegate audioPlayerViewPlayFromIcecastSelected:self]; +} + -(void) playFromLocalFileButtonTouched { [self.delegate audioPlayerViewPlayFromLocalFileSelected:self]; diff --git a/StreamingKit.xcworkspace/xcshareddata/StreamingKit.xccheckout b/StreamingKit.xcworkspace/xcshareddata/StreamingKit.xccheckout index 85a8c6f..deb405b 100644 --- a/StreamingKit.xcworkspace/xcshareddata/StreamingKit.xccheckout +++ b/StreamingKit.xcworkspace/xcshareddata/StreamingKit.xccheckout @@ -10,29 +10,29 @@ StreamingKit IDESourceControlProjectOriginsDictionary - DD310C30-B3D0-4BD7-9565-9F29F09CC4F8 + 3E9414865BAE5433092B9D136FFC1F054EA505C2 https://github.com/tumtumtum/StreamingKit.git IDESourceControlProjectPath StreamingKit.xcworkspace IDESourceControlProjectRelativeInstallPathDictionary - DD310C30-B3D0-4BD7-9565-9F29F09CC4F8 + 3E9414865BAE5433092B9D136FFC1F054EA505C2 .. IDESourceControlProjectURL https://github.com/tumtumtum/StreamingKit.git IDESourceControlProjectVersion - 110 + 111 IDESourceControlProjectWCCIdentifier - DD310C30-B3D0-4BD7-9565-9F29F09CC4F8 + 3E9414865BAE5433092B9D136FFC1F054EA505C2 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey - DD310C30-B3D0-4BD7-9565-9F29F09CC4F8 + 3E9414865BAE5433092B9D136FFC1F054EA505C2 IDESourceControlWCCName StreamingKit diff --git a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj index bc96c98..4555410 100644 --- a/StreamingKit/StreamingKit.xcodeproj/project.pbxproj +++ b/StreamingKit/StreamingKit.xcodeproj/project.pbxproj @@ -401,7 +401,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = STK; - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0610; ORGANIZATIONNAME = "Thong Nguyen"; }; buildConfigurationList = A1E7C4C3188D57F50010896F /* Build configuration list for PBXProject "StreamingKit" */; @@ -554,6 +554,7 @@ A1A49988189E744500E2A2E2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", @@ -574,6 +575,7 @@ A1A49989189E744500E2A2E2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/StreamingKit/StreamingKit/STKAudioPlayer.m b/StreamingKit/StreamingKit/STKAudioPlayer.m index 6c39dc5..a3a8b27 100644 --- a/StreamingKit/StreamingKit/STKAudioPlayer.m +++ b/StreamingKit/StreamingKit/STKAudioPlayer.m @@ -294,7 +294,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn .componentFlagsMask = 0 }; - const int bytesPerSample = sizeof(AudioSampleType); + const int bytesPerSample = 2; canonicalAudioStreamBasicDescription = (AudioStreamBasicDescription) { @@ -1868,7 +1868,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl { OSStatus status; Boolean writable; - UInt32 cookieSize; + UInt32 cookieSize = 0; if (memcmp(asbd, &audioConverterAudioStreamBasicDescription, sizeof(AudioStreamBasicDescription)) == 0) { @@ -1900,11 +1900,16 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl audioConverterAudioStreamBasicDescription = *asbd; - status = AudioFileStreamGetPropertyInfo(audioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable); + if (self->currentlyReadingEntry.dataSource.audioFileTypeHint != kAudioFileAAC_ADTSType) + { + status = AudioFileStreamGetPropertyInfo(audioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable); - if (!status) - { - void* cookieData = alloca(cookieSize); + if (status) + { + return; + } + + void* cookieData = alloca(cookieSize); status = AudioFileStreamGetProperty(audioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData); @@ -1917,6 +1922,8 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl if (status) { + [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; + return; } } diff --git a/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h b/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h index 731de5d..b25a72e 100644 --- a/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h +++ b/StreamingKit/StreamingKit/STKCoreFoundationDataSource.h @@ -43,9 +43,10 @@ @interface STKCoreFoundationDataSource : STKDataSource { +@public + CFReadStreamRef stream; @protected BOOL isInErrorState; - CFReadStreamRef stream; NSRunLoop* eventsRunLoop; } diff --git a/StreamingKit/StreamingKit/STKCoreFoundationDataSource.m b/StreamingKit/StreamingKit/STKCoreFoundationDataSource.m index 1763acd..2cc6003 100644 --- a/StreamingKit/StreamingKit/STKCoreFoundationDataSource.m +++ b/StreamingKit/StreamingKit/STKCoreFoundationDataSource.m @@ -41,8 +41,10 @@ static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eve switch (eventType) { case kCFStreamEventErrorOccurred: + { [datasource errorOccured]; break; + } case kCFStreamEventEndEncountered: [datasource eof]; break; diff --git a/StreamingKit/StreamingKit/STKDataSource.h b/StreamingKit/StreamingKit/STKDataSource.h index 69c2961..d99da2b 100644 --- a/StreamingKit/StreamingKit/STKDataSource.h +++ b/StreamingKit/StreamingKit/STKDataSource.h @@ -45,6 +45,7 @@ @interface STKDataSource : NSObject +@property (readonly) BOOL supportsSeek; @property (readonly) SInt64 position; @property (readonly) SInt64 length; @property (readonly) BOOL hasBytesAvailable; diff --git a/StreamingKit/StreamingKit/STKDataSource.m b/StreamingKit/StreamingKit/STKDataSource.m index 9abd821..f9c57a2 100644 --- a/StreamingKit/StreamingKit/STKDataSource.m +++ b/StreamingKit/StreamingKit/STKDataSource.m @@ -79,4 +79,9 @@ return 0; } +-(BOOL) supportsSeek +{ + return YES; +} + @end diff --git a/StreamingKit/StreamingKit/STKHTTPDataSource.m b/StreamingKit/StreamingKit/STKHTTPDataSource.m index 196dd64..b4d5d08 100644 --- a/StreamingKit/StreamingKit/STKHTTPDataSource.m +++ b/StreamingKit/StreamingKit/STKHTTPDataSource.m @@ -38,12 +38,19 @@ @interface STKHTTPDataSource() { @private + BOOL supportsSeek; UInt32 httpStatusCode; SInt64 seekStart; SInt64 relativePosition; SInt64 fileLength; int discontinuous; int requestSerialNumber; + int prefixBytesRead; + NSData* prefixBytes; + NSMutableData* iceHeaderData; + BOOL iceHeaderSearchComplete; + BOOL iceHeaderAvailable; + BOOL httpHeaderNotAvailable; NSURL* currentUrl; STKAsyncURLProvider asyncUrlProvider; @@ -147,70 +154,230 @@ return audioFileTypeHint; } --(void) dataAvailable +-(BOOL) parseHttpHeader { - if (stream == NULL) { - return; - } - - if (self.httpStatusCode == 0) - { - CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader); + if (!httpHeaderNotAvailable) + { + CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader); if (response) { httpHeaders = (__bridge_transfer NSDictionary*)CFHTTPMessageCopyAllHeaderFields((CFHTTPMessageRef)response); - self->httpStatusCode = (UInt32)CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response); - + if (httpHeaders.count == 0) + { + httpHeaderNotAvailable = YES; + } + else + { + self->httpStatusCode = (UInt32)CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response); + } + CFRelease(response); } - - if (self.httpStatusCode == 200) - { - if (seekStart == 0) - { - fileLength = (SInt64)[[httpHeaders objectForKey:@"Content-Length"] longLongValue]; - } - - NSString* contentType = [httpHeaders objectForKey:@"Content-Type"]; - AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType]; - - if (typeIdFromMimeType != 0) - { - audioFileTypeHint = typeIdFromMimeType; - } - } - else if (self.httpStatusCode == 206) - { - NSString* contentRange = [httpHeaders objectForKey:@"Content-Range"]; - NSArray* components = [contentRange componentsSeparatedByString:@"/"]; - - if (components.count == 2) - { - fileLength = [[components objectAtIndex:1] integerValue]; - } - } - else if (self.httpStatusCode == 416) - { - if (self.length >= 0) - { - seekStart = self.length; - } - - [self eof]; - - return; - } - else if (self.httpStatusCode >= 300) - { - [self errorOccured]; - - return; - } + } + + if (httpHeaderNotAvailable) + { + if (self->iceHeaderSearchComplete && !self->iceHeaderAvailable) + { + return YES; + } + + if (!self->iceHeaderSearchComplete) + { + UInt8 byte; + UInt8 bytes[4]; + UInt8 terminal1[] = { '\n', '\n' }; + UInt8 terminal2[] = { '\r', '\n', '\r', '\n' }; + + if (iceHeaderData == nil) + { + iceHeaderData = [NSMutableData dataWithCapacity:1024]; + } + + while (true) + { + if (![self hasBytesAvailable]) + { + break; + } + + int read = [super readIntoBuffer:&byte withSize:1]; + + if (read <= 0) + { + break; + } + + [iceHeaderData appendBytes:&byte length:read]; + + if (iceHeaderData.length >= sizeof(terminal1)) + { + [iceHeaderData getBytes:&bytes[0] range:(NSRange){.location = iceHeaderData.length - sizeof(terminal1), .length = sizeof(terminal1)}]; + + if (memcmp(&terminal1[0], &bytes[0], sizeof(terminal1)) == 0) + { + self->iceHeaderAvailable = YES; + self->iceHeaderSearchComplete = YES; + + break; + } + } + + if (iceHeaderData.length >= sizeof(terminal2)) + { + [iceHeaderData getBytes:&bytes[0] range:(NSRange){.location = iceHeaderData.length - sizeof(terminal2), .length = sizeof(terminal2)}]; + + if (memcmp(&terminal2[0], &bytes[0], sizeof(terminal2)) == 0) + { + self->iceHeaderAvailable = YES; + self->iceHeaderSearchComplete = YES; + + break; + } + } + + if (iceHeaderData.length >=4) + { + [iceHeaderData getBytes:&bytes[0] length:4]; + + if (memcmp(bytes, "ICY", 3) != 0 && memcmp(bytes, "HTTP", 4) != 0) + { + self->iceHeaderAvailable = NO; + self->iceHeaderSearchComplete = YES; + prefixBytes = iceHeaderData; + + return YES; + } + } + } + + if (!self->iceHeaderSearchComplete) + { + return NO; + } + } + + NSCharacterSet* characterSet = [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; + NSString* fullString = [[NSString alloc] initWithData:self->iceHeaderData encoding:NSUTF8StringEncoding]; + + NSArray* strings = [fullString componentsSeparatedByCharactersInSet:characterSet]; + + httpHeaders = [NSMutableDictionary dictionary]; + + for (NSString* s in strings) + { + if (s.length == 0) + { + continue; + } + + if ([s hasPrefix:@"ICY"]) + { + NSArray* ss = [s componentsSeparatedByString:@" "]; + + if (ss.count >= 2) + { + self->httpStatusCode = [ss[1] intValue]; + } + } + + NSRange range = [s rangeOfString:@":"]; + + if (range.location == NSNotFound) + { + continue; + } + + NSString* key = [s substringWithRange: (NSRange){.location = 0, .length = range.location}]; + NSString* value = [s substringFromIndex:range.location + 1]; + + [httpHeaders setValue:value forKey:key]; + } + } + + if (([httpHeaders objectForKey:@"Accepts-Ranges"] ?: [httpHeaders objectForKey:@"accepts-ranges"]) != nil) + { + self->supportsSeek = YES; + } + + if (self.httpStatusCode == 200) + { + if (seekStart == 0) + { + id value = [httpHeaders objectForKey:@"Content-Length"] ?: [httpHeaders objectForKey:@"content-length"]; + + fileLength = (SInt64)[value longLongValue]; + } + + NSString* contentType = [httpHeaders objectForKey:@"Content-Type"] ?: [httpHeaders objectForKey:@"content-type"] ; + + AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType]; + + if (typeIdFromMimeType != 0) + { + audioFileTypeHint = typeIdFromMimeType; + } + } + else if (self.httpStatusCode == 206) + { + NSString* contentRange = [httpHeaders objectForKey:@"Content-Range"] ?: [httpHeaders objectForKey:@"content-range"]; + NSArray* components = [contentRange componentsSeparatedByString:@"/"]; + + if (components.count == 2) + { + fileLength = [[components objectAtIndex:1] integerValue]; + } + } + else if (self.httpStatusCode == 416) + { + if (self.length >= 0) + { + seekStart = self.length; + } + + [self eof]; + + return NO; + } + else if (self.httpStatusCode >= 300) + { + [self errorOccured]; + + return NO; + } + + return YES; +} + +-(void) dataAvailable +{ + if (stream == NULL) + { + return; + } + + if (self.httpStatusCode == 0) + { + if ([self parseHttpHeader]) + { + if ([self hasBytesAvailable]) + { + [super dataAvailable]; + } + + return; + } + else + { + return; + } } - - [super dataAvailable]; + else + { + [super dataAvailable]; + } } -(SInt64) position @@ -250,6 +417,11 @@ self->isInErrorState = NO; + if (!self->supportsSeek && offset != self->relativePosition) + { + return; + } + [self openForSeek:YES]; } @@ -260,6 +432,23 @@ return 0; } + if (prefixBytes != nil) + { + int count = MIN(size, (int)prefixBytes.length - prefixBytesRead); + + [prefixBytes getBytes:buffer length:count]; + + prefixBytesRead += count; + + if (prefixBytesRead >= prefixBytes.length) + { + prefixBytes = nil; + } + + return count; + } + + int read = (int)CFReadStreamRead(stream, buffer, size); if (read < 0) @@ -290,7 +479,9 @@ { return; } - + + self->supportsSeek = NO; + self->currentUrl = url; if (url == nil) @@ -300,7 +491,7 @@ CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (__bridge CFURLRef)self->currentUrl, kCFHTTPVersion1_1); - if (seekStart > 0) + if (seekStart > 0 && supportsSeek) { CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Range"), (__bridge CFStringRef)[NSString stringWithFormat:@"bytes=%lld-", seekStart]); @@ -312,6 +503,9 @@ NSString* value = [self->requestHeaders objectForKey:key]; CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)value); } + + CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)@"Accept", (__bridge CFStringRef)@"*/*"); + CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)@"Ice-MetaData", (__bridge CFStringRef)@"0"); stream = CFReadStreamCreateForHTTPRequest(NULL, message); @@ -323,6 +517,8 @@ return; } + + CFReadStreamSetProperty(stream, (__bridge CFStringRef)NSStreamNetworkServiceTypeBackground, (__bridge CFStringRef)NSStreamNetworkServiceTypeBackground); if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue)) { @@ -345,9 +541,6 @@ { 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]; @@ -394,4 +587,9 @@ return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position]; } +-(BOOL) supportsSeek +{ + return self->supportsSeek; +} + @end