2012-05-14 27 views
1

我目前正在iOS上开发一个应用程序,它通过TCP套接字读取IMA-ADPCM音频数据并将其转换为PCM,然后播放流。在这个阶段,我已经完成了从流中提取数据并且将其解码为PCM的类(或者我应该说是对推送作出反应)。我还设置了音频队列类并让它播放测试音。我需要帮助的地方是将数据传递到音频队列的最佳方式。Objective-C - 将流数据传递到音频队列

音频数据从ADPCM解码器输出为8Khz 16位LPCM,每个字节640个字节。 (它起源于160字节的ADPCM数据,但解压缩到640)。它作为uint_8t数组进入函数并传出一个NSData对象。该流是一个“推送”流,因此每次发送音频时都会创建/刷新对象。

-(NSData*)convertADPCM:(uint8_t[]) adpcmdata { 

课程的音频队列回调是去寻找在运行每个循环过程数据的拉动作用,在每个传递运行:

-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer { 

我一直工作在这几天之后,PCM的转换完全是要征税的,我头脑中有一些麻烦,是弥合两者之间数据的最佳方式。这不像我正在创建数据,那么我可以简单地将数据创建合并到fillbuffer例程中,而不是数据被推送。

我的确在uint16_t []中设置了一个0.5秒的循环缓冲区,但是我认为我已经把我的大脑磨损了,无法用一种简洁的方式从缓冲区中推拉,所以我最终与快速爆裂弹出。

我已经完成了大部分在Android上的项目,但是发现AudioTrack与Core-Audio Queues非常不同。

在这个阶段,我还会说我拿起Adamson和Avila的Learning Core Audio的副本,并发现这是一个非常好的资源,可以帮助任何想要揭开核心音频的人。

UPDATE: 这里是缓冲区管理代码:

-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer { 

    int frame = 0; 
    double frameCount = bufferSize/self.streamFormat.mBytesPerFrame; 
    // buffersize = framecount = 8000/2 = 4000 
    //  

    // incoming buffer uint16_t[] convAudio holds 64400 bytes (big I know - 100 x 644 bytes) 
    // playedHead is set by the function to say where in the buffer the 
    // next starting point should be 

    if (playHead > 99) { 
     playHead = 0; 
    } 

    // Playstep factors playhead to get starting position 
    int playStep = playHead * 644; 

    // filling the buffer 
    for (frame = 0; frame < frameCount; ++frame) 
     // framecount = 4000 
     { 
     // pointer to buffer 
     SInt16 *data = (SInt16*)buffer->mAudioData; 
     // load data from uint16_t[] convAudio array into frame 
     (data)[frame] = convAudio[(frame + playStep)]; 
    } 

    // set buffersize 
    buffer->mAudioDataByteSize = bufferSize; 

    // return no Error - Osstatus will return an error otherwise if there is one. (I think) 
    return noErr; 
} 

正如我所说,我的脑子是模糊的,当我写这一点,可能有一些昭然若揭我失踪。

上面的代码是由回调称为:

static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) 
{ 
    soundHandler *sHandler = (__bridge soundHandler*)inUserData; 

    CheckError([sHandler fillBuffer: inCompleteAQBuffer], 
       "can't refill buffer", 
       "buffer refilled"); 
    CheckError(AudioQueueEnqueueBuffer(inAQ, 
             inCompleteAQBuffer, 
             0, 
             NULL), 
       "Couldn't enqueue buffer (refill)", 
       "buffer enqued (refill)"); 

} 

对事物的convAudio阵列端我都甩它来记录和它得到填补,以循环方式填充,所以我知道至少该位正在工作。

+0

发布您的缓冲区管理代码,因为这似乎是你的问题。 – hotpaw2

+0

已添加缓冲区代码。 – DoctorDbx

回答

0

管理费率的难点在于如果不匹配,该怎么办。首先,尝试使用一个巨大的循环缓冲区(许多秒),并且在开始音频队列以从中拉出之前大部分时间填充它。然后监视缓冲区级别,以查看他有很大的速率匹配问题。