Streaming Audio - AudioFileStream, CFReadStreamRead and AudioQueue
Streaming Audio - AudioFileStream, CFReadStreamRead and AudioQueue
- Subject: Streaming Audio - AudioFileStream, CFReadStreamRead and AudioQueue
- From: "Adam Fox" <email@hidden>
- Date: Wed, 30 Jul 2008 12:34:17 +0100
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