waveOutPrepareHeader 返回 INVALPARAMS

发布于 2025-01-04 06:57:14 字数 1290 浏览 1 评论 0原文

我已经尝试追踪这个问题有一段时间了,但我不知道下一步该去哪里。每当我调用 waveOutPrepareHeader() 时,我都会收到 INVALPARAMS 指示“缓冲区的基地址与样本大小不对齐”。

我目前正在使用通过 MSDN 找到的方法从文件中的“数据”标记(和长度)之后的数据准备我的标头。

    public Wave.SystemError Read(BinaryReader rdr, uint readLength)
    {
        dwBufferLength = readLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED,
               (uint)data.Length);

        if (lpData == IntPtr.Zero)
            return Wave.SystemError.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return Wave.SystemError.NOERROR;
    }

该类的所有参数在使用前都被清零,在对波形文件调用此函数后,

dwBufferLength = 32768
dwBytesRecorded = 0
dwFlags = 0
dwLoops = 0
dwUser = 0
lpData = 384656
lpNext = 0
reserved = 0

当传递到

return waveOutPrepareHeader(hWaveOut, 
                            ref headerBuffer[buffIndex],
                            (uint)Marshal.SizeOf(headerBuffer[buffIndex]));

headerBuffer[buffIndex] 是上述 WAVEHDR 时,我得到 11 (MMSYSERR_INVALPARAM)。我已经检查过,我的 hWaveOut 和大小似乎是正常的,所以我被迫得出结论,问题出在标题上,但我不知道出了什么问题,甚至不知道要检查什么。

我需要做什么来修复此错误,或者如果失败,我可以检查什么来找出导致该错误的原因?任何帮助将不胜感激

I've been trying to track this down for a while but I'm at a loss as to where to look next. Whenever I call waveOutPrepareHeader() I get INVALPARAMS indicating "The buffer's base address is not aligned with the sample size."

I am currently preparing my header from the data after the "data" tag (and length) from the file using the method found via MSDN.

    public Wave.SystemError Read(BinaryReader rdr, uint readLength)
    {
        dwBufferLength = readLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED,
               (uint)data.Length);

        if (lpData == IntPtr.Zero)
            return Wave.SystemError.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return Wave.SystemError.NOERROR;
    }

All the parameters of the class are zeroed out before use, after calling this function on a wave file I get

dwBufferLength = 32768
dwBytesRecorded = 0
dwFlags = 0
dwLoops = 0
dwUser = 0
lpData = 384656
lpNext = 0
reserved = 0

when passed into

return waveOutPrepareHeader(hWaveOut, 
                            ref headerBuffer[buffIndex],
                            (uint)Marshal.SizeOf(headerBuffer[buffIndex]));

where headerBuffer[buffIndex] is the abovementioned WAVEHDR I get 11 (MMSYSERR_INVALPARAM). I've checked and my hWaveOut and size seems to be sane so I'm forced to conclude the problem is with the header but I can't figure out what is wrong or even what to check.

What do I need to do to fix this error, or failing that, what can I check to see what is causing it? Any assistance would be greatly appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如果没有你 2025-01-11 06:57:14

您的样本大小是否大于 1 字节?如果是这样的话...

在ARM上保持数据对齐很重要,因此如果您分配BYTE(一个字节)缓冲区,然后将其转换为SHORT(两个字节),那么如果BYTE缓冲区分配在奇数地址上,那么您将得到未对齐的数据访问。

因此,如果您的样本大小是两个字节,那么您必须确保您的字节缓冲区地址始终是偶数。

要验证这一点,您可以检查出现错误时 lpData 的值,如果是奇数,则只需多分配 1 个字节并将 buffer+1 发送到 winapi 函数。


下面是正确对齐的示例代码,位于:
http://www.utdallas.edu/~nsg051000/AmbientNoise4/Wave.cs

    ///  
    /// Read a data buffer from the supplied BinaryReader.  This method will 
    /// allocate memory for the data buffer it is not already allocated. 
    ///  
    /// BinaryReader containing data 
    /// Size, in bytes, to be read 
    /// MMSYSERR.NOERROR if successful 
    public MMSYSERR Read(BinaryReader rdr, uint readLength, int align)
    {
        uint bufferLength = readLength;

        if (bufferLength % align != 0)
            bufferLength += (uint)(align - (bufferLength % align));

        dwBufferLength = bufferLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED, (uint)bufferLength);

        if (lpData == IntPtr.Zero)
            return MMSYSERR.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return MMSYSERR.NOERROR;
    }

Is your sample size bigger than 1 byte? If so then ...

on ARM it is important to keep data aligned, so if you allocate BYTE (one byte) buffer and later cast it to SHORT (two bytes), then if BYTE buffer was allocated on odd address then you will get unaligned data access.

So if your sample size is two bytes then you must ensure that your BYTE buffer address is always even.

To verify this you can check what value does lpData have when error appears, if it is odd then simply allocate 1 byte more and send buffer+1 to winapi function.


below is sample code with proper alignment, found at:
http://www.utdallas.edu/~nsg051000/AmbientNoise4/Wave.cs

    ///  
    /// Read a data buffer from the supplied BinaryReader.  This method will 
    /// allocate memory for the data buffer it is not already allocated. 
    ///  
    /// BinaryReader containing data 
    /// Size, in bytes, to be read 
    /// MMSYSERR.NOERROR if successful 
    public MMSYSERR Read(BinaryReader rdr, uint readLength, int align)
    {
        uint bufferLength = readLength;

        if (bufferLength % align != 0)
            bufferLength += (uint)(align - (bufferLength % align));

        dwBufferLength = bufferLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED, (uint)bufferLength);

        if (lpData == IntPtr.Zero)
            return MMSYSERR.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return MMSYSERR.NOERROR;
    }
岁月苍老的讽刺 2025-01-11 06:57:14

该问题最终不是 lpData(由 LocalAlloc 正确分配)的问题,而是 WAVEHDR 结构本身传递到 PInvoked waveOutPrepareHeader 的方式的问题。

waveOut 上的大多数材料(甚至对于 C#)都要求您传递标头类型的对象。但为了停止出现错误,我必须使用 Marshal.AllocHGlobal 创建一个数据块,并使用 Marshal.StructureToPtr 将标头复制到其中。然后,来自 AllocHGlobal 的 IntPtr 被传递到 waveOutPrepareHeader 中,从而解决了问题。

这里有一些粗略的示例代码,供遇到类似问题的人使用。

WAVEHDR header = new WAVEHDR();
//Read or setup header data here
IntPtr headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header));
Marshal.StructureToPtr(header, headerPtr, true);
waveOutPrepareHeader(hWaveOut, headerPtr, (uint)Marshal.SizeOf(header));

这假设您将使用标头的所有内容设置为 IntPtr 类型而不是 WAVEHDR 类型的 PInvoke。

从那里,将 headerPtr 用于需要传递该标头的所有位置。您必须按照您的预期在适当的位置自行处理内存的释放。

The problem ended up being not an issue with lpData (which was being allocated properly by LocalAlloc), but an issue with the way that the WAVEHDR structure itself was being passed to the PInvoked waveOutPrepareHeader.

Most material on waveOut (even for C#) has you passing in an object of the header's type. But in order to stop getting the error, I had to make a block of data using Marshal.AllocHGlobal and copy the header into it with Marshal.StructureToPtr. The IntPtr from the AllocHGlobal then is passed into waveOutPrepareHeader as such and that resolved the issue.

Here's some rough sample code for any who run up against a similar problem.

WAVEHDR header = new WAVEHDR();
//Read or setup header data here
IntPtr headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header));
Marshal.StructureToPtr(header, headerPtr, true);
waveOutPrepareHeader(hWaveOut, headerPtr, (uint)Marshal.SizeOf(header));

This assumes that you set your PInvoke for everything that uses the header to an IntPtr type instead of a WAVEHDR one.

From there, use the headerPtr for all the places where you need to pass in that header. You'll have to handle the freeing of memory yourself at the appropriate location as you would expect.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文