int32_t setup_queue( ALACMagicCookie cookie, PlayerInfo *playerInfo, uint32_t buffer_size, uint32_t num_buffers, uint32_t num_packets ) { // Create Audio Queue for ALAC AudioStreamBasicDescription inFormat = {0}; inFormat.mSampleRate = ntohl(cookie.sampleRate); inFormat.mFormatID = kAudioFormatAppleLossless; inFormat.mFormatFlags = 0; // ALAC uses no flags inFormat.mBytesPerPacket = 0; // Variable size (must use AudioStreamPacketDescription) inFormat.mFramesPerPacket = ntohl(cookie.frameLength); inFormat.mBytesPerFrame = 0; // Compressed inFormat.mChannelsPerFrame = 2; // Stero TODO: get from fmtp? inFormat.mBitsPerChannel = 0; // Compressed inFormat.mReserved = 0; OSStatus err = AudioQueueNewOutput( &inFormat, c_callback, playerInfo, // User data NULL, // Run on audio queue's thread NULL, // Callback run loop's mode 0, // Reserved &playerInfo->queue); if (err) return err; // Need to set the magic cookie too (tail fmtp) err = AudioQueueSetProperty(playerInfo->queue, kAudioQueueProperty_MagicCookie, &cookie, sizeof(ALACMagicCookie)); if (err) return err; // Create input buffers, and enqueue using callback for (int i = 0; i < num_buffers; i++) { AudioQueueBufferRef buffer; err = AudioQueueAllocateBufferWithPacketDescriptions( playerInfo->queue, buffer_size, num_packets, &buffer); if (err) return err; c_callback(playerInfo, playerInfo->queue, buffer); } // Volume full err = AudioQueueSetParameter(playerInfo->queue, kAudioQueueParam_Volume, 1.0); if (err) return err; // Prime err = AudioQueuePrime(playerInfo->queue, 0, NULL); if (err) return err; // Start err = AudioQueueStart(playerInfo->queue, NULL); if (err) return err; return 0; }
void AudioStreamDecoder::PropertyCallback(AudioFileStreamID stream, AudioFileStreamPropertyID property, UInt32* flags) { if (property != kAudioFileStreamProperty_ReadyToProducePackets) return; long err; void* buffer = NULL; unsigned char writable; AudioStreamBasicDescription desc = {0}; UInt32 size = sizeof(desc); BAIL_IF(!stream || stream != mStream, "Invalid stream %p\n", stream); err = AudioFileStreamGetProperty(mStream, kAudioFileStreamProperty_DataFormat, &size, &desc); BAIL_IF(err, "AudioFileStreamGetProperty returned %ld\n", err); err = AudioQueueNewOutput(&desc, StaticBufferCompleteCallback, this, NULL, NULL, 0, &mQueue); BAIL_IF(err, "AudioQueueNewOutput returned %ld\n", err); err = AudioQueueAddPropertyListener(mQueue, kAudioQueueProperty_IsRunning, StaticQueueRunningCallback, this); BAIL_IF(err, "AudioQueueAddPropertyListener returned %ld\n", err); for (int i = 0; i < kBufferCount; i++) { err = AudioQueueAllocateBufferWithPacketDescriptions(mQueue, kBufferSize, kBufferPacketDescs, mBuffers + i); BAIL_IF(err, "AudioQueueAllocateBuffer returned %ld\n", err); } mCurrentBuffer = mBuffers; (*mCurrentBuffer)->mUserData = this; err = AudioFileStreamGetPropertyInfo(mStream, kAudioFileStreamProperty_MagicCookieData, &size, &writable); BAIL_IF(err, "AudioFileStreamGetPropertyInfo returned %ld\n", err); buffer = malloc(size); BAIL_IF(!buffer, "Failed to allocate %u byte buffer for cookie\n", (unsigned int)size); err = AudioFileStreamGetProperty(mStream, kAudioFileStreamProperty_MagicCookieData, &size, buffer); BAIL_IF(err, "AudioFileStreamGetProperty returned %ld\n", err); err = AudioQueueSetProperty(mQueue, kAudioQueueProperty_MagicCookie, buffer, size); BAIL_IF(err, "AudioQueueSetProperty returned %ld\n", err); bail: free(buffer); }
int main (int argc, const char *argv[]) { OSStatus result; State *state = NULL; if (argc != 2) { printf("Usage: play <file>\n"); goto error; } state = StateCreate(); // // open the audio file // CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, (const UInt8*)argv[1], strlen(argv[1]), false ); if (!fileURL) { Error("Invalid filename"); goto error; } result = AudioFileOpenURL( fileURL, kAudioFileReadPermission, 0, &state->audioFile ); CFRelease(fileURL); if (result) { Error("Invalid audio file"); goto error; } // // determine properties of stream including maximum packet size // UInt32 propertyDataSize; AudioStreamBasicDescription streamDescription; propertyDataSize = sizeof(streamDescription); result = AudioFileGetProperty( state->audioFile, kAudioFilePropertyDataFormat, &propertyDataSize, &streamDescription ); if (result) { Error(NULL); goto error; } UInt32 maximumPacketSize; propertyDataSize = sizeof(maximumPacketSize); result = AudioFileGetProperty( state->audioFile, kAudioFilePropertyMaximumPacketSize, &propertyDataSize, &maximumPacketSize ); if (result) { Error(NULL); goto error; } // // initialize the audio queue and allocate buffers // result = AudioQueueNewOutput( &streamDescription, AudioQueueOutput, state, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &state->audioQueue ); if (result) { Error("Failed to initialize audio queue"); goto error; } state->audioBufferSize = maximumPacketSize * PACKETS_PER_BUFFER; AudioQueueBufferRef audioQueueBuffers[NUM_BUFFERS]; for (int i = 0; i < NUM_BUFFERS; ++i) { result = AudioQueueAllocateBufferWithPacketDescriptions( state->audioQueue, state->audioBufferSize, PACKETS_PER_BUFFER, &audioQueueBuffers[i] ); if (result) { Error("Failed to initialize audio queue buffer"); goto error; } } result = AudioQueueAddPropertyListener( state->audioQueue, kAudioQueueProperty_IsRunning, AudioQueuePropertyListener, NULL ); // // prime and start the audio queue // AudioQueueOutput( state, state->audioQueue, audioQueueBuffers[0] ); result = AudioQueueStart( state->audioQueue, NULL ); if (result) { Error("Failed to start audio queue"); goto error; } // // start the run loop that will dispatch audio queue callbacks // CFRunLoopRun(); StateDestroy(state); return 0; error: if (state) { StateDestroy(state); } return 1; }