Pergunta

Eu escrevi uma biblioteca WinMM wrapper de bibliotecas que expõe as classes WaveOut e WaveIn com a finalidade de gravar e reproduzir fluxos de áudio crus.

Tudo funciona muito bem, mas, a fim de seguir as especificações do sistema operacional sobre como lidar com os buffers acabados, eu adicionei um segmento que unprepares os buffers e libera a memória. Eu também tenho todo o baixo sincronização, para que as classes são sólidos e thread-safe.

No entanto, não parece ser um problema raro onde eu adicionar um buffer para o dispositivo WaveOut eo sistema operacional retorna um código de sucesso, mas se o dispositivo é reposto imediatamente afterwords, o sistema operacional não marcar o buffer como acabado e retorno -lo para a aplicação.

Parece que ele está perdendo os buffers. Então, o problema é que eu estou mantendo o controle da contagem de buffers individuais enviados para o dispositivo e bloquear a adesão à função Close () para o segmento que limpa-los.

Qualquer idéias ou conhecidos bugs?

PS:. Isso não parece acontecer em um quad core no Vista, mas não acontecer no meu Dual Core no XP pro

EDIT1:. Estou totalmente disposto a expor o código fonte completo, uma vez que recebo-lo carregado e propery licenciado no CodePlex, se isso iria ajudar alguém

EDIT2: biblioteca publicado para CodePlex: http://winmm.codeplex.com/

Aqui está uma idéia do que está causando o problema:

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;
            }
        }
    }
}
Foi útil?

Solução

Gostaria em primeiro lugar criar um object separado no qual para bloquear. Que deve simplificar um monte de sua lógica de verificação nula (por cerca de metade desde que você verifique antes e depois do bloqueio).

Em segundo lugar, Dispose não irá definir sua variável de null, para que seus outros cheques ainda vai passar por porque o objeto não é nulo, única descartado. Então eu faria

waveOut.Dispose();
waveout = null;

para se certificar de que ele é explicitamente definido como nulo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top