Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ packages:
path: ".."
relative: true
source: path
version: "3.3.3"
version: "3.3.6"
flutter_test:
dependency: "direct dev"
description: flutter
Expand Down
36 changes: 23 additions & 13 deletions example/tests/tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -547,23 +547,33 @@ Future<StringBuffer> testStopFutures() async {

/// Load sample
final currentSound =
await SoLoud.instance.loadAsset('assets/audio/tic-1.wav');
await SoLoud.instance.loadAsset('assets/audio/explosion.mp3');

final random = Random(42);
for (var i = 0; i < 50; i++) {
final handle = await SoLoud.instance.play(currentSound);
output.writeln('$handle started');
await Future<void>.delayed(Duration(milliseconds: random.nextInt(5)));
unawaited(
SoLoud.instance
.stop(handle)
.then((_) => output.writeln('$handle stopped')),
);
}
/// Fast call to `stop` after `play`
var handle = await SoLoud.instance.play(currentSound);
output
..writeln('fast play/stop')
..writeln('$handle started');
unawaited(
SoLoud.instance.stop(handle).then((_) => output.writeln('$handle stopped')),
);

/// Wait a bit so that we can hear a sound to verify it's working as intended.
await delay(500);

/// Schedule a stop and call `stop` after the scheduled time
handle = await SoLoud.instance.play(currentSound);
output
..writeln('\nscheduleStop')
..writeln('$handle started');
SoLoud.instance.scheduleStop(handle, const Duration(milliseconds: 500));
await delay(1000);
unawaited(
SoLoud.instance.stop(handle).then((_) => output.writeln('$handle stopped')),
);

/// Wait a bit.
await delay(1000);

deinit();

if (severeLogs.isNotEmpty) {
Expand Down
11 changes: 10 additions & 1 deletion lib/src/soloud.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,16 @@ interface class SoLoud {
final completer = Completer<void>();
voiceEndedCompleters[handle] = completer;

_controller.soLoudFFI.stop(handle);
// In the case this handle has been ended or stopped by [scheduleStop],
// we should check if it is still valid.
if (!getIsValidVoiceHandle(handle)) {
_log.finest(
() => 'The handle $handle has already been removed by another '
'event like scheduleStop or ended sound.');
completer.complete();
} else {
_controller.soLoudFFI.stop(handle);
}

return completer.future
.timeout(const Duration(milliseconds: 300))
Expand Down
28 changes: 24 additions & 4 deletions src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,23 @@ extern "C"
/// and comes from the audio thread (so on the web, from a different web worker).
FFI_PLUGIN_EXPORT void voiceEndedCallback(unsigned int *handle)
{
bool isHandleFound;
if (player != nullptr)
player->removeHandle(*handle);
{
isHandleFound = player->findByHandle(*handle) != nullptr;
if (isHandleFound)
player->removeHandle(*handle);
else
// If the handle is not found, for sure it is already
// removed by a previous call to `voiceEndedCallback`.
// For example triggering a `stop` in a `Future` after the sound is ended or
// vice versa.
return;
}

// Here the internal flutter_soloud handle, doesn't exist anymore, whether this
// callback is called directly from `stop`, or whether it is called from an
// event in `Soloud::stopVoice_internal (unsigned int aVoice)`.

#ifdef __EMSCRIPTEN__
// Calling JavaScript from C/C++
Expand All @@ -121,7 +136,12 @@ extern "C"
// The `dartVoiceEndedCallback` is not set on Web.
if (dartVoiceEndedCallback == nullptr)
return;
// [n] pointer must be deleted on Dart.
// So, if the handle was already found before (henche the handle is not found), the
// callback to Dart has been already called. If this is the fist time this handle
// is found, the callback to Dart must be called.
if (!isHandleFound)
return;
// [n] pointer must be deleted in Dart.
unsigned int *n = (unsigned int *)malloc(sizeof(unsigned int *));
*n = *handle;
dartVoiceEndedCallback(n);
Expand Down Expand Up @@ -770,10 +790,10 @@ extern "C"
/// [handle]
FFI_PLUGIN_EXPORT void stop(unsigned int handle)
{
if (player.get() == nullptr || !player.get()->isInited() ||
!player.get()->isValidHandle(handle))
Comment on lines -773 to -774
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, why are we no longer checking whether the handle is valid? Does Player::stop() not care?

Oh wait, we checked whether the handle was not valid? And then we stopped it? Sorry, I'm getting confused.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the handle validity is managed by the voiceEndedCallbak. Whether or not it is valid, the callback is called and the SoLoud engine does nothing if the handle doesn't exist.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation!

if (player.get() == nullptr || !player.get()->isInited())
return;
player.get()->stop(handle);
voiceEndedCallback(&handle);
}

/// Stop all handles of the already loaded sound identified by [hash] and dispose it
Expand Down
1 change: 0 additions & 1 deletion src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,6 @@ PlayerErrors Player::play(

void Player::stop(unsigned int handle)
{
removeHandle(handle);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I guess I'd like to see it documented (in comments in this file, ideally) who is responsible for removing the handle (e.g. calling Player::removeHandle()).

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the handle here is now an error because it is now the voiceEndedCallck duty. I have written comments in that callback.

soloud.stop(handle);
}

Expand Down
Binary file modified web/libflutter_soloud_plugin.wasm
Binary file not shown.