Вопрос

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

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

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

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

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

ПС:Кажется, этого НЕ происходит на четырехъядерном процессоре в Vista, но происходит на моем двухъядерном процессоре в 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;
            }
        }
    }
}
Это было полезно?

Решение

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

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

waveOut.Dispose();
waveout = null;

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top