0

生のオーディオ ストリームを録音および再生するために、WaveOut クラスと WaveIn クラスを公開する WinMM ライブラリ ラッパー ライブラリを作成しました。

すべてがうまく機能しますが、完成したバッファの処理方法に関するオペレーティング システムの仕様に従うために、バッファの準備を解除してメモリを解放するスレッドを追加しました。クラスが安定してスレッドセーフになるように、すべての同期も停止しました。

ただし、WaveOut デバイスにバッファを追加すると、オペレーティング システムが成功コードを返すというまれな問題があるようですが、直後にデバイスをリセットすると、OS はバッファを終了としてマークせず、応用。

バッファを失っているようです。したがって、問題は、デバイスに送信された個々のバッファーの数を追跡し、それらをクリーンアップするスレッドに Close() 関数を結合することをブロックしていることです。

アイデアや既知のバグはありますか?

PS: これは Vista のクアッド コアでは発生しないようですが、XP プロのデュアル コアでは発生します。

EDIT1: ソースコードをアップロードし、codeplex で適切にライセンスを取得したら、完全なソースコードを公開しても構わないと思っています。

EDIT2: ライブラリを CodePlex に投稿: http://winmm.codeplex.com/

問題の原因は次のとおりです。

public partial class MainView : Form
{
    private WaveIn waveIn = new WaveIn(WaveIn.WaveInMapperDeviceId);
    private WaveOut waveOut = new WaveOut(WaveOut.WaveOutMapperDeviceId);

    public MainView()
    {
        InitializeComponent();

        WaveFormat format = WaveFormat.Pcm44Khz16BitMono;

        waveOut.Open(format);

        waveIn.DataReady += new EventHandler<DataReadyEventArgs>(WaveIn_DataReady);

        // Tweaking these values affects the internal buffering thread.
        // Setting too small of a QueueSize with too small of a BufferSize
        //  will cause buffer underruns, which will sound like choppy audio.
        waveIn.BufferQueueSize = 200;
        waveIn.BufferSize = 64;

        waveIn.Open(format);

        waveIn.Start();
    }

    void WaveIn_DataReady(object sender, DataReadyEventArgs e)
    {
        if (waveOut != null)
        {
            lock (waveOut)
            {
                // We have to check for null after the lock,
                //  because waveOut may have been disposed
                //  inside another lock.
                if (waveOut != null)
                {
                    waveOut.Write(e.Data);
                }
            }
        }
    }

    private void MainView_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (waveIn != null)
        {
            lock (waveIn)
            {
                waveIn.Dispose();
                waveIn = null;
            }
        }

        if (waveOut != null)
        {
            lock (waveOut)
            {
                waveOut.Dispose();
                waveOut = null;
            }
        }
    }
}
4

1 に答える 1

1

object最初に、ロックするための別のを作成します。これにより、ヌルチェックロジックの多くが簡素化されます(ロックの前後をチェックするため、約半分になります)。

次に、Dispose変数をnullに設定しません。オブジェクトがnullではなく、破棄されるだけなので、他のチェックは引き続き通過します。だから私はします

waveOut.Dispose();
waveout = null;

明示的にnullに設定されていることを確認します。

于 2009-04-23T19:17:28.620 に答える