Cc.audioEngine - how to detect when sound effect finish playing?

Hello,
Sorry for dummy question, but I confused… I can’t find finish playing callback. How to detect when sound effect finish playing?
Cocos2d-JS v3.13

Hi @flahhi

There’s never such thing as a dumb question… :grinning: Have you taken a look here:

http://cocos2d-x.org/docs/api-ref/creator/v1.1.2/classes/audioEngine.html

God Bless…

Sincerely,

Sunday

1 Like

thanks :smile:
Sure, I looked there, but haven’t seen something like “on complete callback”…

Hi @flahhi

How about:

isMusicPlaying ( ) Boolean

Whether the music is playing.
returns:
type: Boolean

If is playing return true,or return false.
examples:

//example
if (cc.audioEngine.isMusicPlaying()) {
cc.log(“music is playing”);
}
else {
cc.log(“music is not playing”); – sound effect finish playing???
}

God Bless…

Sincerely,

Sunday

This is for music and is not for sound effects. If be more precise - I have background music cc.audioEngine.playMusic and sound effect cc.audioEngine.playEffect. When sound effect start playing I reduce music volume. When sound effect finished playing I want return music volume to default value.
I added workaround: scheduleOnce(backVolume, effectLength) but it’s not good solution. I want to know when effect finished playing by code, without any hacks.

It’s Simple you have to use a runAction with cc.sequence

this.playSoundAction=cc.sequence(cc.delayTime(0), cc.callFunc(function () {
cc.audioEngine.setMusicVolume(0.5); // Here reduce your Bg Volume
cc.audioEngine.playEffect(res.yourSound);
},
cc.callFunc(function () {
cc.audioEngine.setMusicVolume(1); // Here make Your Bg sound to normal
}, this))
this.player.runAction(this.playSoundAction);

Hope this helps You!

1 Like

Hi @hemanthgatadi

Can this also be applied to isMusicPlaying() cause I have the following:

gamerandommusic:{
default:[],
url:[cc.AudioClip]
}

PlayRandMusic:function(){
this.randmusic = Math.floor(Math.random() * 3) + 0;
cc.audioEngine.playMusic(this.gamerandommusic[this.randmusic]);
},

RandMusicFinish:function(){
if (cc.audioEngine.isMusicPlaying()){
cc.log(“music is playing”);
}
else{
cc.log(“music is off”);
this.PlayRandMusic();
}},

I can see via log when music starts playing, but when it finishes, I gave it a method to call, which is the same this.PlayRandMusic(), and it doesn’t start again, maybe I need to reset? Would appreciate any help you can offer…Thanks and God Bless…

Sincerely,

Sunday

Hi,

Anybody has a solution for the above, I don’t want to resort to this.schedule if I can use isMusicPlaying method……Would appreciate any help…Thanks and God Bless…

Sincerely,

Sunday

Thank you for your response @hemanthgatadi . But it is not working for me…
(please take a look on questions in comments)

cc.sequence(
	cc.delayTime(0), // do nothing?
	cc.callFunc(function () {
		cc.audioEngine.setMusicVolume(0.5); 
		cc.audioEngine.playEffect(res.yourSound);
	}),
	cc.callFunc(function () {
		// back sound volume, 
		//but didn't wait until effect complete playing...
		cc.audioEngine.setMusicVolume(1); 
	})
)

It works in this way

cc.sequence(
	cc.callFunc(function () {
		cc.audioEngine.setMusicVolume(0.5); 
		cc.audioEngine.playEffect(res.mySound);
	}),
	cc.delayTime(soundLength), // I need know length of every sound by hardcode...
	cc.callFunc(function () {
		cc.audioEngine.setMusicVolume(1); 
	})
)

Or it is the same (my dirty schedule method witch I mentioned before)

...
cc.audioEngine.setMusicVolume(0.5);
cc.director.getScheduler().schedule(function () {
	cc.audioEngine.setMusicVolume(1); 
}, this, soundLength, 0, 0, false);
...

But in both methods we need to know the sound lenght

Hello @luke2125
When RandMusicFinish method is fired?

Hi @flahhi

I have the following:

onLoad: function () {
this.count = 0;
this.PlayRandMusic();
this.RandMusicFinish();
this.MusicOnOffPress();
},

Thanks…God Bless…

Sincerely,

Sunday

So, of course you will have only “music is playing” log in this case.
If I’m not mistaken - you want to start the new random sound playback immediately after the previous sound.
I doubt that you can do it using isMusicPlaying() only. Try to use schedule or runAction from examples above.
Or something like this, with game loop:

onLoad: function () {
	this.scheduleUpdate();
	this.PlayRandMusic();
},

update: function(dt) {
	this.RandMusicFinish();
}

But it is so expensive and performance will suffer a little bit.

Hi @flahhi

Thanks for explanation and suggestion… :smiley: The thing I don’t understand, is that why it can’t be done with isMusicPlaying? Is this an API shortfall that I need to resort to somewhat alternative ways and using other methods to accomplish the task at hand…Or maybe it’s just the way I set it up…? I’ll look into this.schedule and runaction and see what I come up with…Thanks again for the help…God Bless…

Sincerely,

Sunday

Hey @luke2125, you are welcome :wink:

isMusicPlaying method has simple realization. It just return boolean value. If music is playing return true,or return false otherwise. Unfortunately this function isn’t know when your music is finished. In your example you fired RandMusicFinish when application started (in onLoad function). So isMusicPlaying function just return your music status on the application beginning.
If you need start music again after previous completion you should use schedule or other “hacks”. It seems cocos hasn’t any special build-in api for handling sound completion. I created this topic to find them, but it looks like nobody knows. I conclude that there is no easy solution for this topic.

Hi @flahhi

Thanks for the explanation… :grinning: I just went ahead and did the background music on 1 clip, and sequence, instead of using this.schedule or other method…I’m trying to keep it simple…I think in my opinion, the weakest part of Cocos Creator, is the Sound / Music API, hopefully, it will improve in the near future…By any chance do you think you can offer some advice on the following:

Thanks again for you help…God Bless… :smiley:

Sincerely,

Sunday

Sorry, I have never used cocos creator, and I have no ideas for this issue.

Hi @flahhi

Ok, Thanks for the help… :smile: God Bless…

Sincerely,

Sunday

I hope this answered can help…

first to check the audio when finished, we must know how long the durrations of the sound/audio… for example i used 7 seccound from my audio…

And then… in my class i create “CallFunc” to have an some action :
Example:

	auto voiceFinish = CallFunc::create([this]() {   //create callfunc "voiceFinish"
        log("Voice is end");  // this is an action when voice finish is call you can put any action of this area
});

after that, i use “DelayTime” to waiting the audio finished:
Example :
float delayduration = 7; //the duration of voice (in seccound)
this->runAction(Sequence::create(DelayTime::create(delayduration), voiceFinish, nullptr)); //after dellay durration is call after that the voiceFinish is call to.

so yo can try this code

auto voiceFinish = CallFunc::create([this]() { 
log("Voice is end");  
});
        
float delayduration = 7;
this->runAction(Sequence::create(DelayTime::create(delayduration), voiceFinish, nullptr));

Urahh! We now have the setfinishcallback:

cc.audioEngine.setFinishCallback(musicId, function () {});

http://docs.cocos.com/creator/api/en/classes/audioEngine.html#setfinishcallback

1 Like