audiostreamer初识(二)

来源:互联网 发布:龙腾世纪3优化差 编辑:程序博客网 时间:2024/06/05 04:43

让我们看一下audiostreamer.m的init:

- (id)initWithURL:(NSURL *)aURL

{

self = [super init];

if (self != nil)

{

if (url){

url = nil;

[url release];

}

url = [aURL copy];

#ifdef SHOUTCAST_METADATA

if (metaDataString){

metaDataString = nil;

[metaDataString release];

}

//NSLog(@"%d", [metaDataString retainCount]);

metaDataString = [[NSMutableString allocinitWithString:@""];

#endif

        seekTime = 0;

}

return self;

}

这里将url,metaDataString,seekTime初始化。

再看最重要的 start方法:

- (void)start

{

@synchronized (self)

{

if (state == AS_PAUSED)

{

[self pause];

}

else if (state == AS_INITIALIZED)

{

NSAssert([[NSThread currentThread] isEqual:[NSThread mainThread]],

@"Playback can only be started from the main thread.");

notificationCenter =

[[NSNotificationCenter defaultCenterretain];

self.state = AS_STARTING_FILE_THREAD;

internalThread =

[[NSThread alloc]

initWithTarget:self

selector:@selector(startInternal)

object:nil];

[internalThread setName:@"InternalThread"];

[internalThread start];

}

}

}

这里主要是重点注意

internalThread =[[NSThread alloc]initWithTarget:self selector:@selector(startInternal) object:nil];中的方法startInternal:


里面有几段代码特重要:

#if TARGET_OS_IPHONE

//

// Set the audio session category so that we continue to play if the

// iPhone/iPod auto-locks.

//

AudioSessionInitialize (

NULL,                          // 'NULL' to use the default (main) run loop

NULL,                          // 'NULL' to use the default run loop mode

MyAudioSessionInterruptionListener,  // a reference to your interruption callback

self                       // data to pass to your interruption listener callback

);

UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;

AudioSessionSetProperty (

kAudioSessionProperty_AudioCategory,

sizeof (sessionCategory),

&sessionCategory

);

AudioSessionSetActive(true);

__streamer = self;

#endif

相信大家都看懂,这是让播放器后台运行的代码。

接下来我们要看一句代码,让我们的思绪继续走下去:

if (![self openReadStream])

{

goto cleanup;

}

//

// Process the run loop until playback is finished or failed.

//

BOOL isRunning = YES;

do

{

isRunning = [[NSRunLoop currentRunLoop]

runMode:NSDefaultRunLoopMode

beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];

@synchronized(self) {

if (seekWasRequested) {

[self internalSeekToTime:requestedSeekTime];

seekWasRequested = NO;

}

}

//

// If there are no queued buffers, we need to check here since the

// handleBufferCompleteForQueue:buffer: should not change the state

// (may not enter the synchronized section).

//

if (buffersUsed == 0 && self.state == AS_PLAYING)

{

err = AudioQueuePause(audioQueue);

if (err)

{

[self failWithErrorCode:AS_AUDIO_QUEUE_PAUSE_FAILED];

return;

}

self.state = AS_BUFFERING;

}

while (isRunning && ![self runLoopShouldExit]);


这里第一步会调用 openReadStream方法,第二步当返回yes时,就会继续执行do-while语句,这里会碰到runloop循环:

- (BOOL)openReadStream

{

@synchronized(self)

{

NSAssert([[NSThread currentThread] isEqual:internalThread],

@"File stream download must be started on the internalThread");

NSAssert(stream == nil@"Download stream already initialized");

        NSLog(@"opopop   %@",url.absoluteString);

        if (url !=nil && [url.absoluteString rangeOfString:@"file"].location == NSNotFound){

//

// Create the HTTP GET request

//  

            isLocalFile = NO;


。。。。。。

}

如果url不是空,而且不是本地文件的时候,设置isLocalFile = NO;

剩下的几句重要的代码就是:

1.set useful headers

            CFHTTPMessageRef message= CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (CFURLRef)urlkCFHTTPVersion1_1);

    #ifdef SHOUTCAST_METADATA

            CFHTTPMessageSetHeaderFieldValue(message, CFSTR("icy-metadata"), CFSTR("1"));

    #endif

2.create the CFReadStreamRef:

            stream = CFReadStreamCreateForHTTPRequest(NULL, message);

            CFRelease(message);

           if (CFReadStreamSetProperty(

                                        stream,

                                        kCFStreamPropertyAppendToFile,

                                        kCFBooleanTrue) == false)

            {

                [self presentAlertWithTitle:NSLocalizedStringFromTable(@"File Error"@"Errors"nil)

                                    message:NSLocalizedStringFromTable(@"Unable to configure network read stream."@"Errors"nil)];

                return NO;

            }

    if (!CFReadStreamOpen(stream))

            {

CFRelease(stream);

[self presentAlertWithTitle:NSLocalizedStringFromTable(@"File Error"@"Errors"nil)message:NSLocalizedStringFromTable(@"Unable to configure network read stream."@"Errors"nil)];

return NO;

    }

    CFStreamClientContext context = {0selfNULLNULLNULL};

            CFReadStreamSetClient(

stream,

kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,

ASReadStreamCallBack,

&context);

    CFReadStreamScheduleWithRunLoop(streamCFRunLoopGetCurrent(), kCFRunLoopCommonModes);

这几句主要是CFHTTPMessage网络请求,与nsurl的get请求有几分相似,可以一起比较一下。

这时候会回调ASReadStreamCallBack 方法。

#pragma mark CFReadStream Callback Function Implementations

//

// ReadStreamCallBack

//

// This is the callback for the CFReadStream from the network connection. This

// is where all network data is passed to the AudioFileStream.

//

// Invoked when an error occurs, the stream ends or we have data to read.

//

void ASReadStreamCallBack

(

   CFReadStreamRef aStream,

   CFStreamEventType eventType,

   void* inClientInfo

)

{

AudioStreamer* streamer = (AudioStreamer *)inClientInfo;

[streamer handleReadFromStream:aStream eventType:eventType];

}







原创粉丝点击