Modified CoreAudioDecoder to use new source based system. It just ignores the source and uses its own, since the ExtAudioFile API is absolutely hopeless when it comes to streaming.
parent
e452cbe3db
commit
eb96a75a1f
|
@ -17,7 +17,7 @@
|
|||
@protocol CogSource <NSObject>
|
||||
+ (NSArray *)schemes; //http, file, etc
|
||||
|
||||
- (BOOL)buffered; //Return YES if the input should be buffered, NO if it shouldn't. Used for remote connections (HTTP), not local stuff (file).
|
||||
- (NSURL *)url;
|
||||
|
||||
- (BOOL)open:(NSURL *)url;
|
||||
- (NSDictionary *)properties; //Perhaps contains header info for HTTP stream, or path for a regular file.
|
||||
|
|
|
@ -24,20 +24,11 @@
|
|||
|
||||
#import "Plugin.h"
|
||||
|
||||
#undef _USE_WRAPPER_
|
||||
|
||||
@interface CoreAudioDecoder : NSObject <CogDecoder>
|
||||
{
|
||||
ExtAudioFileRef _in;
|
||||
|
||||
#ifdef _USE_WRAPPER_
|
||||
int _inFd;
|
||||
AudioFileID _audioID;
|
||||
|
||||
SInt64 _fileSize;
|
||||
SInt64 _startOffset;
|
||||
#endif
|
||||
|
||||
int bitrate;
|
||||
int bitsPerSample;
|
||||
int channels;
|
||||
|
|
|
@ -28,167 +28,25 @@
|
|||
|
||||
@implementation CoreAudioDecoder
|
||||
|
||||
#ifdef _USE_WRAPPER_
|
||||
OSStatus readFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, void *buffer, ByteCount* actualCount)
|
||||
{
|
||||
CoreAudioFile *caf = (CoreAudioFile *)inRefCon;
|
||||
int fd = caf->_inFd;
|
||||
|
||||
// fseek(fd, inPosition, SEEK_SET);
|
||||
// NSLog(@"Requesting %u", requestCount);
|
||||
// NSLog(@"Currently at %lli", inPosition);
|
||||
|
||||
*actualCount = pread(fd, buffer, requestCount, inPosition+caf->_startOffset);
|
||||
|
||||
if (*actualCount <= 0)
|
||||
{
|
||||
return -1000; //Error?
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
SInt64 getSizeFunc(void *inRefCon)
|
||||
{
|
||||
CoreAudioFile *caf = (CoreAudioFile *)inRefCon;
|
||||
int fd = caf->_inFd;
|
||||
|
||||
if (caf->_fileSize != 0)
|
||||
{
|
||||
return caf->_fileSize;
|
||||
}
|
||||
|
||||
/* long curPos;
|
||||
|
||||
curPos = ftell(fd);
|
||||
|
||||
fseek(fd, 0, SEEK_END);
|
||||
|
||||
caf->_fileSize = ftell(fd);
|
||||
|
||||
fseek(fd, curPos, SEEK_SET);
|
||||
*/
|
||||
|
||||
caf->_fileSize = lseek(fd, 0, SEEK_END) - caf->_startOffset;
|
||||
NSLog(@"SIZE at %lli", caf->_fileSize);
|
||||
|
||||
NSLog(@"ERROR: %i = %i %i %i", errno, EBADF, ESPIPE, EINVAL);
|
||||
return caf->_fileSize;
|
||||
}
|
||||
|
||||
OSStatus setSizeFunc(void * inRefCon, SInt64 inSize)
|
||||
{
|
||||
NSLog(@"setsize FUNC");
|
||||
|
||||
return -1000; //Not supported at the moment
|
||||
}
|
||||
|
||||
OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, const void *buffer, ByteCount* actualCount)
|
||||
{
|
||||
NSLog(@"WRITE FUNC");
|
||||
return -1000; //Not supported at the moment
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void) close
|
||||
{
|
||||
OSStatus err;
|
||||
|
||||
#ifdef _USE_WRAPPER_
|
||||
if (_inFd)
|
||||
close(_inFd);
|
||||
AudioFileClose(_audioID);
|
||||
#endif
|
||||
|
||||
err = ExtAudioFileDispose(_in);
|
||||
if(noErr != err) {
|
||||
NSLog(@"Error closing ExtAudioFile");
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) open:(NSURL *)url
|
||||
- (BOOL)open:(id<CogSource>)source;
|
||||
{
|
||||
OSStatus err;
|
||||
|
||||
#ifdef _USE_WRAPPER_
|
||||
AudioFileTypeID type = 0;
|
||||
NSString *ext;
|
||||
|
||||
// Open the input file
|
||||
_inFd = open([[url path] UTF8String], O_RDONLY, 0777);
|
||||
if (_inFd < 0)
|
||||
{
|
||||
NSLog(@"Error operning file: %s", url);
|
||||
return NO;
|
||||
}
|
||||
_startOffset = 0;
|
||||
|
||||
ext = [[url path] pathExtension];
|
||||
//Find first sync frame for MP3
|
||||
if([ext caseInsensitiveCompare:@"mp3"] == NSOrderedSame) {
|
||||
size_t bytesRead;
|
||||
uint8_t buf[2];
|
||||
|
||||
type = kAudioFileMP3Type;
|
||||
|
||||
for(;;) {
|
||||
bytesRead = read(_inFd, buf, 2);
|
||||
|
||||
|
||||
if(2 != bytesRead) {
|
||||
NSLog(@"Error finding mp3 sync frame");
|
||||
close(_inFd);
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
// found some kind of data
|
||||
if(0x00 != buf[0] || 0x00 != buf[1]) {
|
||||
_startOffset = lseek(_inFd, 0, SEEK_CUR) - 2;
|
||||
NSLog(@"Found sync frame at: %llx", _startOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if([ext caseInsensitiveCompare:@"aac"] == NSOrderedSame) {
|
||||
type = kAudioFileAAC_ADTSType;
|
||||
}
|
||||
else if([ext caseInsensitiveCompare:@"m4a"] == NSOrderedSame) {
|
||||
type = kAudioFileM4AType;
|
||||
}
|
||||
else if([ext caseInsensitiveCompare:@"mp4"] == NSOrderedSame) {
|
||||
type = kAudioFileMPEG4Type;
|
||||
}
|
||||
|
||||
//Using callbacks with fopen, ftell, fseek, fclose, because the default pread hangs when accessing the same file from multiple threads.
|
||||
err = AudioFileOpenWithCallbacks(self, readFunc, writeFunc, getSizeFunc, setSizeFunc, type, &_audioID);
|
||||
if(noErr != err)
|
||||
{
|
||||
NSLog(@"Error opening with callbacks, falling back: %s", (char *)&err);
|
||||
FSRef ref;
|
||||
close(_inFd);
|
||||
_inFd = 0;
|
||||
|
||||
err = FSPathMakeRef((const UInt8 *)[[url path] UTF8String], &ref, NULL);
|
||||
if(noErr != err) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
err = AudioFileOpen(&ref, fsRdPerm, type, &_audioID);
|
||||
if(noErr != err) {
|
||||
NSLog(@"Error opening AudioFile: %s", (char *)&err);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
err = ExtAudioFileWrapAudioFileID(_audioID, NO, &_in);
|
||||
if(noErr != err) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
#else
|
||||
FSRef ref;
|
||||
|
||||
NSURL *url = [source url];
|
||||
if (![[url scheme] isEqualToString:@"file"])
|
||||
return NO;
|
||||
|
||||
// Open the input file
|
||||
err = FSPathMakeRef((const UInt8 *)[[url path] UTF8String], &ref, NULL);
|
||||
if(noErr != err) {
|
||||
|
@ -200,7 +58,7 @@ OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, c
|
|||
NSLog(@"Error opening file: %s", &err);
|
||||
return NO;
|
||||
}
|
||||
#endif
|
||||
|
||||
return [self readInfoFromExtAudioFileRef];
|
||||
}
|
||||
|
||||
|
@ -226,21 +84,8 @@ OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, c
|
|||
return NO;
|
||||
}
|
||||
|
||||
#ifdef _USE_WRAPPER_
|
||||
SInt64 totalBytes;
|
||||
|
||||
size = sizeof(totalBytes);
|
||||
err = AudioFileGetProperty(_audioID, kAudioFilePropertyAudioDataByteCount, &size, &totalBytes);
|
||||
if(err != noErr) {
|
||||
[self close];
|
||||
return NO;
|
||||
}
|
||||
|
||||
bitrate = round(((totalBytes*8.0)/((double)(totalFrames)/asbd.mSampleRate))/1000.0);
|
||||
#else
|
||||
//Is there a way to get bitrate with extAudioFile?
|
||||
bitrate = 0;
|
||||
#endif
|
||||
|
||||
// Set our properties
|
||||
bitsPerSample = asbd.mBitsPerChannel;
|
||||
|
@ -276,6 +121,9 @@ OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, c
|
|||
return NO;
|
||||
}
|
||||
|
||||
[self willChangeValueForKey:@"properties"];
|
||||
[self didChangeValueForKey:@"properties"];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -340,5 +188,10 @@ OSStatus writeFunc(void * inRefCon, SInt64 inPosition, ByteCount requestCount, c
|
|||
nil];
|
||||
}
|
||||
|
||||
- (BOOL)seekable
|
||||
{
|
||||
return YES; //Are you kidding me? it HAS to be seekable. The AudioFile API is 100% impossible to stream in any way. Even using callbacks gives problems. Sigh.
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
|
||||
@implementation CoreAudioPropertiesReader
|
||||
|
||||
- (NSDictionary *)propertiesForURL:(NSURL *)url
|
||||
+ (NSDictionary *)propertiesForSource:(id<CogSource>)source
|
||||
{
|
||||
NSDictionary *properties;
|
||||
CoreAudioDecoder *decoder;
|
||||
|
||||
decoder = [[CoreAudioDecoder alloc] init];
|
||||
if (![decoder open:url])
|
||||
if (![decoder open:source])
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
@interface FileSource : NSObject <CogSource>
|
||||
{
|
||||
FILE *_fd;
|
||||
|
||||
NSURL *_url;
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)url;
|
||||
|
||||
@end
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
- (BOOL)open:(NSURL *)url
|
||||
{
|
||||
[self setURL:url];
|
||||
|
||||
_fd = fopen([[url path] UTF8String], "r");
|
||||
|
||||
return (_fd != NULL);
|
||||
|
@ -53,6 +55,19 @@
|
|||
fclose(_fd);
|
||||
}
|
||||
|
||||
- (NSURL *)url
|
||||
{
|
||||
return _url;
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)url
|
||||
{
|
||||
[url retain];
|
||||
[_url release];
|
||||
_url = url;
|
||||
}
|
||||
|
||||
|
||||
+ (NSArray *)schemes
|
||||
{
|
||||
return [NSArray arrayWithObject:@"file"];
|
||||
|
|
|
@ -15,9 +15,13 @@
|
|||
{
|
||||
Socket *_socket;
|
||||
|
||||
NSURL *_url;
|
||||
|
||||
BOOL pastHeader;
|
||||
|
||||
long byteCount;
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)url;
|
||||
|
||||
@end
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
- (BOOL)open:(NSURL *)url
|
||||
{
|
||||
[self setURL:url];
|
||||
|
||||
unsigned int port = [[url port] unsignedIntValue];
|
||||
if (!port)
|
||||
|
@ -112,6 +113,26 @@
|
|||
[_socket close];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_socket release];
|
||||
[_url release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSURL *)url
|
||||
{
|
||||
return _url;
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)url
|
||||
{
|
||||
[url retain];
|
||||
[_url release];
|
||||
_url = url;
|
||||
}
|
||||
|
||||
+ (NSArray *)schemes
|
||||
{
|
||||
return [NSArray arrayWithObject:@"http"];
|
||||
|
|
Loading…
Reference in New Issue