实时复制缓冲区数据

时间:2018-08-21 18:11:08

标签: c# multithreading unity3d audio buffer

我正在尝试将传入的麦克风音频从Unity实时发送到Wwise。 我有一个“生产者线程”和一个“消费者线程”。我正在尝试将传入缓冲区从生产者复制到消费者。

// Unity callback on microphone input (“producer thread“)
void OnAudioFilterRead(float[] data, int channels)
{
    // acquire ownership of mutex and buffer
    mutex.WaitOne();

    // copy samples to buffer (de–interleave channels)
    for (int i = 0; i < data.Length / channels; i++)
    {
        buffer.Add(data[i * channels]);
    }


    // release ownership of mutex and buffer
    mutex.ReleaseMutex();
}

// Wwise callback that sends buffered samples to Wwise (“consumer thread“)
bool AudioSamplesDelegate(uint playingID, uint channelIndex, float[] samples)
{
    // acquire ownership of mutex and buffer
    mutex.WaitOne();

    // copy samples from buffer to temporary block
    int blockSize = Math.Min(buffer.Count, samples.Length);
    List<float> block = buffer.GetRange(0, blockSize);
    buffer.RemoveRange(0, blockSize);

    // release ownership of mutex and buffer (release mutex as quickly as possible)
    mutex.ReleaseMutex();

    // copy samples from temporary block to output array
    block.CopyTo(samples);

    // Return false to indicate that there is no more data to provide. This will also stop the associated event.
    return IsPlaying;
}

这可以工作,但是我从Wwise那里获得的音频出现了毛刺。是否有关于最佳方法做到这一点/改善这一点的意见?循环缓冲区是否可行?

1 个答案:

答案 0 :(得分:1)

我认为使用多个缓冲区而不是大缓冲区来减少同步时间将很有帮助。

// Create a thread-safed queue
Queue bufferQueue = Queue.Synchronized(new Queue());
List<float> remains;

// Unity callback on microphone input (“producer thread“)
void OnAudioFilterRead(float[] data, int channels)
{
    var buffer = new List<folat>(data.Length);  

    // copy samples to buffer (de–interleave channels)
    for (int i = 0; i < data.Length / channels; i++)
    {
        buffer.Add(data[i * channels]);
    }

    // Add buffer to the queue
    bufferQueue.Enqueue(buffer);
}

// Wwise callback that sends buffered samples to Wwise (“consumer thread“)
bool AudioSamplesDelegate(uint playingID, uint channelIndex, float[] samples)
{
    // Fill samples 
    var requiredLength = samples.Length;
    while (requiredLength > 0)
    {
        if (remains == null)
            if (bufferQueue.Count > 0)
                remains = bufferQueue.Dequeue();
            else
                break;

        if (remains.Length > requiredLength)
        {
            remains.CopyTo(0, samples, samples.Length - requiredLength, requiredLength);
            remains.RemoveRange(0, requiredLength);
            break;
        }

        remains.CopyTo(0, samples, samples.Length - requiredLength, remains.Length);
        requiredLength -= remains.Length;
        remains = null;
    }

    // Return false to indicate that there is no more data to provide. This will also stop the associated event.
    return IsPlaying;
}