- Home /
OnAudioRead Buffer Changing Sizes?
For a variety of reasons on my project (the main one is having over 10000+ audio assets), I'm loading ogg files into memory from an external source, and using the NVorbis library to stream samples to unity through the callback functions available using AudioClip.Create. The code looks roughly like this:
AudioClip InitClip(byte[] inbytes)
{
stream = new MemoryStream(inbytes);
vorbis = new VorbisReader(stream, true);
samplecount = (int) (vorbis.SampleRate*vorbis.TotalTime.TotalSeconds); //probably close enough
return AudioClip.Create("clip", samplecount, vorbis.Channels, vorbis.SampleRate, false, true, OnAudioRead, OnAudioSetPosition);
}
void OnAudioRead(float[] data)
{
var f = new float[data.Length];
vorbis.ReadSamples(f, 0, data.length);
for (int i = 0; i < data.Length; i++)
{
data[i] = f[i];
}
}
void OnAudioSetPosition(int newPosition)
{
vorbis.DecodedTime = new TimeSpan(0); //Only used to rewind the stream, we won't be seeking
}
This actually works pretty well, in most cases it streams properly. I simply attach it to an AudioSource and it's good. The reason for the for loop in the OnAudioRead section is because while OnAudioRead is supposed to be passed a float[], it's actually getting a Single[][], which I can't pass directly to NVorbis. Copying over the buffer like this seems to resolve the issue.
Main problem though is that periodically I will receive error messages and garbled segments of audio. The error is "System.IndexOutOfRangeException: Array index is out of range. at AudioAsset.OnAudioRead (System.Single[] data)". The error to me doesn't make much sense, because there shouldn't be any way the index could be invalid.
So I rigged up the following code within OnAudioRead to test it.
var length = data.length;
vorbis.ReadSamples(f, 0, data.length);
var length2 = data.length;
if(length != length2)
Debug.LogError("Warning! Buffer size changed!? Was " + length + ", now is " + length2);
Running this code, lo and behold, it would sometimes generate the error. I would get this in my error log, interspersed with IndexOutOfRangeExceptions.
Warning! Buffer size changed!? Was 928, now is 4096
Warning! Buffer size changed!? Was 928, now is 4096
Warning! Buffer size changed!? Was 928, now is 4096
Warning! Buffer size changed!? Was 4096, now is 2512
Warning! Buffer size changed!? Was 2512, now is 4096
So the question is, why in the world would the length of the buffer be changing while I'm reading? I can't make any sense of it. In order to rule out NVorbis causing the issue, I did another test, excluding it entirely from the OnAudioRead function.
public void OnAudioRead(Single[] data)
{
for (var i = 0; i < data.length; i++)
data[i] = Mathf.Sin((float)i/100);
}
Still periodically receiving IndexOutOfRangeExceptions. There's so little documentation on these functions that there's nothing really to help me figure out why it's not working. Locking doesn't seem to help either.
Anyone have any clue?
Probably a typo, but I've never heard of OnAudioRead, OnAudioFilterRead is what I use. Never saw it changing data.Length, though...
Sorry, I guess it's not too clear. It's not specifically called OnAudioRead, it's simply a callback function for AudioClip.Create to read audio data. It doesn't have to have that name, but it's referred to it like that in the documentation.
I tried using OnAudioFilterRead briefly but had issues with the frequency being screwy. I guess I can try that again.
Hey Doddler, Indeed, the callbacks you can setup from AudioClip.Create are unreliable. Use OnAudioFilterRead for any kind of reliable access to lower level audio, or accept a higher latency and less flexibility and work with AudioCLip.GetData / SetData. Hope it helps!
Answer by Doddler · Jul 23, 2013 at 11:02 PM
gregzo: Thanks for the tip, I'm trying to use OnAudioFilterRead but running into an issue where the audio is a bit distorted. I imagine this is because my input stream is 44100 and unity wants to use 48000 (even if the clip is set to 44100). Is there an easy way to match this, or do I need to figure out the conversion necessary?
Edit: AudioSettings.outputSampleRate = 44100; will set the output sample rate. I'm good! OnAudioFilterRead will work in place of the broken callbacks.
An update incase anyone stumbles upon this issue. OnAudioRead now works, but at present AudioClip.Create will crash on mac and linux if strea$$anonymous$$g is enabled. Two steps forward, one step back. At least it's progress!
Your answer
Follow this Question
Related Questions
How do I stream audio from disk? 0 Answers
Sound creation using WAV. files 1 Answer
Stream music in Unity mobile 0 Answers
Problem with streaming audio and play in trigger area 0 Answers