コード例 #1
0
void MyPropertyListenerProc(	void *							inClientData,
								AudioFileStreamID				inAudioFileStream,
								AudioFileStreamPropertyID		inPropertyID,
								UInt32 *						ioFlags)
{	
	// this is called by audio file stream when it finds property values
	MyData* myData = (MyData*)inClientData;
	OSStatus err = noErr;

	printf("found property '%c%c%c%c'\n", (inPropertyID>>24)&255, (inPropertyID>>16)&255, (inPropertyID>>8)&255, inPropertyID&255);

	switch (inPropertyID) {
		case kAudioFileStreamProperty_ReadyToProducePackets :
		{
			// the file stream parser is now ready to produce audio packets.
			// get the stream format.
			AudioStreamBasicDescription asbd;
			UInt32 asbdSize = sizeof(asbd);
			err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
			if (err) { PRINTERROR("get kAudioFileStreamProperty_DataFormat"); myData->failed = true; break; }
			
			// create the audio queue
			err = AudioQueueNewOutput(&asbd, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &myData->audioQueue);
			if (err) { PRINTERROR("AudioQueueNewOutput"); myData->failed = true; break; }
			
			// allocate audio queue buffers
			for (unsigned int i = 0; i < kNumAQBufs; ++i) {
				err = AudioQueueAllocateBuffer(myData->audioQueue, kAQBufSize, &myData->audioQueueBuffer[i]);
				if (err) { PRINTERROR("AudioQueueAllocateBuffer"); myData->failed = true; break; }
			}

			// get the cookie size
			UInt32 cookieSize;
			Boolean writable;
			err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable);
			if (err) { PRINTERROR("info kAudioFileStreamProperty_MagicCookieData"); break; }
			printf("cookieSize %d\n", cookieSize);

			// get the cookie data
			void* cookieData = calloc(1, cookieSize);
			err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData);
			if (err) { PRINTERROR("get kAudioFileStreamProperty_MagicCookieData"); free(cookieData); break; }

			// set the cookie on the queue.
			err = AudioQueueSetProperty(myData->audioQueue, kAudioQueueProperty_MagicCookie, cookieData, cookieSize);
			free(cookieData);
			if (err) { PRINTERROR("set kAudioQueueProperty_MagicCookie"); break; }

			// listen for kAudioQueueProperty_IsRunning
			err = AudioQueueAddPropertyListener(myData->audioQueue, kAudioQueueProperty_IsRunning, MyAudioQueueIsRunningCallback, myData);
			if (err) { PRINTERROR("AudioQueueAddPropertyListener"); myData->failed = true; break; }
			
			break;
		}
	}
}
コード例 #2
0
void Audio_Queue::setCookiesForStream(AudioFileStreamID inAudioFileStream)
{
    OSStatus err;
    
    // get the cookie size
    UInt32 cookieSize;
    Boolean writable;
    
    err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable);
    if (err) {
        AQ_TRACE("error in info kAudioFileStreamProperty_MagicCookieData\n");
        return;
    }
    AQ_TRACE("cookieSize %lu\n", cookieSize);
    
    // get the cookie data
    void* cookieData = calloc(1, cookieSize);
    err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData);
    if (err) {
        AQ_TRACE("error in get kAudioFileStreamProperty_MagicCookieData");
        free(cookieData);
        return;
    }
    
    // set the cookie on the queue.
    err = AudioQueueSetProperty(m_outAQ, kAudioQueueProperty_MagicCookie, cookieData, cookieSize);
    free(cookieData);
    if (err) {
        AQ_TRACE("error in set kAudioQueueProperty_MagicCookie");
    }
}
コード例 #3
0
void Audio_Stream::setCookiesForStream(AudioFileStreamID inAudioFileStream)
{
    OSStatus err;
    
    // get the cookie size
    UInt32 cookieSize;
    Boolean writable;
    
    err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable);
    if (err) {
        return;
    }
    
    // get the cookie data
    void* cookieData = calloc(1, cookieSize);
    err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData);
    if (err) {
        free(cookieData);
        return;
    }
    
    // set the cookie on the queue.
    if (m_audioConverter) {
        err = AudioConverterSetProperty(m_audioConverter, kAudioConverterDecompressionMagicCookie, cookieSize, cookieData);
    }
    
    free(cookieData);
}
コード例 #4
0
static void
_MetadataCallback(void* aAppleATDecoder,
                  AudioFileStreamID aStream,
                  AudioFileStreamPropertyID aProperty,
                  UInt32* aFlags)
{
  AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aAppleATDecoder);
  LOG("MetadataCallback receiving: '%s'", FourCC2Str(aProperty));
  if (aProperty == kAudioFileStreamProperty_MagicCookieData) {
    UInt32 size;
    Boolean writeable;
    OSStatus rv = AudioFileStreamGetPropertyInfo(aStream,
                                                 aProperty,
                                                 &size,
                                                 &writeable);
    if (rv) {
      LOG("Couldn't get property info for '%s' (%s)",
          FourCC2Str(aProperty), FourCC2Str(rv));
      decoder->mFileStreamError = true;
      return;
    }
    nsAutoArrayPtr<uint8_t> data(new uint8_t[size]);
    rv = AudioFileStreamGetProperty(aStream, aProperty,
                                    &size, data);
    if (rv) {
      LOG("Couldn't get property '%s' (%s)",
          FourCC2Str(aProperty), FourCC2Str(rv));
      decoder->mFileStreamError = true;
      return;
    }
    decoder->mMagicCookie.AppendElements(data.get(), size);
  }
}
コード例 #5
0
/* This is called by audio file stream parser when it finds property values */
void Audio_Stream::propertyValueCallback(void *inClientData, AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags)
{
    AS_TRACE("%s\n", __PRETTY_FUNCTION__);
    Audio_Stream *THIS = static_cast<Audio_Stream*>(inClientData);
    
    if (!THIS->m_audioStreamParserRunning) {
        AS_TRACE("%s: stray callback detected!\n", __PRETTY_FUNCTION__);
        return;
    }
    
    switch (inPropertyID) {
        case kAudioFileStreamProperty_DataOffset: {
            SInt64 offset;
            UInt32 offsetSize = sizeof(offset);
            OSStatus result = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataOffset, &offsetSize, &offset);
            if (result == 0) {
                THIS->m_dataOffset = offset;
            } else {
                AS_TRACE("%s: reading kAudioFileStreamProperty_DataOffset property failed\n", __PRETTY_FUNCTION__);
            }
            
            break;
        }
        default: {
            THIS->m_audioQueue->handlePropertyChange(inAudioFileStream, inPropertyID, ioFlags);
            break;
        }
    }
}
コード例 #6
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);
}
コード例 #7
0
void DZAudioQueuePlayer::onProperty(AudioFileStreamPropertyID pID)
{
    UInt32 propertySize = 0;
    switch (pID) {
        // Create audio queue with given data format.
        case kAudioFileStreamProperty_DataFormat:
            propertySize = sizeof(this->_format);
            if (dzDebugOK(AudioFileStreamGetProperty(this->_parser, pID, &(propertySize), &(this->_format)), "Fail to get audio file stream property: DataFormat.")) {
                if (this->_queue != NULL) {
                    dzDebug(!noErr, "Audio file stream duplicated data format.");
                } else {
                    if (dzDebugError(AudioQueueNewOutput(&(this->_format), QueueCallback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &(this->_queue)), "Create new output audio queue failed.")) {
                        this->_queue = NULL;
                    }
                }
            }
            break;
            
        // Extract magic cookie data.
        case kAudioFileStreamProperty_MagicCookieData:
            if (noErr == AudioFileStreamGetPropertyInfo(this->_parser, pID, &(propertySize), NULL)) {
                this->_magicCookie = malloc(propertySize);
                this->_magicCookieSize = propertySize;
                if (this->_magicCookie != NULL && dzDebugError(AudioFileStreamGetProperty(this->_parser, pID, &(propertySize), this->_magicCookie), "Fail to get audio file stream property: MagicCookieData.")) {
                    free(this->_magicCookie);
                    this->_magicCookie = NULL;
                    this->_magicCookieSize = 0;
                }
            }
            break;
            
        // Set magic cookie data if any. (Queue shall be already created.)
        case kAudioFileStreamProperty_ReadyToProducePackets:
            if (this->_queue != NULL && this->_magicCookie != NULL) {
                dzDebug(AudioQueueSetProperty(this->_queue, kAudioQueueProperty_MagicCookie, this->_magicCookie, this->_magicCookieSize), "Fail to set audio queue property: MagicCookie.");
            }
            if (this->_queue != NULL && this->_parser != NULL) {
                this->_status = DZAudioQueuePlayerStatus_ReadyToStart;
            }
            break;
        default:
            break;
    }
}
コード例 #8
0
ファイル: audio_queue.cpp プロジェクト: chinshou/FreeStreamer
void Audio_Queue::handlePropertyChange(AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags)
{
    OSStatus err = noErr;
    
    AQ_TRACE("found property '%lu%lu%lu%lu'\n", (inPropertyID>>24)&255, (inPropertyID>>16)&255, (inPropertyID>>8)&255, inPropertyID&255);
    
    switch (inPropertyID) {
        case kAudioFileStreamProperty_ReadyToProducePackets:
        {
            // the file stream parser is now ready to produce audio packets.
            // get the stream format.
            AudioStreamBasicDescription asbd;
            memset(&asbd, 0, sizeof(asbd));
            UInt32 asbdSize = sizeof(asbd);
            err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
            if (err) {
                AQ_TRACE("get kAudioFileStreamProperty_DataFormat\n");
                m_lastError = err;
                break;
            }
            
            // create the audio queue
            err = AudioQueueNewOutput(&asbd, audioQueueOutputCallback, this, NULL, NULL, 0, &m_outAQ);
            if (err) {
                AQ_TRACE("AudioQueueNewOutput\n");
                m_lastError = err;
                break;
            }
            
            // allocate audio queue buffers
            for (unsigned int i = 0; i < AQ_BUFFERS; ++i) {
                err = AudioQueueAllocateBuffer(m_outAQ, AQ_BUFSIZ, &m_audioQueueBuffer[i]);
                if (err) {
                    AQ_TRACE("AudioQueueAllocateBuffer\n");
                    m_lastError = err;
                    break;
                }
            }
            
            setCookiesForStream(inAudioFileStream);
            
            // listen for kAudioQueueProperty_IsRunning
            err = AudioQueueAddPropertyListener(m_outAQ, kAudioQueueProperty_IsRunning, audioQueueIsRunningCallback, this);
            if (err) {
                AQ_TRACE("error in AudioQueueAddPropertyListener");
                m_lastError = err;
                break;
            }
            
            break;
        }
    }
}
コード例 #9
0
SInt64 DZAudioQueuePlayer::seek(float time)
{
    // Cannot seek if parameters not available or parser/queue not ready.
    if (this->_format.mSampleRate <= 0 || this->_format.mFramesPerPacket <= 0) {
        return -1;
    }
    if (this->_parser == NULL || this->_queue == NULL
        || this->_status == DZAudioQueuePlayerStatus_NotReady
        || this->_status == DZAudioQueuePlayerStatus_Error) {
        return -1;
    }
    
    // Get audio data offset.
    SInt64 dataOffset = 0;
    UInt32 propertySize = sizeof(dataOffset);
    if (dzDebugError(AudioFileStreamGetProperty(this->_parser, kAudioFileStreamProperty_DataOffset, &propertySize, &dataOffset), "Fail to get stream data offset.")) {
        return -1;
    }
    
    // Reset audio queue to clear the current queue buffer.
    if (dzDebugError(AudioQueueReset(this->_queue), "Fail to reset audio queue.")) {
        return -1;
    }
    
    // Get audio queue current time.
    AudioTimeStamp timeStamp;
    if (this->_status == DZAudioQueuePlayerStatus_ReadyToStart) {
        timeStamp.mSampleTime = 0;
    } else if (dzDebugError(AudioQueueGetCurrentTime(this->_queue, NULL, &(timeStamp), NULL),
                     "Fail to get audio queue current time.")) {
        return -1;
    }
    
    // Calculate packet offset and so the byte offset.
    SInt64 packetOffset = round(time * this->_format.mSampleRate / this->_format.mFramesPerPacket);
    SInt64 byteOffset = 0;
    UInt32 ioFlag = 0;
    if (dzDebugError(AudioFileStreamSeek(this->_parser, packetOffset, &byteOffset, &ioFlag),
                     "Fail to seek in audio file stream.")) {
        return -1;
    }
    this->_timeAmendment = time - timeStamp.mSampleTime / this->_format.mSampleRate;
    return byteOffset + dataOffset;
}
コード例 #10
0
/*
 * Query the MP3 parser for a piece of metadata.
 */
static nsresult
GetProperty(AudioFileStreamID aAudioFileStream,
            AudioFileStreamPropertyID aPropertyID, void *aData)
{
  UInt32 size;
  Boolean writeable;
  OSStatus rv = AudioFileStreamGetPropertyInfo(aAudioFileStream, aPropertyID,
                                               &size, &writeable);

  if (rv) {
    LOGW("Couldn't get property " PROPERTY_ID_FORMAT "\n",
         PROPERTY_ID_PRINT(aPropertyID));
    return NS_ERROR_FAILURE;
  }

  rv = AudioFileStreamGetProperty(aAudioFileStream, aPropertyID,
                                  &size, aData);

  return NS_OK;
}
コード例 #11
0
ファイル: AppleATDecoder.cpp プロジェクト: luke-chang/gecko-1
static void
_MetadataCallback(void* aAppleATDecoder,
                  AudioFileStreamID aStream,
                  AudioFileStreamPropertyID aProperty,
                  UInt32* aFlags)
{
  AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aAppleATDecoder);
  MOZ_RELEASE_ASSERT(decoder->mTaskQueue->IsCurrentThreadIn());

  LOGEX(decoder, "MetadataCallback receiving: '%s'", FourCC2Str(aProperty));
  if (aProperty == kAudioFileStreamProperty_MagicCookieData) {
    UInt32 size;
    Boolean writeable;
    OSStatus rv = AudioFileStreamGetPropertyInfo(aStream,
                                                 aProperty,
                                                 &size,
                                                 &writeable);
    if (rv) {
      LOGEX(decoder,
            "Couldn't get property info for '%s' (%s)",
            FourCC2Str(aProperty),
            FourCC2Str(rv));
      decoder->mFileStreamError = true;
      return;
    }
    auto data = MakeUnique<uint8_t[]>(size);
    rv = AudioFileStreamGetProperty(aStream, aProperty,
                                    &size, data.get());
    if (rv) {
      LOGEX(decoder,
            "Couldn't get property '%s' (%s)",
            FourCC2Str(aProperty),
            FourCC2Str(rv));
      decoder->mFileStreamError = true;
      return;
    }
    decoder->mMagicCookie.AppendElements(data.get(), size);
  }
}
コード例 #12
0
void Audio_Queue::handlePropertyChange(AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags)
{
    OSStatus err = noErr;
    
    AQ_TRACE("found property '%lu%lu%lu%lu'\n", (inPropertyID>>24)&255, (inPropertyID>>16)&255, (inPropertyID>>8)&255, inPropertyID&255);
    
    switch (inPropertyID) {
        case kAudioFileStreamProperty_ReadyToProducePackets:
        {
            cleanup();
            
            // the file stream parser is now ready to produce audio packets.
            // get the stream format.
            memset(&m_streamDesc, 0, sizeof(m_streamDesc));
            UInt32 asbdSize = sizeof(m_streamDesc);
            err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &m_streamDesc);
            if (err) {
                AQ_TRACE("%s: error in kAudioFileStreamProperty_DataFormat\n", __PRETTY_FUNCTION__);
                m_lastError = err;
                break;
            }
            
            // create the audio queue
            err = AudioQueueNewOutput(&m_streamDesc, audioQueueOutputCallback, this, CFRunLoopGetCurrent(), NULL, 0, &m_outAQ);
            if (err) {
                AQ_TRACE("%s: error in AudioQueueNewOutput\n", __PRETTY_FUNCTION__);
                
                if (m_delegate) {
                    m_delegate->audioQueueInitializationFailed();
                }
                
                m_lastError = err;
                break;
            }
            
            // allocate audio queue buffers
            for (unsigned int i = 0; i < AQ_BUFFERS; ++i) {
                err = AudioQueueAllocateBuffer(m_outAQ, AQ_BUFSIZ, &m_audioQueueBuffer[i]);
                if (err) {
                    /* If allocating the buffers failed, everything else will fail, too.
                     *  Dispose the queue so that we can later on detect that this
                     *  queue in fact has not been initialized.
                     */
                    
                    AQ_TRACE("%s: error in AudioQueueAllocateBuffer\n", __PRETTY_FUNCTION__);
                    
                    (void)AudioQueueDispose(m_outAQ, true);
                    m_outAQ = 0;
                    
                    if (m_delegate) {
                        m_delegate->audioQueueInitializationFailed();
                    }
                    
                    m_lastError = err;
                    break;
                }
            }
            
            setCookiesForStream(inAudioFileStream);
            
            // listen for kAudioQueueProperty_IsRunning
            err = AudioQueueAddPropertyListener(m_outAQ, kAudioQueueProperty_IsRunning, audioQueueIsRunningCallback, this);
            if (err) {
                AQ_TRACE("%s: error in AudioQueueAddPropertyListener\n", __PRETTY_FUNCTION__);
                m_lastError = err;
                break;
            }
            
            break;
        }
    }
}
コード例 #13
0
/* This is called by audio file stream parser when it finds property values */
void Audio_Stream::propertyValueCallback(void *inClientData, AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags)
{
    AS_TRACE("%s\n", __PRETTY_FUNCTION__);
    Audio_Stream *THIS = static_cast<Audio_Stream*>(inClientData);
    
    if (!THIS->m_audioStreamParserRunning) {
        AS_TRACE("%s: stray callback detected!\n", __PRETTY_FUNCTION__);
        return;
    }
    
    switch (inPropertyID) {
        case kAudioFileStreamProperty_DataOffset: {
            SInt64 offset;
            UInt32 offsetSize = sizeof(offset);
            OSStatus result = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataOffset, &offsetSize, &offset);
            if (result == 0) {
                THIS->m_dataOffset = offset;
            } else {
                AS_TRACE("%s: reading kAudioFileStreamProperty_DataOffset property failed\n", __PRETTY_FUNCTION__);
            }
            
            break;
        }
        case kAudioFileStreamProperty_AudioDataByteCount: {
            UInt32 byteCountSize = sizeof(UInt64);
            OSStatus err = AudioFileStreamGetProperty(inAudioFileStream,
                                                      kAudioFileStreamProperty_AudioDataByteCount,
                                                      &byteCountSize, &THIS->m_audioDataByteCount);
            if (err) {
                THIS->m_audioDataByteCount = 0;
            }
            break;
        }
        case kAudioFileStreamProperty_ReadyToProducePackets: {
            memset(&(THIS->m_srcFormat), 0, sizeof m_srcFormat);
            UInt32 asbdSize = sizeof(m_srcFormat);
            OSStatus err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &(THIS->m_srcFormat));
            if (err) {
                AS_TRACE("Unable to set the src format\n");
                break;
            }
            
            THIS->m_packetDuration = THIS->m_srcFormat.mFramesPerPacket / THIS->m_srcFormat.mSampleRate;
            
            AS_TRACE("srcFormat, bytes per packet %i\n", (unsigned int)THIS->m_srcFormat.mBytesPerPacket);
            
            if (THIS->m_audioConverter) {
                AudioConverterDispose(THIS->m_audioConverter);
            }
            
            err = AudioConverterNew(&(THIS->m_srcFormat),
                                    &(THIS->m_dstFormat),
                                    &(THIS->m_audioConverter));
            
            if (err) {
                AS_TRACE("Error in creating an audio converter, error %i\n", err);
                
                THIS->m_initializationError = err;
            }
            
            THIS->setCookiesForStream(inAudioFileStream);
            
            THIS->audioQueue()->handlePropertyChange(inAudioFileStream, inPropertyID, ioFlags);
            break;
        }
        default: {
            THIS->audioQueue()->handlePropertyChange(inAudioFileStream, inPropertyID, ioFlags);
            break;
        }
    }
}
コード例 #14
0
ファイル: mac_audio.c プロジェクト: stevestreza/pianobar
void StreamPropertyListenerProc(void * inClientData,
                                AudioFileStreamID inAudioFileStream,
                                AudioFileStreamPropertyID inPropertyID,
                                UInt32 * ioFlags)
{
    // this is called by audio file stream when it finds property values
    struct audioPlayer* player = (struct audioPlayer*)inClientData;
    OSStatus err = noErr;

//    printf("found property '%c%c%c%c'\n", (inPropertyID>>24)&255, (inPropertyID>>16)&255, (inPropertyID>>8)&255, inPropertyID&255);

    switch (inPropertyID) {
    case kAudioFileStreamProperty_ReadyToProducePackets :
    {
        // the file stream parser is now ready to produce audio packets.
        // get the stream format.
        AudioStreamBasicDescription asbd;
        UInt32 asbdSize = sizeof(asbd);
        err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
        if (err) {
            PRINTERROR("get kAudioFileStreamProperty_DataFormat");
            player->failed = true;
            break;
        }

        //TODO: Is this really right!?!
        player->songDuration = player->waith.contentLength * 2000 / asbd.mSampleRate;
        player->samplerate = asbd.mSampleRate;

        player->packetDuration = asbd.mFramesPerPacket / asbd.mSampleRate;

        // create the audio queue
        err = AudioQueueNewOutput(&asbd, PianobarAudioQueueOutputCallback, player, NULL, NULL, 0, &player->audioQueue);
        if (err) {
            PRINTERROR("AudioQueueNewOutput");
            player->failed = true;
            break;
        }

        // allocate audio queue buffers
        for (unsigned int i = 0; i < kNumAQBufs; ++i) {
            err = AudioQueueAllocateBuffer(player->audioQueue, kAQBufSize, &player->audioQueueBuffer[i]);
            if (err) {
                PRINTERROR("AudioQueueAllocateBuffer");
                player->failed = true;
                break;
            }
        }


        // get the cookie size
        UInt32 cookieSize;
        Boolean writable;
        err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable);
        if (err) {
            PRINTERROR("info kAudioFileStreamProperty_MagicCookieData");
            break;
        }

        // get the cookie data
        void* cookieData = calloc(1, cookieSize);
        err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData);
        if (err) {
            PRINTERROR("get kAudioFileStreamProperty_MagicCookieData");
            free(cookieData);
            break;
        }

        // set the cookie on the queue.
        err = AudioQueueSetProperty(player->audioQueue, kAudioQueueProperty_MagicCookie, cookieData, cookieSize);
        free(cookieData);
        if (err) {
            PRINTERROR("set kAudioQueueProperty_MagicCookie");
            break;
        }

        // listen for kAudioQueueProperty_IsRunning
        err = AudioQueueAddPropertyListener(player->audioQueue, kAudioQueueProperty_IsRunning, AudioQueueIsRunningCallback, player);
        if (err) {
            PRINTERROR("AudioQueueAddPropertyListener");
            player->failed = true;
            break;
        }

        break;
    }
    }
}