Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/97.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在iOS上使用音频队列播放音频一段时间后,声音静音_Ios_Audioqueue - Fatal编程技术网

在iOS上使用音频队列播放音频一段时间后,声音静音

在iOS上使用音频队列播放音频一段时间后,声音静音,ios,audioqueue,Ios,Audioqueue,我正在iOS上编写一个实时音频播放程序 它从对等方接收音频RTP包,并将其放入音频队列中播放 开始播放时,声音正常。但在1或2分钟后,声音静音,并且AudioQueue API没有报告任何错误。回调函数继续正常调用,没有异常 但它只是沉默了 我的回调函数: 1:循环,直到有足够的数据可以复制到音频队列缓冲区 do { read_bytes_enabled = g_audio_playback_buf.GetReadByteLen(); if (read_bytes_enable

我正在iOS上编写一个实时音频播放程序

它从对等方接收音频RTP包,并将其放入音频队列中播放

开始播放时,声音正常。但在1或2分钟后,声音静音,并且AudioQueue API没有报告任何错误。回调函数继续正常调用,没有异常

但它只是沉默了

我的回调函数:

1:循环,直到有足够的数据可以复制到音频队列缓冲区

do 
{
    read_bytes_enabled = g_audio_playback_buf.GetReadByteLen();
    if (read_bytes_enabled >= kAudioQueueBufferLength)
    {
        break;
    }
    usleep(10*1000);
}
while (true);
2:复制到AudioQueue缓冲区,并将其排队。此回调函数保持正常运行,没有错误

//copy to audio queue buffer
read_bytes = kAudioQueueBufferLength;

g_audio_playback_buf.Read((unsigned char *)inBuffer->mAudioData, read_bytes);

WriteLog(LOG_PHONE_DEBUG, "AudioQueueBuffer(Play): copy [%d] bytes to AudioQueue buffer! Total len = %d", read_bytes, read_bytes_enabled);

inBuffer->mAudioDataByteSize = read_bytes;

UInt32 nPackets = read_bytes / g_audio_periodsize; // mono

inBuffer->mPacketDescriptionCount = nPackets;

// re-enqueue this buffer
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);

问题已经解决了

关键的一点是,不能让音频队列缓冲区等待,必须不断地为其提供数据,否则它可能会被静音。如果没有足够的数据,请用空白数据填充

因此,应更改以下代码:

do 
{
    read_bytes_enabled = g_audio_playback_buf.GetReadByteLen();
    if (read_bytes_enabled >= kAudioQueueBufferLength)
{
    break;
}
    usleep(10*1000);
}
while (true);
改为:

read_bytes_enabled = g_audio_playback_buf.GetReadByteLen();
if (read_bytes_enabled < kAudioQueueBufferLength)
{
    memset(inBuffer->mAudioData, 0x00, kAudioQueueBufferLength);
}
else
{
    inBuffer->mAudioDataByteSize = kAudioQueueBufferLength;
}
...
read_bytes_enabled=g_audio_playback_buf.GetReadByteLen();
if(已启用读取字节mAudioData,0x00,kaudioquebufferlength);
}
其他的
{
inBuffer->mAudioDataByteSize=kAudioQueueBufferLength;
}
...

如果使用AudioQueuePause,可以让AudioQueue等待

在本例中,在Swift 5中,我使用了一个通用队列。当这个队列为空时,正如您所做的那样,我在callback和callaudioqueuepause中用空数据填充缓冲区。需要注意的是,在播放调用AudioQueuePause之前,所有AudioQueueBuffer都会使用AudioQueueBuffer发送到AudioQueueRef

创建userData类以将所需的所有内容发送到回调:

class UserData {
    let dataQueue = Queue<Data>()
    let semaphore = DispatchSemaphore(value: 1)
}
private var inQueue: AudioQueueRef!
private var userData = UserData()
生成所有缓冲区,不要直接将它们排队:调用回调函数:

for _ in 0...2 {
    var bufferRef: AudioQueueBufferRef!
    AudioQueueAllocateBuffer(inQueue, 320, &bufferRef)
    audioQueueOutputCallback(&userData, inQueue, bufferRef)
}
当您收到音频数据时,您可以调用一个方法,该方法将您的数据排队,并让它等待回调函数获取数据:

func audioReceived(_ audio: Data) {
    let dataQueue = userData.dataQueue
    let semaphore = userData.semaphore

    semaphore.wait()
    dataQueue.enqueue(audio)
    semaphore.signal()
    // Start AudioQueue every time, if it's already started this call do nothing
    AudioQueueStart(inQueue, nil)
}
最后,您可以实现如下回调函数:

private let audioQueueOutputCallback: AudioQueueOutputCallback = { (inUserData, inAQ, inBuffer) in
    // Get data from UnsageMutableRawPointer
    let userData: UserData = (inUserData!.bindMemory(to: UserData.self, capacity: 1).pointee)
    let queue = userData.dataQueue
    let semaphore = userData.semaphore
    // bind UnsafeMutableRawPointer to UnsafeMutablePointer<UInt8> for data copy
    let audioBuffer = inBuffer.pointee.mAudioData.bindMemory(to: UInt8.self, capacity: 320)

    if queue.isEmpty {
        print("Queue is empty: pause")
        AudioQueuePause(inAQ)
        audioBuffer.assign(repeating: 0, count: 320)
        inBuffer.pointee.mAudioDataByteSize = 320
    } else {
        semaphore.wait()
        if let data = queue.dequeue() {
            data.copyBytes(to: audioBuffer, count: data.count)
            inBuffer.pointee.mAudioDataByteSize = data.count
        } else {
            print("Error: queue is empty")
            semaphore.signal()
            return
        }
        semaphore.signal()
    }

    AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)
}
private let audioQueueOutputCallback:audioQueueOutputCallback={(inUserData、inAQ、inBuffer)在
//从UnsageMutableRawPointer获取数据
让userData:userData=(inUserData!.bindMemory(收件人:userData.self,容量:1).pointee)
让queue=userData.dataQueue
让信号量=userData.semaphore
//将UnsafeMutableRawPointer绑定到数据复制的UnsafeMutablePointer
让audioBuffer=inBuffer.pointee.mAudioData.bindMemory(to:UInt8.self,容量:320)
如果queue.isEmpty{
打印(“队列为空:暂停”)
音频队列暂停(inAQ)
audioBuffer.assign(重复:0,计数:320)
inBuffer.pointee.mAudioDataByteSize=320
}否则{
信号量。等待()
如果let data=queue.dequeue(){
data.copyBytes(to:audioBuffer,count:data.count)
inBuffer.pointee.mAudioDataByteSize=data.count
}否则{
打印(“错误:队列为空”)
信号量
返回
}
信号量
}
audioqueuenbuffer(inAQ、inBuffer、0、nil)
}
在我的例子中,我使用320字节的缓冲区来存储20ms的PCM数据,16位,8kHz,单声道。 这个解决方案更为复杂,但比CPU使用空音频数据的伪无限循环要好。苹果对贪婪的应用程序非常严厉;)


我希望这个解决方案能有所帮助。

@davin zhao,我也面临同样的问题,我的有时不工作,声音停止,有两个问题要问你,可能答案也会解决我的问题1)KaudioqueBufferLength的值是多少2)如果可能,你会分享这个代码的示例吗?非常感谢你的帮助
private let audioQueueOutputCallback: AudioQueueOutputCallback = { (inUserData, inAQ, inBuffer) in
    // Get data from UnsageMutableRawPointer
    let userData: UserData = (inUserData!.bindMemory(to: UserData.self, capacity: 1).pointee)
    let queue = userData.dataQueue
    let semaphore = userData.semaphore
    // bind UnsafeMutableRawPointer to UnsafeMutablePointer<UInt8> for data copy
    let audioBuffer = inBuffer.pointee.mAudioData.bindMemory(to: UInt8.self, capacity: 320)

    if queue.isEmpty {
        print("Queue is empty: pause")
        AudioQueuePause(inAQ)
        audioBuffer.assign(repeating: 0, count: 320)
        inBuffer.pointee.mAudioDataByteSize = 320
    } else {
        semaphore.wait()
        if let data = queue.dequeue() {
            data.copyBytes(to: audioBuffer, count: data.count)
            inBuffer.pointee.mAudioDataByteSize = data.count
        } else {
            print("Error: queue is empty")
            semaphore.signal()
            return
        }
        semaphore.signal()
    }

    AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)
}