簡體   English   中英

使用AudioQueue播放AAC,但回調功能不起作用

[英]Use AudioQueue to play AAC, but the callback function doesn't work

最近,我的項目希望通過AAC實現音頻通信,因此我使用AudioQueue,但是存在播放器的回調函數不起作用的問題,在我的項目中,回調函數已經起作用了3次。 這是for函數工作3次。 當激活AudioQueueStart(mQueue, NULL) ,永遠不會調用回調函數。

我使用兩個iPhone來運行。 它們是通過udp套接字連接的,我確定這部分還可以。 我可以獲得正確的音頻數據。

我修改了一個演示,它播放文件數據而不是內存。 所以我不知道這是一個問題嗎?

這是我的代碼: AQPlayer.h

#include <AudioToolbox/AudioToolbox.h>

#include "CAStreamBasicDescription.h"
#include "CAXException.h"

#define kNumberBuffers 3
#define kBufferDurationSeconds 0.5

class AQPlayer
{
public:
    AQPlayer();
    ~AQPlayer();

    OSStatus                        StartQueue(BOOL inResume);
    OSStatus                        StopQueue();
    OSStatus                        PauseQueue();

    AudioQueueRef                   Queue()                 { return mQueue; }
    CAStreamBasicDescription        DataFormat() const      { return mDataFormat; }
    Boolean                         IsRunning() const       { return (mIsRunning) ? true : false; }
    Boolean                         IsInitialized() const   { return mIsInitialized; }
    CFStringRef                     GetFilePath() const     { return (mFilePath) ? mFilePath : CFSTR(""); }
    Boolean                         IsLooping() const       { return mIsLooping; }

    void SetLooping(Boolean inIsLooping)    { mIsLooping = inIsLooping; }
    void CreateQueueForFile(CFStringRef inFilePath);
    void DisposeQueue(Boolean inDisposeFile);
    void prepareAudioQueue();
    void start();
    void stop();

private:
    UInt32                          GetNumPacketsToRead()               { return mNumPacketsToRead; }
    SInt64                          GetCurrentPacket()                  { return mCurrentPacket; }
    AudioFileID                     GetAudioFileID()                    { return mAudioFile; }
    void                            SetCurrentPacket(SInt64 inPacket)   { mCurrentPacket = inPacket; }

    void                            SetupNewQueue();

    AudioQueueRef                   mQueue;
    AudioQueueBufferRef             mBuffers[kNumberBuffers];
    AudioFileID                     mAudioFile;
    CFStringRef                     mFilePath;
    CAStreamBasicDescription        mDataFormat;

    Boolean                         mIsInitialized;
    UInt32                          mNumPacketsToRead;
    SInt64                          mCurrentPacket;
    UInt32                          mIsRunning;
    Boolean                         mIsDone;
    Boolean                         mIsLooping;

    static void isRunningProc(      void *              inUserData,
                              AudioQueueRef           inAQ,
                              AudioQueuePropertyID    inID);

    static void AQBufferCallback(   void *                  inUserData,
                                 AudioQueueRef          inAQ,
                                 AudioQueueBufferRef        inCompleteAQBuffer);

    void CalculateBytesForTime(     CAStreamBasicDescription & inDesc,
                               UInt32 inMaxPacketSize, 
                               Float64 inSeconds, 
                               UInt32 *outBufferSize, 
                               UInt32 *outNumPackets);

};

這是AQPlayer.mm

#include "package.h"
#include "udpsocket.h"
#define MAXPACKETSIZE 1000
#define BUFFER_SIZE 4000

#include "AQPlayer.h"


extern udpsocket *udp;

void AQPlayer::AQBufferCallback(void *                  inUserData,
                                AudioQueueRef           inAQ,
                                AudioQueueBufferRef     inCompleteAQBuffer) 
{

    AQPlayer *THIS = (AQPlayer *)inUserData;

    dispatch_semaphore_wait(udp->sempahore,DISPATCH_TIME_FOREVER);
    NSLog(@"read begin");

    while ([udp->AudioQueue count]>0 &&
        ![[udp->AudioQueue objectAtIndex:0] isKindOfClass:[AUDIO_CACHE_OBJECT class]])
    {
        [udp->AudioQueue removeObjectAtIndex:0];
    }
    if([udp->AudioQueue count]<1){
        [NSThread sleepForTimeInterval:0.05];
        AQBufferCallback(inUserData, inAQ, inCompleteAQBuffer);
        return;
    }
    int packets = 0;
    int dataLen = 0;
    AUDIO_CACHE_OBJECT *pack;

    char *data = (char*)malloc(sizeof(char)*BUFFER_SIZE);;
    memset(data, 0, BUFFER_SIZE);
    pack = [udp->AudioQueue firstObject];

    while (dataLen+pack.datalen<BUFFER_SIZE && [udp->AudioQueue count]>0 /*&& packets<21*/) {
        memcpy(data+dataLen, [pack GetData], [pack datalen]);
        dataLen+=[pack datalen];
        [udp->AudioQueue removeObjectAtIndex:0];
        //            [pack memset];
        packets ++;

        while ([udp->AudioQueue count]>1 &&
               ![[udp->AudioQueue objectAtIndex:0] isKindOfClass:[AUDIO_CACHE_OBJECT class]])
        {
            [udp->AudioQueue removeObjectAtIndex:0];
        }
        if([udp->AudioQueue count]<1){
            break;
        }
        pack = [udp->AudioQueue firstObject];

    }

    memcpy(inCompleteAQBuffer->mAudioData, data, dataLen);

    inCompleteAQBuffer->mAudioDataByteSize = dataLen;
    inCompleteAQBuffer->mPacketDescriptionCount = packets;
    AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, 0,NULL);
    THIS->mCurrentPacket += packets;
    free(data);
    NSLog(@"read end --- %lld",THIS->mCurrentPacket);

}

void AQPlayer::isRunningProc (  void *              inUserData,
                              AudioQueueRef           inAQ,
                              AudioQueuePropertyID    inID)
{
    AQPlayer *THIS = (AQPlayer *)inUserData;
    UInt32 size = sizeof(THIS->mIsRunning);
    OSStatus result = AudioQueueGetProperty (inAQ, kAudioQueueProperty_IsRunning, &THIS->mIsRunning, &size);

    if ((result == noErr) && (!THIS->mIsRunning))
        [[NSNotificationCenter defaultCenter] postNotificationName: @"playbackQueueStopped" object: nil];
}

void AQPlayer::CalculateBytesForTime (CAStreamBasicDescription & inDesc, UInt32 inMaxPacketSize, Float64 inSeconds, UInt32 *outBufferSize, UInt32 *outNumPackets)
{
    // we only use time here as a guideline
    // we're really trying to get somewhere between 16K and 64K buffers, but not allocate too much if we don't need it
    static const int maxBufferSize = 0x10000; // limit size to 64K
    static const int minBufferSize = 0x4000; // limit size to 16K

    if (inDesc.mFramesPerPacket) {
        Float64 numPacketsForTime = inDesc.mSampleRate / inDesc.mFramesPerPacket * inSeconds;
        *outBufferSize = numPacketsForTime * inMaxPacketSize;
    } else {
        // if frames per packet is zero, then the codec has no predictable packet == time
        // so we can't tailor this (we don't know how many Packets represent a time period
        // we'll just return a default buffer size
        *outBufferSize = maxBufferSize > inMaxPacketSize ? maxBufferSize : inMaxPacketSize;
    }

    // we're going to limit our size to our default
    if (*outBufferSize > maxBufferSize && *outBufferSize > inMaxPacketSize)
        *outBufferSize = maxBufferSize;
    else {
        // also make sure we're not too small - we don't want to go the disk for too small chunks
        if (*outBufferSize < minBufferSize)
            *outBufferSize = minBufferSize;
    }
    *outNumPackets = *outBufferSize / inMaxPacketSize;
}

AQPlayer::AQPlayer() :
mQueue(0),
mAudioFile(0),
mFilePath(NULL),
mIsRunning(false),
mIsInitialized(false),
mNumPacketsToRead(0),
mCurrentPacket(0),
mIsDone(false),
mIsLooping(false) { }

AQPlayer::~AQPlayer()
{
    DisposeQueue(true);
}





OSStatus AQPlayer::StartQueue(BOOL inResume)
{
    if (mQueue == NULL)
        CreateQueueForFile(mFilePath);

    mIsDone = false;
    if (!inResume)
        mCurrentPacket = 0;

    for (int i = 0; i < kNumberBuffers; ++i) {
        AQBufferCallback (this, mQueue, mBuffers[i]);
    }
    NSLog(@"audioqueuestart");
    UInt32 i =0;
    AudioQueuePrime(mQueue, 0, &i);
    NSLog(@"%d",(unsigned int)i);
    return AudioQueueStart(mQueue, NULL);
}

OSStatus AQPlayer::StopQueue()
{
    OSStatus result = AudioQueueStop(mQueue, true);
    if (result) printf("ERROR STOPPING QUEUE!\n");

    return result;
}

OSStatus AQPlayer::PauseQueue()
{
    OSStatus result = AudioQueuePause(mQueue);

    return result;
}

void AQPlayer::CreateQueueForFile(CFStringRef inFilePath)
{

    try {

            UInt32 size = sizeof(mDataFormat);

            mDataFormat.mSampleRate         =  44100;
            mDataFormat.mFormatID           =  kAudioFormatMPEG4AAC;
            mDataFormat.mFormatFlags        =  0;
            mDataFormat.mFramesPerPacket    =  1024;
            mDataFormat.mChannelsPerFrame   =  2;
            mDataFormat.mBitsPerChannel     =  0;//表示這是一個壓縮格式
            mDataFormat.mBytesPerPacket     =  0;//表示這是一個變比特率壓縮
            mDataFormat.mBytesPerFrame      =  0;
            mDataFormat.mReserved           =  0;
            //aqc.bufferByteSize                  =  2000;

        SetupNewQueue();
    }
    catch (NSException *e) {

        fprintf(stderr, "Error: %@ (%@)\n", [e debugDescription], [e description]);
    }
}

void AQPlayer::SetupNewQueue()
{
    AudioQueueNewOutput(&mDataFormat, AQPlayer::AQBufferCallback, this,//NULL,NULL,0,&mQueue);
                                      CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue);
    UInt32 bufferByteSize;
    UInt32 maxPacketSize = MAXPACKETSIZE;
    UInt32 size = sizeof(maxPacketSize);
    CalculateBytesForTime (mDataFormat, maxPacketSize, kBufferDurationSeconds, &bufferByteSize, &mNumPacketsToRead);

    size = sizeof(UInt32);


   AudioQueueAddPropertyListener(mQueue, kAudioQueueProperty_IsRunning, isRunningProc, this);

    bool isFormatVBR = (mDataFormat.mBytesPerPacket == 0 || mDataFormat.mFramesPerPacket == 0);
    AudioQueueSetParameter(mQueue, kAudioQueueParam_Volume, 1.0);


    for (int i = 0; i < kNumberBuffers; ++i) {
        AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]);
    }

    // set the volume of the queue
    mIsInitialized = true;
}
void AQPlayer::DisposeQueue(Boolean inDisposeFile)
{
    if (mQueue)
    {
        AudioQueueDispose(mQueue, true);
        mQueue = NULL;
    }
    if (inDisposeFile)
    {
        if (mAudioFile)
        {
            AudioFileClose(mAudioFile);
            mAudioFile = 0;
        }
        if (mFilePath)
        {
            CFRelease(mFilePath);
            mFilePath = NULL;
        }
    }
    mIsInitialized = false;
}

謝謝您的時間。

您的輸入是VBR,因此您的緩沖區需要一個附帶的數據包描述數組。 最初創建緩沖區時,請使用AudioQueueAllocateBufferWithPacketDescriptions:而不是AudioQueueAllocateBuffer: 然后為回調過程中的while循環內的每個數據包設置mStartOffsetmDataByteSizemVariableFramesInPacket (始終為零)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM