Compare commits

..

6 Commits

Author SHA1 Message Date
Thong Nguyen 000930a295 Fixed seek not working with HTTP 2014-11-10 17:25:02 +00:00
Thong Nguyen 269f335ee4 Smallf ix to ExampleAppMac app 2014-11-08 20:56:55 +00:00
Thong Nguyen 162d964372 STKHTTPDataSource tidyup 2014-11-08 20:04:29 +00:00
Thong Nguyen ef7f42c97e AudioPlayerView layout jig 2014-11-08 19:52:54 +00:00
Thong Nguyen ea9e40b17a Added progress for live streams in AudioPlayerView 2014-11-08 19:45:26 +00:00
Thong Nguyen 9510d74e58 Added progress for live streams in AudioPlayerView 2014-11-08 19:43:51 +00:00
4 changed files with 79 additions and 65 deletions
+17 -6
View File
@@ -63,22 +63,22 @@
[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.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 35, size.width, size.height);
[playFromIcecastButton addTarget:self action:@selector(playFromIcecasButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[playFromIcecastButton setTitle:@"Play from Icecast" forState:UIControlStateNormal];
playFromLocalFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 100, size.width, size.height);
playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height);
[playFromLocalFileButton addTarget:self action:@selector(playFromLocalFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[playFromLocalFileButton setTitle:@"Play from Local File" forState:UIControlStateNormal];
queueShortFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 150, size.width, size.height);
queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height);
[queueShortFileButton addTarget:self action:@selector(queueShortFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[queueShortFileButton setTitle:@"Queue short file" forState:UIControlStateNormal];
queuePcmWaveFileFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 280, size.width, size.height);
queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height);
[queuePcmWaveFileFromHTTPButton addTarget:self action:@selector(queuePcmWaveFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[queuePcmWaveFileFromHTTPButton setTitle:@"Queue PCM/WAVE from HTTP" forState:UIControlStateNormal];
@@ -94,7 +94,7 @@
[stopButton setTitle:@"Stop" forState:UIControlStateNormal];
muteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
muteButton.frame = CGRectMake((320 - size.width) - 30, 420, size.width, size.height);
muteButton.frame = CGRectMake((320 - size.width) - 30, 430, size.width, size.height);
[muteButton addTarget:self action:@selector(muteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[muteButton setTitle:@"Mute" forState:UIControlStateNormal];
@@ -180,6 +180,17 @@
return;
}
if (audioPlayer.currentlyPlayingQueueItemId == nil)
{
slider.value = 0;
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = @"";
return;
}
if (audioPlayer.duration != 0)
{
slider.minimumValue = 0;
@@ -194,7 +205,7 @@
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = @"";
label.text = [NSString stringWithFormat:@"Live stream %@", [self formatTimeFromSeconds:audioPlayer.progress]];
}
statusLabel.text = audioPlayer.state == STKAudioPlayerStateBuffering ? @"buffering" : @"";
+1 -1
View File
@@ -72,7 +72,7 @@
CGFloat meterWidth = 0;
if (audioPlayer.duration != 0)
if (audioPlayer.currentlyPlayingQueueItemId != nil)
{
slider.minValue = 0;
slider.maxValue = audioPlayer.duration;
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "StreamingKit"
s.version = "0.1.23"
s.version = "0.1.25"
s.summary = "A fast and extensible audio streamer for iOS and OSX with support for gapless playback and custom (non-HTTP) sources."
s.homepage = "https://github.com/tumtumtum/StreamingKit/"
s.license = 'MIT'
+60 -57
View File
@@ -164,6 +164,50 @@
return audioFileTypeHint;
}
-(NSDictionary*) parseIceHeader:(NSData*)headerData
{
NSMutableDictionary* retval = [[NSMutableDictionary alloc] init];
NSCharacterSet* characterSet = [NSCharacterSet characterSetWithCharactersInString:@"\r\n"];
NSString* fullString = [[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding];
NSArray* strings = [fullString componentsSeparatedByCharactersInSet:characterSet];
httpHeaders = [NSMutableDictionary dictionary];
for (NSString* s in strings)
{
if (s.length == 0)
{
continue;
}
if ([s hasPrefix:@"ICY "])
{
NSArray* parts = [s componentsSeparatedByString:@" "];
if (parts.count >= 2)
{
self->httpStatusCode = [parts[1] intValue];
}
continue;
}
NSRange range = [s rangeOfString:@":"];
if (range.location == NSNotFound)
{
continue;
}
NSString* key = [s substringWithRange: (NSRange){.location = 0, .length = range.location}];
NSString* value = [s substringFromIndex:range.location + 1];
[retval setValue:value forKey:key];
}
return retval;
}
-(BOOL) parseHttpHeader
{
if (!httpHeaderNotAvailable)
@@ -197,7 +241,6 @@
if (!self->iceHeaderSearchComplete)
{
UInt8 byte;
UInt8 bytes[4];
UInt8 terminal1[] = { '\n', '\n' };
UInt8 terminal2[] = { '\r', '\n', '\r', '\n' };
@@ -224,9 +267,7 @@
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)
if (memcmp(&terminal1[0], [self->iceHeaderData bytes] + iceHeaderData.length - sizeof(terminal1), sizeof(terminal1)) == 0)
{
self->iceHeaderAvailable = YES;
self->iceHeaderSearchComplete = YES;
@@ -237,9 +278,7 @@
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)
if (memcmp(&terminal2[0], [self->iceHeaderData bytes] + iceHeaderData.length - sizeof(terminal2), sizeof(terminal2)) == 0)
{
self->iceHeaderAvailable = YES;
self->iceHeaderSearchComplete = YES;
@@ -248,11 +287,9 @@
}
}
if (iceHeaderData.length >=4)
if (iceHeaderData.length >= 4)
{
[iceHeaderData getBytes:&bytes[0] length:4];
if (memcmp(bytes, "ICY", 3) != 0 && memcmp(bytes, "HTTP", 4) != 0)
if (memcmp([self->iceHeaderData bytes], "ICY ", 4) != 0 && memcmp([self->iceHeaderData bytes], "HTTP", 4) != 0)
{
self->iceHeaderAvailable = NO;
self->iceHeaderSearchComplete = YES;
@@ -269,45 +306,12 @@
}
}
NSCharacterSet* characterSet = [NSCharacterSet characterSetWithCharactersInString:@"\r\n"];
NSString* fullString = [[NSString alloc] initWithData:self->iceHeaderData encoding:NSUTF8StringEncoding];
httpHeaders = [self parseIceHeader:self->iceHeaderData];
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];
}
self->iceHeaderData = nil;
}
if (([httpHeaders objectForKey:@"Accepts-Ranges"] ?: [httpHeaders objectForKey:@"accepts-ranges"]) != nil)
if (([httpHeaders objectForKey:@"Accept-Ranges"] ?: [httpHeaders objectForKey:@"accept-ranges"]) != nil)
{
self->supportsSeek = YES;
}
@@ -322,7 +326,6 @@
}
NSString* contentType = [httpHeaders objectForKey:@"Content-Type"] ?: [httpHeaders objectForKey:@"content-type"] ;
AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType];
if (typeIdFromMimeType != 0)
@@ -436,6 +439,11 @@
}
-(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size
{
return [self privateReadIntoBuffer:buffer withSize:size];
}
-(int) privateReadIntoBuffer:(UInt8*)buffer withSize:(int)size
{
if (size == 0)
{
@@ -458,8 +466,7 @@
return count;
}
int read = (int)CFReadStreamRead(stream, buffer, size);
int read = [super readIntoBuffer:buffer withSize:size];
if (read < 0)
{
@@ -490,8 +497,6 @@
return;
}
self->supportsSeek = NO;
self->currentUrl = url;
if (url == nil)
@@ -511,11 +516,12 @@
for (NSString* key in self->requestHeaders)
{
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");
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Accept"), CFSTR("*/*"));
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Ice-MetaData"), CFSTR("0"));
stream = CFReadStreamCreateForHTTPRequest(NULL, message);
@@ -540,13 +546,11 @@
}
// Proxy support
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFRelease(proxySettings);
// SSL support
if ([self->currentUrl.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)
{
NSDictionary* sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
@@ -563,7 +567,6 @@
self->httpStatusCode = 0;
// Open
if (!CFReadStreamOpen(stream))
{
CFRelease(stream);