Проблемы с библиотекой WinMM - PullRequest
0 голосов
/ 02 апреля 2009

Я написал библиотеку-оболочку библиотеки WinMM, которая предоставляет классы WaveOut и WaveIn для записи и воспроизведения необработанных аудиопотоков.

Все отлично работает, но для того, чтобы следовать спецификациям операционной системы о том, как обрабатывать готовые буферы, я добавил поток, который освобождает буферы и освобождает память. Я также отключил всю синхронизацию, чтобы классы были надежными и потокобезопасными.

Однако, кажется, есть редкая проблема, когда я добавляю буфер на устройство WaveOut, и операционная система возвращает код успеха, но если устройство сразу после слов сбрасывается, ОС не помечает буфер как завершенный и возвращает это к заявке.

Кажется, что он теряет буферы. Итак, проблема в том, что я отслеживаю количество отдельных буферов, отправляемых на устройство, и блокирую присоединение функции Close () к потоку, который их очищает.

Есть идеи или известные ошибки?

PS: Похоже, что это не происходит на Quad Core в Vista, но происходит на моем Dual Core в XP pro.

РЕДАКТИРОВАТЬ1: Я полностью готов предоставить полный исходный код, как только я загружу его и лицензирую надлежащим образом на codeplex, если это кому-нибудь поможет. РЕДАКТИРОВАТЬ 2: Размещенная библиотека для 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;
            }
        }
    }
}

1 Ответ

1 голос
/ 23 апреля 2009

Я бы сначала создал отдельный object для блокировки. Это должно значительно упростить вашу логику проверки нуля (примерно вдвое, поскольку вы проверяете до и после блокировки).

Во-вторых, Dispose не установит для вашей переменной значение null, поэтому другие ваши проверки по-прежнему будут проходить, потому что объект не нулевой, а только удален. Так что я бы сделал

waveOut.Dispose();
waveout = null;

чтобы убедиться, что для него явно установлено значение null.

...