Re: Streaming Audio - AudioFileStream, CFReadStreamRead and AudioQueue
Re: Streaming Audio - AudioFileStream, CFReadStreamRead and AudioQueue
- Subject: Re: Streaming Audio - AudioFileStream, CFReadStreamRead and AudioQueue
- From: "Adam Fox" <email@hidden>
- Date: Thu, 31 Jul 2008 11:02:31 +0100
Yay I have finally figured this out. What a relief :) If anyone needs
help getting the same thing working you can contact me :)
ps. Sorry Jens for mailing you personally I believed I was replying to
the mailing list..
On Wed, Jul 30, 2008 at 12:34 PM, Adam Fox <email@hidden> wrote:
> Hi guys,
>
> I am trying to stream and play MP3 file over network.
>
> Here is what I have got so far using AudioFileStream, CFReadStream and
> AudioQueue..
>
> I hope it helps some people start off, and I hope some people can help
> me finish!
>
> First, I define a custom data structure to hold stuff throughout..
>
> [code]
> typedef struct {
> AudioFileStreamID audioFileStream;
> AudioStreamBasicDescription *mDataFormat;
> AudioQueueRef mQueue;
> CFReadStream readStream;
> UInt32 mNumPackets;
> AudioStreamPacketDescription *mPacketDescs;
> } CustomData;
>
> CustomData customData;
> [/code]
>
> I set up an AudioFileStream..
>
> [code]
> AudioFileStreamOpen(0,
> audioFileStream_Properties,
> audioFileStream_Packets,
> kAudioFileMP3Type,
> &customData.audioFileStream);
> [/code]
>
> ..this has call back functions attached when the AudioFileStream
> receives either stream properties or stream packets..
>
> I then open a data stream to a URL of an MP3 stream..
>
> [code]
> NSURL *url = [NSURL URLWithString:@"http://mp3stream.com"];
> CFHTTPMessageRef message = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
> CFSTR("GET"),
> (CFURLRef)url,
> kCFHTTPVersion1_1);
>
> customData.readStream =
> CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, message);
> CFOptionFlags events = kCFStreamEventHasBytesAvailable |
> kCFStreamEventErrorOccured | kCFStreamEventEndEncountered;
>
> CFStreamClientContext dataStreamContext = {0, self, NULL, NULL, NULL};
>
> if (CFReadStreamSetClient(customData.readStream, events,
> readStreamEventCallBack, &dataStreamContext)) {
> CFReadStreamScheduleWithRunLoop(customData.readStream,
> CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
> }
>
> CFReadStreamOpen(customData.readStream);
> [/code]
>
> ..this opens a CFReadStream with a call back function that is called
> on bytes available events, error events and end events..
>
> [code]
> void readStreamEventCallBack(CFReadStreamRef stream, CFStreamEventType
> eventType, void *clientcallBackInfo) {
>
> switch(eventType) {
> case kCFStreamEventHasBytesAvailable:
> UInt8 buf[4096];
> CFIndex bytesRead = CFReadStreamRead(stream, buf, 4096);
> if (bytesRead > 0) {
> AudioFileStreamParseBytes(customData.audioFileStream,
> bytesRead, buf, 0);
> }
>
> case kCFStreamEventErrorOccurred:
> //do stuff
> break;
>
> case kCFStreamEventEndOccurred:
> //do stuff
> break;
>
> }
>
>
> }
> [/code]
>
>
> So when the CFReadStream reads some bytes it passes them to the
> AudioFileStream which will in turn call its callback functions when it
> receives stream properties or stream packets..
>
> In audioFileStream_Properties I attempt to get the dataFormat of the stream..
> I also set up an Audio Queue....
>
> [code]
> void audioFileStream_Properties (void *inClientData,
> AudioFileStreamID inAudioFileStream,
> AudioFileStreamPropertyID inPropertyID,
> UInt32 *ioFlags) {
>
> if (inPropertyID == kAudioFileStreamProperty_ReadyToProducePackets) {
>
> AudioQueueNewOutput(customData.mDataFormat,
> AudioOutputCallBack,
> &customData,
> NULL,
> kCFRunLoopCommonModes,
> 0,
> &customData.mQueue);
>
> } if (inPropertyID == kAudioFileStreamProperty_DataFormat) {
>
> UInt32 size;
> AudioFileStreamGetPropertyInfo(inAudioFileStream,
> inPropertyID, &size, nil)
> AudioFileStreamGetProperty(inAudioFileStream, inPropertyID,
> &size, customData.mDataFormat);
> }
> }
> [/code]
>
> Most of these function calls return an OSStatus which I check for
> error (!= 0) but I have left them out for now.. I get an error setting
> mDataFormat using AudioFileStreamGetProperty..
>
> Then the AudioFileStream packets..
>
> [code]
> void audioFileStream_Packets (void *inClientData,
> UInt32 inNumberBytes,
> UInt32 inNumberPackets,
> const void *inInputData,
> AudioStreamPacketDescription *inPacketDescs) {
>
> customData.mNumPackets = inNumberPackets;
> customData.mPacketDescs = inPacketDescs;
>
> AudioQueueBufferRef outBuffer;
> AudioQueueAllocateBuffer(customData.mQueue, inNumberBytes, &outBuffer);
> AudioOutputCallBack(&customData, customData.mQueue, outBuffer);
>
> }
> [/code]
>
> ..here I try and allocate the stream packets into the an
> AudioQueueBuffer and force that buffer into the AudioQueue callback..
>
> [code]
> static void AudioOutputCallBack(void *inCustomData,
> AudioQueueRef outAQ,
> AudioQueueBufferRef) {
>
> CustomData *customData = (CustomData*)inCustomData;
>
> AudioQueueEnqueueBuffer(customData->mQueue, outBuffer,
> (customData->mPacketDescs ? customData->mNumPackets : 0),
> playState->mPacketDescs);
>
> }
> [/code]
>
> ..I believe I am very close but I still have two problems...
>
> Firstly, I think I am getting or setting mDataFormat incorrectly as I
> get an error.....
>
> Mainly, I am unsure how to proceed from here.. I am getting audio data
> packets in my callback... but how do I transfer them properly to the
> AudioQueue. Does anyone have some example code for doing this?
>
> Hope this is clear enough.... and thanks in advance to anyone who can
> offer assistance!
>
> Adam
>
> null
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden