开发者

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.

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 wh开发者_JS百科at, it only plays the amount of data that is in the stream at the point of calling 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.

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.

Function pointer:

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

Callback used to populate the FMOD sound:

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. 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. The second is you can set the file system globally for all FMOD file operations (incase you want to do this with multiple files).

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.

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...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜