流媒体播放-在线音乐播放(2)


// MyFindQueueBuffer

//

// Returns the index of the specified buffer in the audioQueueBuffer array.

//

// This function is unchanged from Apple's example in AudioFileStreamExample.

//

int MyFindQueueBuffer(xxxxx* myData, AudioQueueBufferRef inBuffer)

{

    for (unsigned int i = 0; i < kNumAQBufs; ++i) {

        if (inBuffer == myData->buffers)

            return i;

    }

    return -1;

}



//

// MyAudioQueueOutputCallback

//

// Called from the AudioQueue when playback of specific buffers completes. This

// function signals from the AudioQueue thread to the AudioStream thread that

// the buffer is idle and available for copying data.

//

// This function is unchanged from Apple's example in AudioFileStreamExample.

//

void MyAudioQueueOutputCallback(void* inClientData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)

{

    // this is called by the audio queue when it has finished decoding our data.

    // The buffer is now free to be reused.

    xxxxx* myData = (xxxxx*)inClientData;

    unsigned int bufIndex = MyFindQueueBuffer(myData, inBuffer);

    

    // signal waiting thread that the buffer is free.

    pthread_mutex_lock(&myData->mutex);

    myData->inuse[bufIndex] = false;

    pthread_cond_signal(&myData->cond);

    pthread_mutex_unlock(&myData->mutex);

}



//

// MyAudioQueueIsRunningCallback

//

// Called from the AudioQueue when playback is started or stopped. This

// information is used to toggle the observable "isPlaying" property and

// set the "finished" flag.

//

void MyAudioQueueIsRunningCallback(void *inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID)

{

    xxxxx *myData = (xxxxx *)inUserData;

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    

    if (myData.isPlaying)

    {

        myData->trackEnded = true;

        myData.isPlaying = false;

        

#ifdef TARGET_OS_IPHONE

        AudioSessionSetActive(false);

#endif

    }

    else

    {

        myData.isPlaying = true;

        if (myData->trackEnded)

        {

            myData.isPlaying = false;

        }

        

        //

        // Note about this bug avoidance quirk:

        //

        // On cleanup of the AudioQueue thread, on rare occasions, there would

        // be a crash in CFSetContainsValue as a CFRunLoopObserver was getting

        // removed from the CFRunLoop.

        //

        // After lots of testing, it appeared that the audio thread was

        // attempting to remove CFRunLoop observers from the CFRunLoop after the

        // thread had already deallocated the run loop.

        //

        // By creating an NSRunLoop for the AudioQueue thread, it changes the

        // thread destruction order and seems to avoid this crash bug -- or

        // at least I haven't had it since (nasty hard to reproduce error!)

        //

        [NSRunLoop currentRunLoop];

    }

    

    [pool release];

}



#ifdef TARGET_OS_IPHONE

//

// MyAudioSessionInterruptionListener

//

// Invoked if the audio session is interrupted (like when the phone rings)

//

void MyAudioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState)

{

}

#endif



#pragma mark -

#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 ReadStreamCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void* dataIn)

{

    xxxxx *myData = (xxxxx *)dataIn;

    

    if (eventType == kCFStreamEventErrorOccurred)

    {

        myData->failed = YES;

    }

    else if (eventType == kCFStreamEventEndEncountered)

    {

        if (myData->failed || myData->trackEnded)

        {

            return;

        }

        

        //

        // If there is a partially filled buffer, pass it to the AudioQueue for

        // processing

        //

        if (myData->bytesFilled)

        {

            MyEnqueueBuffer(myData);

        }

        

        //

        // If the AudioQueue started, then flush it (to make certain everything

        // sent thus far will be processed) and subsequently stop the queue.

        //

        if (myData->started)

        {

            OSStatus err = AudioQueueFlush(myData->queue);

            if (err) { NSLog(@"AudioQueueFlush"); return; }

            

            err = AudioQueueStop(myData->queue, false);

            if (err) { NSLog(@"AudioQueueStop"); return; }

            

            CFReadStreamClose(stream);

            CFRelease(stream);

            myData->stream = nil;

        }

        else

        {

            //

            // If we have reached the end of the file without starting, then we

            // have failed to find any audio in the file. Abort.

            //

            myData->failed = YES;

        }

    }

    else if (eventType == kCFStreamEventHasBytesAvailable)

    {

        if (myData->failed || myData->trackEnded)

        {

            return;

        }

        

        //

        // Read the bytes from the stream

        //

        UInt8 bytes[kAQBufSize];

        CFIndex length = CFReadStreamRead(stream, bytes, kAQBufSize);

        

        if (length == -1)

        {

            myData->failed = YES;

            return;

        }

        

        //

        // Parse the bytes read by sending them through the AudioFileStream

        //

        if (length > 0)

        {

            if (myData->discontinuous)

            {

                OSStatus err = AudioFileStreamParseBytes(myData->audioFileStream, length, bytes, kAudioFileStreamParseFlag_Discontinuity);

                if (err) { NSLog(@"AudioFileStreamParseBytes"); myData->failed = true;}

            }

            else

            {

                OSStatus err = AudioFileStreamParseBytes(myData->audioFileStream, length, bytes, 0);

                if (err) { NSLog(@"AudioFileStreamParseBytes"); myData->failed = true; }

            }

        }

    }

}



@interface xxxxx (private)



static void propertyListenerCallback(void *inUserData, AudioQueueRef queueObject, AudioQueuePropertyID propertyID);

- (void) playBackIsRunningStateChanged;



static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer);

- (void) callbackForBuffer:(AudioQueueBufferRef)buffer;

- (UInt32) readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;



@end



@implementation xxxxx



@synthesize isPlaying, trackClosed;



#pragma mark -

#pragma mark xxxxx



- (void)dealloc

{

    [self close];

    if (packetDescs != nil)

        free(packetDescs);

    [url release];

    [super dealloc];

}



- (void)close

{

    // it is preferrable to call close first, if there is a problem waiting for an autorelease

    if (trackClosed)

        return;

    trackClosed = YES;

    AudioQueueStop(queue, YES); // <-- YES means stop immediately

    AudioQueueDispose(queue, YES);

    AudioFileClose(audioFile);

    kxxxTrackActive = NO;

}



- (id)initWithURL:(NSURL*)newUrl

{

    self = [super init];

    if (self != nil)

    {

        url = [newUrl retain];

    }

    return self;

}



- (id)initWithPath:(NSString*)path

{

    UInt32 size, maxPacketSize;

    char *cookie;

    int i;

    

    if (kxxxTrackActive)

    {

        NSLog(@"Other music is playing.");

        return nil;

    }

    

    if (path == nil) return nil;

    if(!(self = [super init])) return nil;

    

    // try to open up the file using the specified path

    if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x01, 0, &audioFile))

    {

        NSLog(@"File can not be opened!");

        return nil;

    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值