如何同步两个 Xaudio2 流媒体源语音



我正在使用SharpDX Samples(https://github.com/sharpdx/SharpDX-Samples/blob/master/WindowsDesktop/XAudio2/AudioPlayerApp/AudioPlayer.cs(中的流原理同时播放多个声音。

我有一个包含同一首歌曲多个版本的列表。我想在同一时间启动它们。我为每首歌曲启动一个新任务,并使用 CountDownEvent 和 ManualResetEvent 的组合来确保它们同时启动:

在任务中,我准备缓冲区并向 CountDownEvent 发出信号,表明歌曲已准备好播放。然后,歌曲等待来自手动重置事件的信号。当 CountDownEvent 有来自每首歌曲的信号准备就绪时,它会发出 ManualResetEvent 和 SubmitSourceBuffer 被调用的信号。

10 次歌曲中有 9 次开始采样同步(歌曲之间没有可检测到的相位,只是声音更大(,但有时有一首略有偏差。

以下是一些需要详细说明的代码:

            Task playingtask = Task.Factory.StartNew(() =>
        {
            int nextbuffer = 0;
            long zeroticks = MasterClock.Elapsed.Ticks;
            try
            {
                while (true) 
                {
                    if (oursong.ADecoder == null || oursong.Status == PlaybackStatus.Stop) { break; }
                    var sampleiterator = oursong.ADecoder.GetSamples(TimeSpan.FromTicks(oursong.Position)).GetEnumerator();
                    while (true) 
                    {
                        if (oursong.ADecoder == null || oursong.Status == PlaybackStatus.Stop) { break; }
                        foreach (SourceVoice SVoice in oursong.SVoices)
                        {
                            while (SVoice.State.BuffersQueued == oursong.BufferRing.Length && oursong.ADecoder != null)
                            {
                                BufferEndEvent.WaitOne(1);
                            }
                        }
                        if (!sampleiterator.MoveNext())
                        {
                            break;
                        }
                        var bufferpointer = sampleiterator.Current;
                        if (bufferpointer.Size > oursong.MBufferRing[nextbuffer].Size)
                        {
                            if (oursong.MBufferRing[nextbuffer].Pointer != IntPtr.Zero)
                            {
                                SharpDX.Utilities.FreeMemory(oursong.MBufferRing[nextbuffer].Pointer);
                            }
                            oursong.MBufferRing[nextbuffer].Pointer = SharpDX.Utilities.AllocateMemory(bufferpointer.Size);
                            oursong.MBufferRing[nextbuffer].Size = bufferpointer.Size;
                        }

                        SharpDX.Utilities.CopyMemory(oursong.MBufferRing[nextbuffer].Pointer, bufferpointer.Pointer, bufferpointer.Size);
                        oursong.BufferRing[nextbuffer].AudioDataPointer = oursong.MBufferRing[nextbuffer].Pointer;
                        oursong.BufferRing[nextbuffer].AudioBytes = bufferpointer.Size;
                        if (oursong.Status == PlaybackStatus.Ready)
                        {
                            CountDownEvent.Signal();
                            SongManualResetEvent.WaitOne();
                            oursong.Status = PlaybackStatus.Start;
                        }
                        foreach (SourceVoice SVoice in oursong.SVoices)
                        {
                            SVoice.SubmitSourceBuffer(oursong.BufferRing[nextbuffer], null);
                        }
                        oursong.Position += MasterClock.Elapsed.Ticks - zeroticks;
                        zeroticks = MasterClock.Elapsed.Ticks;
                        nextbuffer = ++nextbuffer % oursong.BufferRing.Length;
                    }
                }
            }
            finally
            {
                DisposeAudio(oursong);
                oursong.Position = oursong.Start;
            }
        }, TaskCreationOptions.LongRunning);

旁注:我将每首歌曲的缓冲区发送到多个音频设备,使用 foreach 语句以相同的顺序将每首歌曲发送到多个音频设备。Ready 状态是使用预设内存、音频解码器等的加载方法预先设置的。

我知道可以使用操作集同时启动源语音,但是有没有另一种方法(使用时钟或其他同步方法(来确保为每首播放的歌曲同时发送样本?

您应该能够使用 XAudio2 操作集直接实现此目的,而无需使用外部自定义同步事件对其进行解决方法。

最新更新