This project has moved and is read-only. For the latest updates, please go here.

I got NAudio.MmException: WaveStillPlaying calling waveOutWrite Exception , am I missing something?

Jul 12, 2011 at 12:32 PM
Edited Jul 12, 2011 at 3:36 PM

Hello,

I have an application which receives messages over the network. These messages can be:

  • concatenate wav files specified in the message, and play the result (announcement)
  • stop playing of the specified announcement.

This applicition sometimes (order of magnitude: 1 time per 1000 announcement) throws this Exception: NAudio.MmException: WaveStillPlaying calling waveOutWrite

Thank you in advance:

Ferenc

Details:

  • .NET 4.0
  • Windows PosReady 2009
  • Windows Forms application
  • WaveOut with WaveCallbackInfo.NewWindow()
  • After the Exception throwed the app is in a working state the subsequent announcemnts are fine, but i don't know what happens with the announcement which throws the exception
  • Exception, and code:

 

See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
NAudio.MmException: WaveStillPlaying calling waveOutWrite
   at NAudio.Wave.WaveOutBuffer.WriteToWaveOut() in E:\aktualis_fejlesztesek\pis-kofe201\Naudio-1.4b\NAudio\Wave\WaveStreams\WaveOutBuffer.cs:line 154
   at NAudio.Wave.WaveOutBuffer.OnDone() in E:\aktualis_fejlesztesek\pis-kofe201\Naudio-1.4b\NAudio\Wave\WaveStreams\WaveOutBuffer.cs:line 118
   at NAudio.Wave.WaveOut.Callback(IntPtr hWaveOut, WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) in E:\aktualis_fejlesztesek\pis-kofe201\Naudio-1.4b\NAudio\Wave\WaveOutputs\WaveOut.cs:line 377
   at NAudio.Wave.WaveWindow.WndProc(Message& m) in E:\aktualis_fejlesztesek\pis-kofe201\Naudio-1.4b\NAudio\Wave\MmeInterop\WaveWindow.cs:line 64
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 (RTMRel.030319-0100)
    CodeBase: file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
----------------------------------------
PisAnn2
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///D:/PIS/Release2/PisAnn2.exe
----------------------------------------
System.Windows.Forms
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System.Drawing
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.ServiceModel
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.ServiceModel/v4.0_4.0.0.0__b77a5c561934e089/System.ServiceModel.dll
----------------------------------------
System.Core
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
----------------------------------------
log4net
    Assembly Version: 1.2.10.0
    Win32 Version: 1.2.10.0
    CodeBase: file:///D:/PIS/Release2/log4net.DLL
----------------------------------------
PisDO
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///D:/PIS/Release2/PisDO.DLL
----------------------------------------
System.Runtime.Serialization
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 (RTMRel.030319-0100)
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Runtime.Serialization/v4.0_4.0.0.0__b77a5c561934e089/System.Runtime.Serialization.dll
----------------------------------------
System.Configuration
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 (RTMRel.030319-0100)
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
PresentationFramework
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/PresentationFramework/v4.0_4.0.0.0__31bf3856ad364e35/PresentationFramework.dll
----------------------------------------
WindowsBase
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/WindowsBase/v4.0_4.0.0.0__31bf3856ad364e35/WindowsBase.dll
----------------------------------------
PresentationCore
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_32/PresentationCore/v4.0_4.0.0.0__31bf3856ad364e35/PresentationCore.dll
----------------------------------------
System.Xaml
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xaml/v4.0_4.0.0.0__b77a5c561934e089/System.Xaml.dll
----------------------------------------
System.Runtime.DurableInstancing
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 built by: RTMRel
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Runtime.DurableInstancing/v4.0_4.0.0.0__31bf3856ad364e35/System.Runtime.DurableInstancing.dll
----------------------------------------
SMDiagnostics
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 (RTMRel.030319-0100)
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/SMDiagnostics/v4.0_4.0.0.0__b77a5c561934e089/SMDiagnostics.dll
----------------------------------------
System.Transactions
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 (RTMRel.030319-0100)
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Transactions/v4.0_4.0.0.0__b77a5c561934e089/System.Transactions.dll
----------------------------------------
System.EnterpriseServices
    Assembly Version: 4.0.0.0
    Win32 Version: 4.0.30319.1 (RTMRel.030319-0100)
    CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.EnterpriseServices/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.EnterpriseServices.dll
----------------------------------------
NAudio
    Assembly Version: 1.5.3.0
    Win32 Version: 1.5.3.0
    CodeBase: file:///D:/PIS/Release2/NAudio.DLL
----------------------------------------

************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.

For example:

<configuration>
    <system.windows.forms jitDebugging="true" />
</configuration>

When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NAudio.Wave;
using NAudio.CoreAudioApi;
using System.IO;
using System.Threading;

namespace PisDO.Announcer
{
    public class SimpleAnnouncer : IAnnouncer

    {
        IWavePlayer waveOut;
        string fileName = null;
        WaveStream mainOutputStream;
        WaveChannel32 volumeStream;
        WaveOutType wavOutType;
        bool waveOutCallbackWithNewWindow;
        bool wasapiExclusiveMode;
        bool wasapiEventCallback;
        System.Windows.Forms.Timer timer;
        string currentTimeText="";
        int currentTimeSeconds = 0;
        bool canPlay;
        int latency;
        int volume;
        string tempFile = "kimondja.wav";
        IAnnouncementOutputChannel outputChannel;
        IAnnouncement announcement;
        string wavFileDir;
        string[] wavStore;

        #region utility fields
        private readonly object eventLock = new object();
        private log4net.ILog logger;
        #endregion

        public SimpleAnnouncer(IAnnouncementOutputChannel outputChannel,string wavFileDir, string[] wavStore) {
            this.outputChannel = outputChannel;
            this.wavFileDir = wavFileDir;
            this.wavStore = wavStore;
            latency = 200;
            wavOutType = WaveOutType.WaveOut;
            waveOutCallbackWithNewWindow = true;
            wasapiEventCallback = false;
            wasapiExclusiveMode = false;
            timer = new System.Windows.Forms.Timer();
            //timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Tick += new EventHandler(timer_Tick);
            canPlay = true;
            volume = 1;
            logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        }

        void timer_Tick(object sender, EventArgs e)
        {
            if (mainOutputStream != null)
            {
                if (mainOutputStream.Position >= mainOutputStream.Length)
                {
                    IAnnouncement tmpAnnouncement = announcement;
                    Ended();
                    OnPlayEnded(new PlayStateChangedEventArgs(outputChannel, tmpAnnouncement, true));
                }
                else
                {
                    TimeSpan currentTime = mainOutputStream.CurrentTime;
                    TimeSpan totalTime = mainOutputStream.TotalTime;
                    currentTimeSeconds = (int)currentTime.TotalSeconds;
                    currentTimeText = String.Format("{0:00}:{1:00}/{2:00}:{3:00}", (int)currentTime.TotalMinutes, currentTime.Seconds,(int)totalTime.TotalMinutes,totalTime.Seconds);
                    if (logger.IsDebugEnabled) logger.Debug("currentTimeText: " + currentTimeText);
                }
            }
        }


        #region IAnnouncer Members

        public void Stop()
        {
            if (logger.IsDebugEnabled) logger.Debug("Stop() be");
            if (waveOut != null)
            {
                if (logger.IsDebugEnabled) logger.Debug("waveOut is not null, that's normal");
                waveOut.Stop();
                closeWaveOut();
                timer.Stop();

                canPlay = true;
                IAnnouncement tmpAnnouncement = announcement;
                announcement = null;
                OnPlayStopped(new PlayStateChangedEventArgs(outputChannel, tmpAnnouncement, false));
            }
            else {
                if (logger.IsWarnEnabled) logger.Warn("waveOut is null, that's strange");
            }
            if (logger.IsDebugEnabled) logger.Debug("Stop() ki");
        }

        private void Ended() {
            if (logger.IsDebugEnabled) logger.Debug("Ended() be");
                if (waveOut != null)
                {
                    if (logger.IsDebugEnabled) logger.Debug("waveOut is not null, that's normal");
                    timer.Stop();
                    waveOut.Stop();
                    closeWaveOut();
                    canPlay = true;
                    IAnnouncement tmpAnnouncement = announcement;
                    announcement = null;
                    OnPlayStopped(new PlayStateChangedEventArgs(outputChannel, tmpAnnouncement, true));
                }
                else
                {
                    if (logger.IsWarnEnabled) logger.Warn("waveOut is null, that's strange");
                }
                if (logger.IsDebugEnabled) logger.Debug("Ended() ki");
        }

        public void Dispose()
        {
            timer.Stop();
            timer = null;
            closeWaveOut();
        }

        public event EventHandler<PlayStateChangedEventArgs> PlayStopped;

        public event EventHandler<PlayStateChangedEventArgs> PlayStarted;

        public event EventHandler<PlayStateChangedEventArgs> PlayEnded;

        public void Play(IAnnouncement announcement) {
            this.announcement = announcement;
            string[] wavs = announcement.Data.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
            List<string> wavList = new List<string>();
            foreach (string wav in wavs)
            {
.....
  wavList.Add(wavFileDir + wav + ".wav"); } playWavs(wavList.ToArray<string>()); } public IAnnouncement Announcement { get { return announcement; } } #endregion public void OnPlayStopped(PlayStateChangedEventArgs e) { EventHandler<PlayStateChangedEventArgs> handler; lock (eventLock) { handler = PlayStopped; } if (handler != null) { handler(this, e); } } public void OnPlayStarted(PlayStateChangedEventArgs e) { EventHandler<PlayStateChangedEventArgs> handler; lock (eventLock) { handler = PlayStarted; } if (handler != null) { handler(this, e); } } public void OnPlayEnded(PlayStateChangedEventArgs e) { EventHandler<PlayStateChangedEventArgs> handler; lock (eventLock) { handler = PlayEnded; } if (handler != null) { handler(this, e); } } //0: ok //1: not worth to try again //2: worth to try again private int playWav(string soundFile) { if (logger.IsDebugEnabled) logger.Debug("playWav be " + soundFile); fileName = soundFile; timer.Interval = 500; timer.Start(); if (waveOut != null) { if (logger.IsWarnEnabled) logger.Warn("playWav waveOut is not null"); if (waveOut.PlaybackState == PlaybackState.Playing) { if (logger.IsWarnEnabled) logger.Warn("playWav ki " + soundFile + ", 1 (already playing)"); timer.Stop(); waveOut.Stop(); closeWaveOut(); return 2; } else if (waveOut.PlaybackState == PlaybackState.Paused) { waveOut.Play(); canPlay = false; if (logger.IsWarnEnabled) logger.Warn("playWav ki " + soundFile + ", 1 (Paused)"); timer.Stop(); waveOut.Stop(); closeWaveOut(); return 2; } } if (String.IsNullOrEmpty(fileName)) { throw new ArgumentException("Wav file to play is null or empty!"); } try { createWaveOut(); } catch (Exception driverCreateException) { if (logger.IsWarnEnabled) logger.Warn("driverCreateException: " + driverCreateException.Message); return 1; } mainOutputStream = createInputStream(fileName); currentTimeSeconds = 0; currentTimeText = String.Format("{0:00}:{1:00}", (int)mainOutputStream.TotalTime.TotalMinutes, mainOutputStream.TotalTime.Seconds); try { waveOut.Init(mainOutputStream); } catch (Exception initException) { if (logger.IsWarnEnabled) logger.Warn("initException, Error Initializing Output" + initException.Message); return 1; } volumeStream.Volume = volume; try { if (logger.IsDebugEnabled) logger.Debug("waveOut.Play before"); waveOut.Play(); if (logger.IsDebugEnabled) logger.Debug("waveOut.Play after"); } catch (Exception playException) { if (logger.IsWarnEnabled) logger.Warn("playException, Error Playing" + playException.Message); return 2; } OnPlayStarted(new PlayStateChangedEventArgs(outputChannel,announcement, false)); return 0; } private void playWavs(string[] soundFiles) { if (logger.IsDebugEnabled) logger.Debug("Play started."); //Hack while (waveOut != null && waveOut.PlaybackState == PlaybackState.Playing) { if (logger.IsWarnEnabled) logger.Warn("waiting for waveOut to free, it should be free from start anyway ..."); Thread.Sleep(100); } byte[] buffer = new byte[1024]; using (WaveFileWriter waveFileWriter = new WaveFileWriter(tempFile, new WaveFormat(44100, 16, 1))) { if (logger.IsDebugEnabled) logger.Debug("Building: " + tempFile); foreach (string sourceFile in soundFiles) { if (logger.IsDebugEnabled) logger.Debug("Adding: " + sourceFile); using (WaveFileReader reader = new WaveFileReader(sourceFile)) { int read; while ((read = reader.Read(buffer, 0, buffer.Length)) > 0) { waveFileWriter.Write(buffer, 0, read); } } } if (logger.IsDebugEnabled) logger.Debug(tempFile + " is ready"); //waveFileWriter.Flush(); } for (int i = 0; i < 10; i++) { int res = playWav(tempFile); if (logger.IsDebugEnabled) logger.Debug("playWav return value is: " + res); if (res == 0 || res == 1) { break; } Thread.Sleep(200); } } private WaveStream createInputStream(string fileName) { WaveChannel32 inputStream; if (fileName.EndsWith(".wav")) { WaveStream readerStream = new WaveFileReader(fileName); if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm) { readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream); readerStream = new BlockAlignReductionStream(readerStream); } if (readerStream.WaveFormat.BitsPerSample != 16) { var format = new WaveFormat(readerStream.WaveFormat.SampleRate, 16, readerStream.WaveFormat.Channels); readerStream = new WaveFormatConversionStream(format, readerStream); } inputStream = new WaveChannel32(readerStream); } else if (fileName.EndsWith(".mp3")) { WaveStream mp3Reader = new Mp3FileReader(fileName); WaveStream pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader); WaveStream blockAlignedStream = new BlockAlignReductionStream(pcmStream); inputStream = new WaveChannel32(blockAlignedStream); } else { throw new InvalidOperationException("Unsupported extension"); } // we are not going into a mixer so we don't need to zero pad //((WaveChannel32)inputStream).PadWithZeroes = false; volumeStream = inputStream; var meteringStream = new MeteringStream(inputStream, inputStream.WaveFormat.SampleRate / 10); //meteringStream.StreamVolume += new EventHandler<StreamVolumeEventArgs>(meteringStream_StreamVolume); return meteringStream; } private void createWaveOut() { if (logger.IsDebugEnabled) logger.Debug("createWaveOut() be"); closeWaveOut(); if (wavOutType==WaveOutType.WaveOut) { WaveCallbackInfo callbackInfo = waveOutCallbackWithNewWindow ? WaveCallbackInfo.NewWindow() : WaveCallbackInfo.FunctionCallback(); WaveOut outputDevice = new WaveOut(callbackInfo); outputDevice.DesiredLatency = latency; waveOut = outputDevice; } else if (wavOutType == WaveOutType.DirectSound) { waveOut = new DirectSoundOut(latency); } else if (wavOutType == WaveOutType.ASIO) { } else { waveOut = new WasapiOut( wasapiExclusiveMode ? AudioClientShareMode.Exclusive : AudioClientShareMode.Shared, wasapiEventCallback, latency); } if (logger.IsDebugEnabled) logger.Debug("createWaveOut() ki"); } private void closeWaveOut() { if (waveOut != null) { waveOut.Stop(); } if (mainOutputStream != null) { // this one really closes the file and ACM conversion volumeStream.Close(); volumeStream = null; // this one does the metering stream mainOutputStream.Close(); mainOutputStream = null; } if (waveOut != null) { waveOut.Dispose(); waveOut = null; } } } public enum WaveOutType { WaveOut, DirectSound, ASIO } }
Jul 26, 2011 at 10:42 AM

What waveOut callback model are you using?  I would go with new window if possible.

Aug 17, 2011 at 5:24 PM

I am going with the basic WavOut constructor

WaveOut outputDevice = new WaveOut();

I am calling Play from a gui thread like this, where announcer.Play eventually leads to a wavOut.Play and winFormsGui is a form

winFormsGui.BeginInvoke(new MethodInvoker(delegate
{
	ircsCenterManager.Announce(nextToAnnounce.Zone.IrcsId);
	announcer.Play(nextToAnnounce);
}));

 

 



 

Sep 5, 2011 at 2:50 PM

the instance of WaveOut should be created on a GUI thread.

Sep 26, 2011 at 1:40 PM

Yes, the WaveOut device is created (if needed) in the same announcer.Play method mentioned above.

So it is created on the GUI thread albeit with the help of BeginInvoke. Can this be the problem?