简体   繁体   English

C#FMOD实时播放流

[英]C# FMOD Playing stream in realtime

i am trying to play a stream in real time ( I keep appedning data to it as it comes in from a nexternal source) but no matter what FMOD doesn't want to carry on playing after the first chunk that got loaded, it seems as it is copying the memory stream/decoding it before playing, then as it is playing it doesn't use my stream anymore. 我正在尝试实时播放流(我一直在对数据进行分页,因为它来自下一个来源),但是无论FMOD不想在第一个块加载后继续进行播放,它在播放之前先复制内存流/对其进行解码,然后在播放时不再使用我的流。

I am using the following to play my stream: 我正在使用以下播放流:

        var exinfo = new FMOD.CREATESOUNDEXINFO();
        exinfo.cbsize = Marshal.SizeOf(exinfo);
        exinfo.length = (uint)_buffer.Length;

        _result = System.createStream(_buffer, MODE.CREATESTREAM | MODE.OPENMEMORY_POINT , ref exinfo, ref _sound);
        FMODErrorCheck(_result);

        _result = System.playSound(FMOD.CHANNELINDEX.FREE, _sound, false, ref _channel);
        FMODErrorCheck(_result);

But no matter what, it only plays the amount of data that is in the stream at the point of calling playSound. 但是无论如何,它仅在调用playSound时播放流中的数据量。

Can anyone know how to modify the buffer in real time? 谁能知道如何实时修改缓冲区? After the stream has started playing...? 流开始播放后...?

I would recommend you check out the "usercreatedsound" example that ships with FMOD, it should do what you require. 我建议您检查一下FMOD附带的“ usercreatedsound”示例,它应该可以满足您的要求。

The basic idea is you define the properties of the sound you wish to play in the CreateSoundExInfo structure and provide it with callbacks which you can use to load / stream data from wherever you like. 基本思想是在CreateSoundExInfo结构中定义希望播放的声音的属性,并为它提供回调,您可以使用它们从任意位置加载/流式传输数据。

Function pointer: 函数指针:

private FMOD.SOUND_PCMREADCALLBACK pcmreadcallback = new FMOD.SOUND_PCMREADCALLBACK(PCMREADCALLBACK);

Callback used to populate the FMOD sound: 用于填充FMOD声音的回调:

private static FMOD.RESULT PCMREADCALLBACK(IntPtr soundraw, IntPtr data, uint datalen)
{
    unsafe
    {  
        short *stereo16bitbuffer = (short *)data.ToPointer();

        // Populate the 'stereo16bitbuffer' with sound data 
    }

    return FMOD_OK;
}

Code to create the sound that will use the callback: 用于创建将使用回调的声音的代码:

// ...Usual FMOD initialization code here...

FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO();

// You define your required frequency and channels
exinfo.cbsize            = Marshal.SizeOf(exinfo);
exinfo.length            = frequency * channels * 2 * 5; // *2 for sizeof(short) *5 for 5 seconds
exinfo.numchannels       = (int)channels;
exinfo.defaultfrequency  = (int)frequency;
exinfo.format            = FMOD.SOUND_FORMAT.PCM16;
exinfo.pcmreadcallback   = pcmreadcallback;

result = system.createStream((string)null, (FMOD.MODE.DEFAULT | FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_NORMAL), ref exinfo, ref sound);

That should be sufficient to get you going, hope this helps. 那应该足以使您前进,希望这会有所帮助。

If you wish to stream raw data, not PCM data you could achieve this by overriding the FMOD file system. 如果您希望流传输原始数据,而不是PCM数据,则可以通过覆盖FMOD文件系统来实现。 There are two ways to achieve this, the first is by setting the file callbacks in the CreateSoundExInfo structure if this is for one specific file. 有两种方法可以实现此目的,第一种是通过在CreateSoundExInfo结构中设置文件回调(如果这是针对一个特定文件)的。 The second is you can set the file system globally for all FMOD file operations (incase you want to do this with multiple files). 第二个是可以为所有FMOD文件操作全局设置文件系统(如果要对多个文件执行此操作)。

I will explain the latter, it would be trivial to switch to the former though. 我将解释后者,但是切换到前者将是微不足道的。 Refer to the "filecallbacks" FMOD example for a complete example. 有关完整的示例,请参考“文件回调” FMOD示例。

Function pointers: 函数指针:

private FMOD.FILE_OPENCALLBACK  myopen  = new FMOD.FILE_OPENCALLBACK(OPENCALLBACK);
private FMOD.FILE_CLOSECALLBACK myclose = new FMOD.FILE_CLOSECALLBACK(CLOSECALLBACK);
private FMOD.FILE_READCALLBACK  myread  = new FMOD.FILE_READCALLBACK(READCALLBACK);
private FMOD.FILE_SEEKCALLBACK  myseek  = new FMOD.FILE_SEEKCALLBACK(SEEKCALLBACK);

Callbacks: 回调:

private static FMOD.RESULT OPENCALLBACK([MarshalAs(UnmanagedType.LPWStr)]string name, int unicode, ref uint filesize, ref IntPtr handle, ref IntPtr userdata)
{
    // You can ID the file from the name, then do any loading required here
    return FMOD.RESULT.OK;
}

private static FMOD.RESULT CLOSECALLBACK(IntPtr handle, IntPtr userdata)
{
    // Do any closing required here
    return FMOD.RESULT.OK;
}

private static FMOD.RESULT READCALLBACK(IntPtr handle, IntPtr buffer, uint sizebytes, ref uint bytesread, IntPtr userdata)
{
    byte[] readbuffer = new byte[sizebytes];

    // Populate readbuffer here with raw data

    Marshal.Copy(readbuffer, 0, buffer, (int)sizebytes);
    return FMOD.RESULT.OK;
}

private static FMOD.RESULT SEEKCALLBACK(IntPtr handle, int pos, IntPtr userdata)
{
    // Seek your stream to desired position
    return FMOD.RESULT.OK;
}

Implementation: 执行:

// Usual init code here...

result = system.setFileSystem(myopen, myclose, myread, myseek, 2048);
ERRCHECK(result);

// Usual create sound code here...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM