C#FMOD实时播放流

时间:2010-08-08 20:36:38

标签: c# streaming audio fmod

我正在尝试实时播放一个流(我从一个nexternal源继续向我发送数据)但无论FMOD在第一个加载的块之后不想继续播放,它似乎是在播放之前复制内存流/解码它,然后在播放它时不再使用我的流。

我正在使用以下内容来播放我的信息流:

        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);

但无论如何,它只会在调用playSound时播放流中的数据量。

有谁知道如何实时修改缓冲区?流开始播放后......?

2 个答案:

答案 0 :(得分:2)

我建议你查看FMOD附带的“usercreatedsound”示例,它应该做你需要的。

基本思想是定义您希望在CreateSoundExInfo结构中播放的声音的属性,并为其提供回调,您可以使用这些回调从任何地方加载/流式传输数据。

功能指针:

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

用于填充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;
}

创建将使用回调的声音的代码:

// ...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);

这应该足以让你前进,希望这会有所帮助。

答案 1 :(得分:1)

如果您希望流式传输原始数据,而不是PCM数据,则可以通过覆盖FMOD文件系统来实现此目的。有两种方法可以实现这一点,第一种方法是在CreateSoundExInfo结构中设置文件回调(如果这是针对一个特定文件)。第二种是您可以为所有FMOD文件操作全局设置文件系统(如果您想对多个文件执行此操作)。

我将解释后者,但转换到前者是微不足道的。有关完整示例,请参阅“filecallbacks”FMOD示例。

函数指针:

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);

回调:

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;
}

实现:

// Usual init code here...

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

// Usual create sound code here...