Проблемы с библиотекой WinMM
Вопрос
Я написал библиотеку-оболочку 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.