MP3 streaming!
parent
1e5c5f54e3
commit
7d6c8fc6f5
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
- (BOOL)seekable
|
- (BOOL)seekable
|
||||||
{
|
{
|
||||||
return YES;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)seek:(long)position whence:(int)whence
|
- (BOOL)seek:(long)position whence:(int)whence
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
{
|
{
|
||||||
Socket *_socket;
|
Socket *_socket;
|
||||||
|
|
||||||
|
BOOL pastHeader;
|
||||||
|
|
||||||
long byteCount;
|
long byteCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
if (_socket) {
|
if (_socket) {
|
||||||
NSData *request = [[NSString stringWithFormat:@"GET %@ HTTP/1.0\nHOST: %@\n\n",[url path],[url host]] dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *request = [[NSString stringWithFormat:@"GET %@ HTTP/1.0\nHOST: %@\n\n",[url path],[url host]] dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
[_socket send:(void *)[request bytes] amount:[request length]];
|
[_socket send:(void *)[request bytes] amount:[request length]];
|
||||||
|
pastHeader = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (_socket != nil);
|
return (_socket != nil);
|
||||||
|
@ -56,6 +57,44 @@
|
||||||
- (int)read:(void *)buffer amount:(int)amount
|
- (int)read:(void *)buffer amount:(int)amount
|
||||||
{
|
{
|
||||||
int l = [_socket receive:buffer amount:amount];
|
int l = [_socket receive:buffer amount:amount];
|
||||||
|
|
||||||
|
if (!pastHeader) {
|
||||||
|
uint8_t *f = (uint8_t *)strnstr((const char *)buffer, "\r\n\r\n", l);
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
pastHeader = YES;
|
||||||
|
|
||||||
|
uint8_t *bufferOffset = f + 4; //\r\n\r\n
|
||||||
|
uint8_t *bufferEnd = (uint8_t *)buffer + l;
|
||||||
|
int amountRemaining = bufferEnd - bufferOffset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
//For testing only
|
||||||
|
FILE *testFout = fopen("header.raw", "w");
|
||||||
|
fwrite(buffer, 1, bufferOffset - (uint8_t *)buffer, testFout);
|
||||||
|
fclose(testFout);
|
||||||
|
|
||||||
|
testFout = fopen("test.raw", "w");
|
||||||
|
fwrite(bufferOffset, 1, amountRemaining, testFout);
|
||||||
|
fclose(testFout);
|
||||||
|
*/
|
||||||
|
|
||||||
|
memmove(buffer,bufferOffset, amountRemaining);
|
||||||
|
|
||||||
|
return amountRemaining + [self read:((uint8_t *)buffer + amountRemaining) amount:(amount - amountRemaining)];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Keep searching for header. Note: NEED TO WATCH BOUNDARY CASES
|
||||||
|
return [self read:buffer amount:amount];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//FOR TESTING ONLY
|
||||||
|
FILE *testFout = fopen("test.raw", "a");
|
||||||
|
fwrite(buffer, 1, l, testFout);
|
||||||
|
fclose(testFout);
|
||||||
|
*/
|
||||||
if (l > 0)
|
if (l > 0)
|
||||||
byteCount += l;
|
byteCount += l;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
BOOL _seekSkip;
|
BOOL _seekSkip;
|
||||||
|
|
||||||
|
BOOL _firstFrame;
|
||||||
|
|
||||||
//For gapless playback of mp3s
|
//For gapless playback of mp3s
|
||||||
BOOL _gapless;
|
BOOL _gapless;
|
||||||
long _currentFrame;
|
long _currentFrame;
|
||||||
|
|
|
@ -270,6 +270,8 @@ int parse_headers(struct xing *xing, struct lame *lame, struct mad_bitptr ptr, u
|
||||||
length = mad_timer_count(_duration, MAD_UNITS_MILLISECONDS);
|
length = mad_timer_count(_duration, MAD_UNITS_MILLISECONDS);
|
||||||
|
|
||||||
bitrate /= 1000;
|
bitrate /= 1000;
|
||||||
|
|
||||||
|
bitsPerSample = 16;
|
||||||
|
|
||||||
[_source seek:0 whence:SEEK_SET];
|
[_source seek:0 whence:SEEK_SET];
|
||||||
|
|
||||||
|
@ -291,10 +293,14 @@ int parse_headers(struct xing *xing, struct lame *lame, struct mad_bitptr ptr, u
|
||||||
mad_frame_init(&_frame);
|
mad_frame_init(&_frame);
|
||||||
mad_synth_init(&_synth);
|
mad_synth_init(&_synth);
|
||||||
mad_timer_reset(&_timer);
|
mad_timer_reset(&_timer);
|
||||||
|
|
||||||
bitsPerSample = 16;
|
|
||||||
|
|
||||||
return [self scanFileFast:YES useXing:YES];
|
_firstFrame = YES;
|
||||||
|
|
||||||
|
if ([_source seekable]) {
|
||||||
|
return [self scanFileFast:YES useXing:YES];
|
||||||
|
}
|
||||||
|
NSLog(@"NOT SCANNING FILE!!!");
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -506,6 +512,18 @@ static inline signed int scale (mad_fixed_t sample)
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (_firstFrame && ![_source seekable]) {
|
||||||
|
frequency = _frame.header.samplerate;
|
||||||
|
channels = MAD_NCHANNELS(&_frame.header);
|
||||||
|
bitsPerSample = 16;
|
||||||
|
|
||||||
|
NSLog(@"FORMAT CHANGED: %f", frequency);
|
||||||
|
[self willChangeValueForKey:@"properties"];
|
||||||
|
[self didChangeValueForKey:@"properties"];
|
||||||
|
|
||||||
|
_firstFrame = NO;
|
||||||
|
}
|
||||||
|
|
||||||
mad_timer_add (&_timer, _frame.header.duration);
|
mad_timer_add (&_timer, _frame.header.duration);
|
||||||
|
|
||||||
mad_synth_frame (&_synth, &_frame);
|
mad_synth_frame (&_synth, &_frame);
|
||||||
|
|
Loading…
Reference in New Issue