playSoundOnTargetChannels method
Plays the given Sound on one of the specified target channels.
sound
: The Sound object to play.targetChannels
: A list of preferred channel IDs. The sound will be played on the first available channel from this list. Ifnull
, all channels are considered.loop
: Whether the sound should loop. Defaults tofalse
.loopStart
: The start time in samples for looping, ifloop
istrue
. Converted to seconds internally using the sound's sample rate. RequiresloopEnd
to also be set.loopEnd
: The end time in samples for looping, ifloop
istrue
. Converted to seconds internally using the sound's sample rate. RequiresloopStart
to also be set.
Returns the channel ID on which the sound is playing, or -1 if the sound could not be played (e.g., sound not ready, retrigger delay not met, or no suitable channel found).
Implementation
int playSoundOnTargetChannels(
Sound sound, {
List<int>? targetChannels,
bool loop = false,
double? loopStart,
double? loopEnd,
}) {
if (audioContext.state == 'suspended') {
audioContext.resume();
}
if (sound.state != LoadingState.ready) {
return -1;
}
if (sound.lastTimePlayed != null) {
final timeSinceLastPlayed = DateTime.now().difference(sound.lastTimePlayed!);
if (timeSinceLastPlayed < sound.retriggerDelay) {
return -1;
}
}
var channelId = obtainFreeChannel(targetChannels);
if (channelId == -1) {
warn("All audio channels are in use. Consider to increase channel count.");
return -1;
}
var channel = _channels[channelId];
if (channel.state != ChannelState.stopped && channel.sourceNode != null) {
channel.sourceNode!.onended = null;
try {
channel
..sourceNode!.stop(0)
..state = ChannelState.stopped;
} catch (e) {
//
}
}
channel
..sound = sound
..loop = loop
..sourceNode = audioContext.createBufferSource()
..sourceNode!.buffer = sound.buffer
..sourceNode!.playbackRate.value = channel.rate
..sourceNode!.loop = loop
..sourceNode!.connect(channel.pannerNode);
if (channel.sourceNode!.loop) {
if (loopStart != null && loopEnd != null && loopEnd > loopStart) {
double hz = sound.buffer?.sampleRate ?? 44100;
loopStart = loopStart / hz;
loopEnd = loopEnd / hz;
} else {
loopStart = 0;
loopEnd = channel.sourceNode!.buffer!.duration;
}
channel.sourceNode!
..loopStart = loopStart
..loopEnd = loopEnd;
}
channel.sourceNode!.onended =
(Event event) {
channel
..sourceNode = null
..state = ChannelState.stopped;
}.toJS;
channel
..offset = 0
..startTime = audioContext.currentTime
..sourceNode?.start(0)
..state = ChannelState.playing;
sound.lastTimePlayed = DateTime.now();
return channelId;
}