Rather than us trying to debug desktop code that we don't have full source for, have you tried starting with a codebase that is known to work for the Compact Framework instead? There's a complete example of using the waveform audio APIs up in MSDN that probably defines everything you need, and it was written for the Compact Framework.
How to initialize WaveOUT API on Win CE running on ARM in C#
-
15-01-2022 - |
Pergunta
I am trying to make work WinOut API on Win CE (ARM) but with the same code that runs on Windows 7 I am getting MMSYSERR_INVALIDPARAM in the line for buffer preparation.
Win32.MMRESULT hr = Win32.waveOutPrepareHeader(
hWaveOut, ref WaveOutHeaders[i], Marshal.SizeOf(WaveOutHeaders[i]));
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR) ...
I think that is the problem of buffer alignment on byte boundary for ARM but I do not know how to do it in .NET Compact Framework for Windows CE.
I am trying to find some solution or explanation but nothing.
UPDATE
This is the P/Invoke that works on Win CE and .NET Compact Framework. On the internet is possible to find P/Invoke related to "winmm.dll" instead of "coredll.dll". Winmm.dll exists on Windows XP, 7. Windows CE works only coredll.dll. If used "winmm.dll" on WinCE is received the following message " "Can't P/Invoke winmm.dll"
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern MMRESULT waveOutOpen(ref IntPtr hWaveOut, int uDeviceID, ref WAVEFORMATEX lpFormat, DelegateWaveOutProc dwCallBack, int dwInstance, int dwFlags);
[DllImport("coredll.dll")]
public static extern MMRESULT waveInOpen(ref IntPtr hWaveIn, int deviceId, ref WAVEFORMATEX wfx, DelegateWaveInProc dwCallBack, int dwInstance, int dwFlags);
[DllImport("coredll.dll", SetLastError = true)]
public static extern MMRESULT waveInStart(IntPtr hWaveIn);
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint waveInGetDevCaps(int index, ref WAVEINCAPS pwic, int cbwic);
[DllImport("coredll.dll", SetLastError = true)]
public static extern uint waveInGetNumDevs();
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint waveOutGetDevCaps(int index, ref WAVEOUTCAPS pwoc, int cbwoc);
[DllImport("coredll.dll", SetLastError = true)]
public static extern uint waveOutGetNumDevs();
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern MMRESULT waveOutWrite(IntPtr hWaveOut, ref WAVEHDR pwh, int cbwh);
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern MMRESULT waveOutPrepareHeader(IntPtr hWaveOut, ref WAVEHDR lpWaveOutHdr, int uSize);
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint waveOutGetDevCaps(int index, ref WAVEOUTCAPS pwoc, int cbwoc);
[DllImport("coredll.dll", SetLastError = true)]
public static extern uint waveOutGetNumDevs();
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern MMRESULT waveOutWrite(IntPtr hWaveOut, ref WAVEHDR pwh, int cbwh);
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern MMRESULT waveOutPrepareHeader(IntPtr hWaveOut, ref WAVEHDR lpWaveOutHdr, int uSize);
[DllImport("coredll.dll", EntryPoint = "waveOutReset", SetLastError = true)]
public static extern MMRESULT waveOutReset(IntPtr hWaveOut);
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern MMRESULT waveOutUnprepareHeader(IntPtr hWaveOut, ref WAVEHDR pwh, int cbwh);
[DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern Win32.MMRESULT waveOutClose(IntPtr hWaveOut);
[DllImport("coredll.dll")]
public static extern Win32.MMRESULT waveOutPause(IntPtr hWaveOut);
[DllImport("coredll.dll", EntryPoint = "waveOutRestart", SetLastError = true)]
public static extern Win32.MMRESULT waveOutRestart(IntPtr hWaveOut);
Data Structures and constants used
public const int WAVE_MAPPER = -1;
public const int WT_EXECUTEDEFAULT = 0x00000000;
public const int WT_EXECUTEINIOTHREAD = 0x00000001;
public const int WT_EXECUTEINTIMERTHREAD = 0x00000020;
public const int WT_EXECUTEINPERSISTENTTHREAD = 0x00000080;
public const int TIME_ONESHOT = 0;
public const int TIME_PERIODIC = 1;
/// <summary>
/// WAVEOUTCAPS
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
public struct WAVEOUTCAPS
{
public short wMid;
public short wPid;
public int vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szPname;
public uint dwFormats;
public short wChannels;
public short wReserved;
public int dwSupport;
}
/// <summary>
/// WAVEINCAPS
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
public struct WAVEINCAPS
{
public short wMid;
public short wPid;
public int vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szPname;
public uint dwFormats;
public short wChannels;
public short wReserved;
public int dwSupport;
}
/// <summary>
/// WAVEFORMATEX
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
/// <summary>
/// MMRESULT
/// </summary>
public enum MMRESULT : uint
{
MMSYSERR_NOERROR = 0,
MMSYSERR_ERROR = 1,
MMSYSERR_BADDEVICEID = 2,
MMSYSERR_NOTENABLED = 3,
MMSYSERR_ALLOCATED = 4,
MMSYSERR_INVALHANDLE = 5,
MMSYSERR_NODRIVER = 6,
MMSYSERR_NOMEM = 7,
MMSYSERR_NOTSUPPORTED = 8,
MMSYSERR_BADERRNUM = 9,
MMSYSERR_INVALFLAG = 10,
MMSYSERR_INVALPARAM = 11,
MMSYSERR_HANDLEBUSY = 12,
MMSYSERR_INVALIDALIAS = 13,
MMSYSERR_BADDB = 14,
MMSYSERR_KEYNOTFOUND = 15,
MMSYSERR_READERROR = 16,
MMSYSERR_WRITEERROR = 17,
MMSYSERR_DELETEERROR = 18,
MMSYSERR_VALNOTFOUND = 19,
MMSYSERR_NODRIVERCB = 20,
WAVERR_BADFORMAT = 32,
WAVERR_STILLPLAYING = 33,
WAVERR_UNPREPARED = 34
}
/// <summary>
/// MMSYSERR
/// </summary>
public enum MMSYSERR : uint
{
// Add MMSYSERR's here!
MMSYSERR_BASE = 0x0000,
MMSYSERR_NOERROR = 0x0000
}
[Flags]
public enum WaveHdrFlags : uint
{
WHDR_DONE = 1,
WHDR_PREPARED = 2,
WHDR_BEGINLOOP = 4,
WHDR_ENDLOOP = 8,
WHDR_INQUEUE = 16
}
[Flags]
public enum WaveProcFlags : int
{
CALLBACK_NULL = 0,
CALLBACK_FUNCTION = 0x30000,
CALLBACK_EVENT = 0x50000,
CALLBACK_WINDOW = 0x10000,
CALLBACK_THREAD = 0x20000,
WAVE_FORMAT_QUERY = 1,
WAVE_MAPPED = 4,
WAVE_FORMAT_DIRECT = 8
}
[Flags]
public enum HRESULT : long
{
S_OK = 0L,
S_FALSE = 1L
}
[Flags]
public enum WaveFormatFlags : int
{
WAVE_FORMAT_PCM = 0x0001
}
/// <summary>
/// WAVEHDR
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WAVEHDR
{
public IntPtr lpData; // pointer to locked data buffer
public uint dwBufferLength; // length of data buffer
public uint dwBytesRecorded; // used for input only
public IntPtr dwUser; // for client's use
public WaveHdrFlags dwFlags; // assorted flags (see defines)
public uint dwLoops; // loop control counter
public IntPtr lpNext; // PWaveHdr, reserved for driver
public IntPtr reserved; // reserved for driver
}
/// <summary>
/// TimeCaps
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TimeCaps
{
public UInt32 wPeriodMin;
public UInt32 wPeriodMax;
};
/// <summary>
/// WOM_Messages
/// </summary>
public enum WOM_Messages : int
{
OPEN = 0x03BB,
CLOSE = 0x03BC,
DONE = 0x03BD
}
/// <summary>
/// WIM_Messages
/// </summary>
public enum WIM_Messages : int
{
OPEN = 0x03BE,
CLOSE = 0x03BF,
DATA = 0x03C0
}
public delegate void DelegateWaveOutProc(IntPtr hWaveOut, WOM_Messages msg, IntPtr dwInstance, ref Win32.WAVEHDR wavehdr, IntPtr lParam);
public delegate void DelegateWaveInProc(IntPtr hWaveIn, WIM_Messages msg, IntPtr dwInstance, ref Win32.WAVEHDR wavehdr, IntPtr lParam);
public delegate void DelegateTimerProc(IntPtr lpParameter, bool TimerOrWaitFired);
public delegate void TimerEventHandler(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2);
Method calls
/// <summary>
/// CreateWaveOutHeaders
/// </summary>
/// <returns></returns>
private bool CreateWaveOutHeaders()
{
//Buffer anlegen
this.WaveOutHeaders = new Win32.WAVEHDR[BufferCount];
this.GCWaveOutHandleBuffers = new GCHandle[BufferCount];
GCWaveOutHandleHeaders = new GCHandle[BufferCount];
int createdHeaders = 0;
//Für jeden Buffer
for (int i = 0; i < BufferCount; i++)
{
//Header erstellen
WaveOutHeaders[i].dwLoops = 0;
WaveOutHeaders[i].dwUser = IntPtr.Zero;
WaveOutHeaders[i].lpNext = IntPtr.Zero;
WaveOutHeaders[i].reserved = IntPtr.Zero;
//Im Speicher verankern
GCWaveOutHandleHeaders[i] = GCHandle.Alloc(this.WaveOutHeaders[i], GCHandleType.Pinned);
//Wenn der Buffer vorbereitet werden konnte
Win32.MMRESULT hr = Win32.waveOutPrepareHeader(hWaveOut, ref WaveOutHeaders[i], Marshal.SizeOf(WaveOutHeaders[i]));
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR)
{
createdHeaders++;
}
}
//Fertig
return (createdHeaders == BufferCount);
}
/// <summary>
/// FreeWaveOutHeaders
/// </summary>
private void FreeWaveOutHeaders()
{
try
{
if (WaveOutHeaders != null)
{
for (int i = 0; i < WaveOutHeaders.Length; i++)
{
Win32.MMRESULT hr = Win32.waveOutUnprepareHeader(hWaveOut, ref WaveOutHeaders[i], Marshal.SizeOf(WaveOutHeaders[i]));
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex.Message);
}
}
/// <summary>
/// OpenWaveOuz
/// </summary>
/// <returns></returns>
private bool OpenWaveOut()
{
if (hWaveOut == IntPtr.Zero)
{
//Wenn nicht schon offen
if (IsWaveOutOpened == false)
{
//Format bestimmen
Win32.WAVEFORMATEX waveFormatEx = new Win32.WAVEFORMATEX();
waveFormatEx.wFormatTag = (ushort)Win32.WaveFormatFlags.WAVE_FORMAT_PCM;
waveFormatEx.nChannels = (ushort)Channels;
waveFormatEx.nSamplesPerSec = (ushort)SamplesPerSecond;
waveFormatEx.wBitsPerSample = (ushort)BitsPerSample;
waveFormatEx.nBlockAlign = (ushort)((waveFormatEx.wBitsPerSample * waveFormatEx.nChannels) >> 3);
waveFormatEx.nAvgBytesPerSec = (uint)(waveFormatEx.nBlockAlign * waveFormatEx.nSamplesPerSec);
//WaveOut Gerät ermitteln
int deviceId = WinSound.GetWaveOutDeviceIdByName(WaveOutDeviceName);
//WaveIn Gerät öffnen
Win32.MMRESULT hr = Win32.waveOutOpen(ref hWaveOut, deviceId, ref waveFormatEx, delegateWaveOutProc, 0, (int)Win32.WaveProcFlags.CALLBACK_FUNCTION);
//Wenn nicht erfolgreich
if (hr != Win32.MMRESULT.MMSYSERR_NOERROR)
{
IsWaveOutOpened = false;
return false;
}
//Handle sperren
GCHandle.Alloc(hWaveOut, GCHandleType.Pinned);
}
}
IsWaveOutOpened = true;
return true;
}
/// <summary>
///Open
/// </summary>
/// <param name="waveInDeviceName"></param>
/// <param name="waveOutDeviceName"></param>
/// <param name="samplesPerSecond"></param>
/// <param name="bitsPerSample"></param>
/// <param name="channels"></param>
/// <returns></returns>
public bool Open(string waveOutDeviceName, int samplesPerSecond, int bitsPerSample, int channels, int bufferCount)
{
try
{
lock (Locker)
{
//Wenn nicht schon geöffnet
if (Opened == false)
{
//Daten übernehmen
WaveOutDeviceName = waveOutDeviceName;
SamplesPerSecond = samplesPerSecond;
BitsPerSample = bitsPerSample;
Channels = channels;
BufferCount = Math.Max(bufferCount, 1);
//Wenn WaveOut geöffnet werden konnte
if (OpenWaveOut())
{
//Wenn alle Buffer erzeugt werden konnten
if (CreateWaveOutHeaders())
{
//Thread starten
StartThreadPlayWaveOut();
IsClosed = false;
return true;
}
}
}
//Schon geöffnet
return false;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(String.Format("Start | {0}", ex.Message));
return false;
}
}
/// <summary>
/// PlayData
/// </summary>
/// <param name="datas"></param>
/// <param name="isBlocking"></param>
/// <returns></returns>
public bool PlayData(Byte[] datas, bool isBlocking)
{
try
{
if (Opened)
{
int index = GetNextFreeWaveOutHeaderIndex();
if (index != -1)
{
//Werte übernehmen
this.IsBlocking = isBlocking;
//Daten kopieren
GCWaveOutHandleBuffers[index] = GCHandle.Alloc(datas, GCHandleType.Pinned);
WaveOutHeaders[index].lpData = GCWaveOutHandleBuffers[index].AddrOfPinnedObject();
WaveOutHeaders[index].dwBufferLength = (uint)datas.Length;
WaveOutHeaders[index].dwUser = (IntPtr)index;
//Abspielen
this.IsStarted = true;
Win32.MMRESULT hr = Win32.waveOutWrite(hWaveOut, ref WaveOutHeaders[index], (int)Marshal.SizeOf(WaveOutHeaders[index]));
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR)
{
//Wenn blockierend
if (isBlocking)
{
AutoResetEventDataPlayed.WaitOne();
AutoResetEventDataPlayed.Set();
}
return true;
}
else
{
//Fehler beim Abspielen
AutoResetEventDataPlayed.Set();
return false;
}
}
else
{
//Kein freier Ausgabebuffer vorhanden
//System.Diagnostics.Debug.WriteLine(String.Format("No free WaveOut Buffer found | {0}", DateTime.Now.ToLongTimeString()));
return false;
}
}
else
{
//Nicht geöffnet
return false;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(String.Format("PlayData | {0}", ex.Message));
return false;
}
}
/// <summary>
/// Close
/// </summary>
/// <returns></returns>
public bool Close()
{
try
{
lock (Locker)
{
//Wenn geöffnet
if (Opened)
{
//Als manuel beendet setzen
IsClosed = true;
Win32.MMRESULT hr = Win32.waveOutReset(hWaveOut);
//Warten bis alle Daten fertig abgespielt
int count = 0;
while (Win32.waveOutClose(hWaveOut) != Win32.MMRESULT.MMSYSERR_NOERROR && count <= 100)
{
System.Threading.Thread.Sleep(50);
count++;
}
//Variablen setzen
IsWaveOutOpened = false;
AutoResetEventDataPlayed.Set();
return true;
}
return false;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(String.Format("Close | {0}", ex.Message));
return false;
}
}
Solução