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

Solução

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.

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