Thursday, 25 March 2010

NAudio x64 Testing Needed

After a bit of a blogging break, I think it is time to give a brief status update. I have been trying to keep up with the constant stream of support requests coming in through the NAudio forums and comments on posts here but the reality is that there has been more than I can handle so please accept my apologies if your query has gone unanswered.

I do continue to make slow progress on NAudio. Today I checked in a changeset that should hopefully give us proper x64 support. My only trouble is that I do not have an x64 machine to test on (next PC I buy will be x64 but that may not be for another year). If anyone has a 64 bit OS and is willing to help me out with a quick test then please do the following:

  1. Download the latest NAudio source code and load it up in Visual Studio 2008
  2. Go to the NAudio project settings, and on the Build tab set the Platform target to Any CPU (it is currently set to “x86”)
  3. Run the NAudioDemo application and attempt to play an MP3 file
  4. Comment here letting me know how you got on

It would be great to be able to properly support x64 as currently you are forced to set your calling application to x86 only as well.

13 comments:

Unknown said...

Tried to play an mp3 in x64 mode, but I there was an exception. I wasn't sure how to figure out which parameter was invalid.

NAudio.MmException: InvalidParameter calling acmStreamPrepareHeader
at NAudio.MmException.Try(MmResult result, String function) in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\MmeInterop\MmException.cs:line 40
at NAudio.Wave.Compression.AcmStreamHeader.Prepare() in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\Compression\AcmStreamHeader.cs:line 37
at NAudio.Wave.Compression.AcmStreamHeader.Convert(Int32 bytesToConvert, Int32& sourceBytesConverted) in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\Compression\AcmStreamHeader.cs:line 57
at NAudio.Wave.Compression.AcmStream.Convert(Int32 bytesToConvert, Int32& sourceBytesConverted) in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\Compression\AcmStream.cs:line 163
at NAudio.Wave.WaveFormatConversionStream.Read(Byte[] array, Int32 offset, Int32 count) in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\WaveStreams\WaveFormatConversionStream.cs:line 158
at NAudio.Wave.BlockAlignReductionStream.Read(Byte[] buffer, Int32 offset, Int32 count) in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\WaveStreams\BlockAlignReductionStream.cs:line 148
at NAudio.Wave.WaveChannel32.Read(Byte[] destBuffer, Int32 offset, Int32 numBytes) in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\WaveStreams\WaveChannel32.cs:line 151
at NAudioDemo.MeteringStream.Read(Byte[] buffer, Int32 offset, Int32 count) in C:\Users\Brian\Downloads\naudio-43087\NAudioDemo\MeteringStream.cs:line 54
at NAudio.Wave.WaveOutBuffer.OnDone() in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\WaveStreams\WaveOutBuffer.cs:line 105
at NAudio.Wave.WaveOut.Play() in C:\Users\Brian\Downloads\naudio-43087\NAudio\Wave\WaveOutputs\WaveOut.cs:line 142
at NAudioDemo.AudioPlaybackForm.buttonPlay_Click(Object sender, EventArgs e) in C:\Users\Brian\Downloads\naudio-43087\NAudioDemo\AudioPlaybackForm.cs:line 97

Unknown said...

thanks Brian, your help is greatly appreciated. I'll revisit the acmStreamPrepareHeader function. It could possibly be due to some changes I made to ACMSTREAMHEADER as well.

Unknown said...

I think I may have found the issue. In AcmStreamHeader.Prepare I was hard-coding the cbStruct member. It now uses Marshal.SizeOf. I've checked in a new version to CodePlex for anyone else who is willing to test for me.

Unknown said...

Hey Mark, I got the same exception with the new version, but I was able to get it to work. Marshal.SizeOf returned 104 for your class, but that wasn't big enough. I got it to work with a class that is 128 bytes.
The acmStreamPrepareHeader method fills the reserved array (at an offset of 88 bytes) with data and seems to ignore the 24 bytes before it.

Here is a solution that works for both x86 and x64 modes.

Explicitly set the size to 128:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 128)]
class AcmStreamHeaderStruct

and simply delete the following field, because user code isn't supposed to touch it and it isn't needed:

[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]
public int[] reserved;

Is there anything else that needs testing in x64 mode?

Unknown said...

thanks Brian. With hindsight, I think that was the reason why I originally had this structure with ten int members rather than an array and hardcoded its size. I've checked in your suggested code.

Playing an MP3 gives a fairly good workout to WaveOut and some of the ACM stuff. It is probably also worth giving a quick run through the recording form, and also checking that all the playback modes work (WaveOut both modes, DirectSound and WASAPI). Using the ACM test form (even just to see the contents of the listbox) will also test out a few more function signatures.

There is also some basic mixer interop and MIDI interop in NAudio. If you have any MIDI hardware you can use the NAudioDemo project to give it a go. Also you can run unit tests to give the mixer interop a runthrough. Some of the tests intermittently fail on x86 simply due to failing to set control values to exactly what we want, but the main thing is that the mixer functions can be called in x64 without crashing.

thanks again Brian for doing this, it is extremely helpful.

The Reverand said...

I have a 64bit OS, Windows 7 Pro, and I am hoping to get down a dirty with it shortly.
I am using Beta 2 of Visual C# Express 2010 and when I compiled the latest source I was "warned" that there was a depreciated method call.
The call is in DirectSoundOut.Stop(), you use a Monitor.TryEnter() overload that doesn't use a lockTaken bool parameter.
Here is the new code for Stop():
public void Stop()
{
// Try and tidy up nicely
bool lockTaken = false;

Monitor.TryEnter(m_LockObject, 50, ref lockTaken);

if (lockTaken)
{
playbackState = PlaybackState.Stopped;
Monitor.Exit(m_LockObject);
}
else
{
// No joy - abort the thread!
if (notifyThread != null)
{
notifyThread.Abort();
notifyThread = null;
}
}
}

Unknown said...

thanks The Reverand. I'm guessing that must be some kind of .NET 4 thing, because that overload of Monitor.TryEnter isn't available on my system.

The Reverand said...

Must be. I'd never seen it before.

AlienImation said...

Working perfectly for me with my 64-bit app while I had the same "InvalidParameter calling acmStreamPrepareHeader
" exception.

Brillant

Bob Denny said...

With 46831 I can play MP3 if both the demo and NAudio set to x86. When both set to ANyCPU (VS2008, XP64):

NAudio.MmException was unhandled
Message="NoDriver calling acmFormatSuggest"
Source="NAudio"
StackTrace:
at NAudio.MmException.Try(MmResult result, String function) in D:\dev\DotNet Audio\naudio-46381\NAudio\Wave\MmeInterop\MmException.cs:line 40
at NAudio.Wave.Compression.AcmStream.SuggestPcmFormat(WaveFormat compressedFormat) in D:\dev\DotNet Audio\naudio-46381\NAudio\Wave\Compression\AcmStream.cs:line 111
at NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(WaveStream sourceStream) in D:\dev\DotNet Audio\naudio-46381\NAudio\Wave\WaveStreams\WaveFormatConversionStream.cs:line 29
at NAudioDemo.AudioPlaybackForm.CreateInputStream(String fileName) in D:\dev\DotNet Audio\naudio-46381\NAudioDemo\AudioPlaybackForm.cs:line 122
at NAudioDemo.AudioPlaybackForm.buttonPlay_Click(Object sender, EventArgs e) in D:\dev\DotNet Audio\naudio-46381\NAudioDemo\AudioPlaybackForm.cs:line 78
at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
...etc...

Unknown said...

thanks Bob,
that's annoying, will have to check that the MP3 wave format translates properly to 64 bit.

Unknown said...

Bob, is the ACM Format Conversion option on the NAudio Demo project able to show the ACM codecs installed on your PC. If so, is there an MP3 one one there, and are you able to display selected format info?

Shimmy said...

I changed the target-compile to x86 and everything works like a charm.