PlayOneShot returns false for isPlaying

It seems that if you play an audio clip with

audio.PlayOneShot(clipName);

and then if you trying to check if the audio.isPlaying it returns false even though the audio is obviously playing. When I use audio.Play, then isPlaying returns True as expected.

Am I missing anything? is there any way around this? as I do need to use PlayOneShot so that I can follow it with a delayed Play.

5 Answers

5

I worked around this by writing my own isPlaying() method while wrapping a class around my audioclips. Hope it helps!

private float startTime;

private void PlayOneShot(AudioClip clip, float volume)
{
	audioSource.PlayOneShot(clip, volume);
	startTime = Time.time;
}

public bool isPlaying()
{
	if((Time.time - startTime) >= clip.length)
		return false;
	return true;
}

its working awesome answer!!!

–

Great Answer

–

Did the same like this: audioSource.PlayOneShot(clip); playTimeout = Math.Max(Time.time + clip.length, playTimeout); and to check: public bool isPlaying { get { return Time.time <= playTimeout; } }

–

This fixed the issue I was having when checking for a single or double click, synced animations with audio perfectly!

–

In fact, PlayOneShot doesn’t affect isPlaying. It starts the sound and gets ready to another one, even if the first is still playing. Play can start a new sound too, but the prior sound is stopped if still playing.

You can work around this by emulating a version of PlayOneShot based on Play, like this:

var sound1:AudioClip;
var sound2:AudioClip;
var sound3:AudioClip;
 .
function playSound(sound:AudioClip, vol:float){
  audio.clip = sound;
  audio.volume = vol;
  audio.Play();
}
 .
// play a sound this way:
  playSound(sound2,0.8);
 .

That's not really a workaround for PlayOneShot, because you can't play multiple overlapping AudioClips through one AudioSource (which you can with the PlayOneShot and I guess that's the reason for it to exist).

–

Not always. If your script is used on multiple objects, they would still use the old script. With the method above, the components on your objects and préfabs will automatically be updated to use the newly named script instead.

–

I don’t have an answer per se, but I can confirm the behavior you describe.

I’m tempted to say it’s a bug, and might be worth reporting as such (it seems that the ‘is playing’ property should be useable even when the sound was played using PlayOneShot()). However, it may be the intended behavior (I’m not sure).

[Edit: Based on what aldonaletto says, I guess it’s the intended behavior.]

[Edit 2: Just tried it out, and it looks like it is indeed the correct/intended behavior. I have to admit I didn’t know PlayOneShot() functioned that way (the docs don’t mention it), but I suppose it makes sense that it does.]

Mike, looks like you're confusing PlayOneShot() with PlayClipAtPoint(). I can't say what exactly PlayOneShot() does behind the scenes, but if you invoke PlayOneShot() and watch the hierarchy pane, you'll see that no game object is created (at least none that's visible to the user). PlayClipAtPoint() behaves as you describe, but that's a different function. [Looks like Mike deleted his comment...? Anyway, I'll leave this here just as additional clarification.]

–

Another approach I am using is checking the outputlevel of the audiosource. I read somewhere that getoutputdata is fairly cheap. + it works with playOneShot.

_audiossource.GetOutputData(audioSamples, 0);
            float sum = 0;

            for (int i = 0; i < audioSamples.Length; i++)
            {
                sum += audioSamples _* audioSamples*; // sum squared samples*_

}

var rmsValue = Mathf.Sqrt(sum / audioSamples.Length); // rms = square root of average
var dbValue = 20 * Mathf.Log10(rmsValue / 0.1F); // calculate dB

bool playing = false;

if (dbValue != Mathf.Infinity && dbValue != Mathf.NegativeInfinity)
playing = true;

Nice, didn't know about GetOutputData… might be interesting for other applications as well!

–

using UnityEngine;

public static class AudioSourceExtensions
{
    public static bool IsPlayingOneShot(this AudioSource audioSource) {
        float[] audioSamples = new float[256];

        audioSource.GetOutputData(audioSamples, 0);
        float sum = 0;

        for (int i = 0; i < audioSamples.Length; i++) {
            sum += audioSamples _* audioSamples*; // sum squared samples*_

}

var rmsValue = Mathf.Sqrt(sum / audioSamples.Length); // rms = square root of average
var dbValue = 20 * Mathf.Log10(rmsValue / 0.1F); // calculate dB

return (dbValue != Mathf.Infinity && dbValue != Mathf.NegativeInfinity);
}
}

This is an extension method, which as it’s name says, magically extends the original AudioSource class.
To use it just:
1. Create a file named AudioSourceExtensions and paste the class there.
2. Call it like audiosource.IsPlayingOneShot()