ios - 使用AudioQueue播放不稳定的音频

标签 ios objective-c audio core-audio audioqueue

我有以下代码,它将打开一个AudioQueue以便在44,100hz上播放16位pcm。它有一个很奇怪的怪癖,一旦初始缓冲区被填满,它就会真正快速地播放,然后在等待更多字节通过网络时变得“不稳定”。

因此,要么是我搞乱了将一部分数据复制到缓冲区的代码,要么是我告诉AudioQueue播放速度比数据通过网络传输的速度快。

有人有什么想法吗?我已经被困了几天了。

//
// Created by Benjamin St Pierre on 15-01-02.
// Copyright (c) 2015 Lightning Strike Solutions. All rights reserved.
//

#import <MacTypes.h>
#import "MediaPlayer.h"


@implementation MediaPlayer


@synthesize sampleQueue;


void OutputBufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
    //Cast userData to MediaPlayer Objective-C class instance
    MediaPlayer *mediaPlayer = (__bridge MediaPlayer *) inUserData;
    // Fill buffer.
    [mediaPlayer fillAudioBuffer:inBuffer];
    // Re-enqueue buffer.
    OSStatus err = AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
    if (err != noErr)
        NSLog(@"AudioQueueEnqueueBuffer() error %d", (int) err);
}

- (void)fillAudioBuffer:(AudioQueueBufferRef)inBuffer {
    if (self.currentAudioPiece == nil || self.currentAudioPiece.duration >= self.currentAudioPieceIndex) {
        //grab latest sample from sample queue
        self.currentAudioPiece = sampleQueue.dequeue;
        self.currentAudioPieceIndex = 0;
    }

    //Check for empty sample queue
    if (self.currentAudioPiece == nil) {
        NSLog(@"Empty sample queue");
        memset(inBuffer->mAudioData, 0, kBufferByteSize);
        return;
    }

    UInt32 bytesToRead = inBuffer->mAudioDataBytesCapacity;

    while (bytesToRead > 0) {
        UInt32 maxBytesFromCurrentPiece = self.currentAudioPiece.audioData.length - self.currentAudioPieceIndex;
        //Take the min of what the current piece can provide OR what is needed to be read
        UInt32 bytesToReadNow = MIN(maxBytesFromCurrentPiece, bytesToRead);

        NSData *subRange = [self.currentAudioPiece.audioData subdataWithRange:NSMakeRange(self.currentAudioPieceIndex, bytesToReadNow)];
        //Copy what you can before continuing loop
        memcpy(inBuffer->mAudioData, subRange.bytes, subRange.length);
        bytesToRead -= bytesToReadNow;

        if (bytesToReadNow == maxBytesFromCurrentPiece) {
            @synchronized (sampleQueue) {
                self.currentAudioPiece = self.sampleQueue.dequeue;
                self.currentAudioPieceIndex = 0;
            }
        } else {
            self.currentAudioPieceIndex += bytesToReadNow;
        }
    }
    inBuffer->mAudioDataByteSize = kBufferByteSize;
}

- (void)startMediaPlayer {
    AudioStreamBasicDescription streamFormat;
    streamFormat.mFormatID = kAudioFormatLinearPCM;
    streamFormat.mSampleRate = 44100.0;
    streamFormat.mChannelsPerFrame = 2;
    streamFormat.mBytesPerFrame = 4;
    streamFormat.mFramesPerPacket = 1;
    streamFormat.mBytesPerPacket = 4;
    streamFormat.mBitsPerChannel = 16;
    streamFormat.mReserved = 0;
    streamFormat.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;

    // New input queue
    OSStatus err = AudioQueueNewOutput(&streamFormat, OutputBufferCallback, (__bridge void *) self, nil, nil, 0, &outputQueue);
    if (err != noErr) {
        NSLog(@"AudioQueueNewOutput() error: %d", (int) err);
    }

    int i;
    // Enqueue buffers
    AudioQueueBufferRef buffer;
    for (i = 0; i < kNumberBuffers; i++) {
        err = AudioQueueAllocateBuffer(outputQueue, kBufferByteSize, &buffer);
        memset(buffer->mAudioData, 0, kBufferByteSize);
        buffer->mAudioDataByteSize = kBufferByteSize;
        if (err == noErr) {
            err = AudioQueueEnqueueBuffer(outputQueue, buffer, 0, nil);
            if (err != noErr) NSLog(@"AudioQueueEnqueueBuffer() error: %d", (int) err);
        } else {
            NSLog(@"AudioQueueAllocateBuffer() error: %d", (int) err);
            return;
        }
    }

    // Start queue
    err = AudioQueueStart(outputQueue, nil);
    if (err != noErr) NSLog(@"AudioQueueStart() error: %d", (int) err);
}

@end

最佳答案

我要在这里大张旗鼓地说,您正在播放断断续续的播放,因为您没有为数据推进写指针。我对objective-C的了解不够,无法告诉您此语法是否正确,但是我认为您需要添加以下内容:

while (bytesToRead > 0) {
    ....
    memcpy(inBuffer->mAudioData, subRange.bytes, subRange.length);
    bytesToRead -= bytesToReadNow;
    inBuffer->mAudioData += bytesReadNow; // move the write pointer
    ...
}

关于ios - 使用AudioQueue播放不稳定的音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27830872/

相关文章:

ios - WKWebView 是否使用来自 Safari 的 cookie?

haskell - 使用 Gloss 运行模拟,同时使用 SDL 播放声音

java - 搜索由音频识别生成的数组列表

ios - Xcode 5 框架/库搜索路径绝对地址

ios - 从 Web 服务器更新 App Store 应用程序

javascript - iOS - 手动关注输入/文本区域的解决方法

iphone - 刷新 UITableView

ios - 我的应用程序在 uikit 中崩溃,仅发生在 iPhone X 及以上异常名称 NSInternalInconsistencyException

iphone - 如何在 iOS 6 中获取 Facebook 好友?

iPhone SpeakHere 1 个 channel 上的示例录音