Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio issue #3367

Open
1 task
RawadZogheib opened this issue Nov 16, 2024 · 7 comments
Open
1 task

Audio issue #3367

RawadZogheib opened this issue Nov 16, 2024 · 7 comments
Labels

Comments

@RawadZogheib
Copy link

What happened?

When I remove the audio the game a fast and all is functioning well, but when I add the audio I have 2 issue:

  1. If I'm in a WhatsApp call the game have a bad functionality (this issue is not accruing if I remove the audio plugin)
  2. I we play 5 round or more the game start lagging and having low FPS (this issue is not accruing if I remove the audio plugin)

I think there is an issue with the dispose in this plugin after checking the code!

What do you expect?

a solution for the bug? :')

How can we reproduce this?

I guess if there is a good dispose for the audio after it's played the issue should be solved because this issue isn't available on AudioPlayer!

What steps should take to fix this?

.

Do have an example of where the bug occurs?

no

Relevant log output

There is no exception!

Execute in a terminal and put output into the code block below

flutter doctor -v
[✓] Flutter (Channel stable, 3.24.4, on macOS 13.7.1 22H221 darwin-x64, locale en-LB)
• Flutter version 3.24.4 on channel stable at /Users/rawadzogheib/Documents/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 603104015d (3 weeks ago), 2024-10-24 08:01:25 -0700
• Engine revision db49896cf2
• Dart version 3.5.4
• DevTools version 2.37.3

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at /Users/rawadzogheib/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 21.0.3+-79915915-b509.11)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15C500b
• CocoaPods version 1.15.2

[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2024.2)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.3+-79915915-b509.11)

[✓] VS Code (version 1.94.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.98.0

[✓] Connected device (2 available)
• macOS (desktop) • macos • darwin-x64 • macOS 13.7.1 22H221 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 131.0.6778.69

[✓] Network resources
• All expected network resources are available.

• No issues found!

Affected platforms

Android, iOS

Other information

import 'dart:math';

import 'package:flame_audio/flame_audio.dart';
import 'package:kung_fu_cat/locale/get_storage_helper.dart';
import 'package:kung_fu_cat/remote/firebase/crud_firestore.dart';

class AudioHelper {
  static final AudioHelper _singleton = AudioHelper._internal();

  factory AudioHelper() {
    return _singleton;
  }

  AudioHelper._internal() {
    _musicVolume = GetStorageHelper().getMusicVolume();
    _gameVolume = GetStorageHelper().getGameVolume();
  }

  double _musicVolume = 1.0;
  double _gameVolume = 1.0;

  double get musicVolume => _musicVolume;

  double get gameVolume => _gameVolume;

  set musicVolume(double value) {
    _musicVolume = value;
    GetStorageHelper().setMusicVolume(musicVolume: _musicVolume);
  }

  set gameVolume(double value) {
    _gameVolume = value;
    GetStorageHelper().setGameVolume(gameVolume: _gameVolume);
  }

  AudioPool? clickSound;
  AudioPool? slicingSound0;
  AudioPool? slicingSound1;
  AudioPool? slicingSound2;
  AudioPool? slicingSound3;
  AudioPool? coinThrowSoundSound;
  AudioPool? bombThrowSoundSound;
  AudioPool? gameOverBombSound;
  AudioPool? chooseGameSwipe;

  Future<void> initAudio() async {
    try {
      FlameAudio.bgm.initialize();
      await FlameAudio.audioCache.loadAll([
        'background_music/background_song.mp3',
        'button_sound/button_click_sound.mp3',
        'slicing_sound/slicing_sound0.mp3',
        'slicing_sound/slicing_sound1.mp3',
        'slicing_sound/slicing_sound2.mp3',
        'slicing_sound/slicing_sound3.mp3',
        'coin_sound/coin_throw_sound.mp3',
        'bomb_sound/bomb_throw_sound.mp3',
        'loading_game/countdown_one.mp3',
        'loading_game/countdown_two.mp3',
        'loading_game/countdown_three.mp3',
        'loading_game/countdown_go.mp3',
        'loading_game/countdown_end_sound.mp3',
        'golden_cat_sound/golden_cat_throw_sound.mp3',
        'golden_cat_sound/thunder_sound.mp3',
        'background_music/golden_cat_song.mp3',
        'game_view/game_over_via_bomb_sound.mp3',
        'game_view/game_over_via_fruit_sound.mp3',
        'game_view/next_level_sound.mp3',
        'choose_game_view/choose_game_swipe.mp3',
        'waiting_room/opponent_found_sound.mp3',
        'waiting_room/prize_pool_sound.mp3',
        'waiting_room/start_multiplayer_game_sound.mp3',
        'waiting_room/waiting_opponent_sound.mp3',
      ]);
      await iniAudioPool();
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio First Init");
    }
  }

  Future<void> playBackgroundMusic() async {
    if (FlameAudio.bgm.isPlaying) {
      try {
        await FlameAudio.bgm.stop();
      } catch (e) {
        _exception(
            exception: e.toString(),
            errorDescription: "On Audio Stop Background Music");
      }
    }
    try {
      await FlameAudio.bgm
          .play('background_music/background_song.mp3', volume: _musicVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Background Music");
    }
  }

  Future<void> playWaitingOpponentBackgroundMusic() async {
    if (FlameAudio.bgm.isPlaying) {
      try {
        await FlameAudio.bgm.stop();
      } catch (e) {
        _exception(
            exception: e.toString(),
            errorDescription: "On Audio Stop WaitingRoom Background Music");
      }
    }
    try {
      await FlameAudio.bgm
          .play('waiting_room/waiting_opponent_sound.mp3', volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play WaitingRoom Background Music");
    }
  }

  Future<void> playGoldenCatThrowMusic() async {
    if (FlameAudio.bgm.isPlaying) {
      try {
        await FlameAudio.bgm.stop();
      } catch (e) {
        _exception(
            exception: e.toString(),
            errorDescription: "On Audio Stop Golden Cat Background Music1");
      }
    }
    try {
      await FlameAudio.play('golden_cat_sound/golden_cat_throw_sound.mp3',
          volume: _gameVolume);
      await FlameAudio.bgm
          .play('background_music/golden_cat_song.mp3', volume: _musicVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Golden Cat Background Music1");
    }
  }

  Future<void> playGoldenCatBackgroundMusic() async {
    if (FlameAudio.bgm.isPlaying) {
      try {
        await FlameAudio.bgm.stop();
      } catch (e) {
        _exception(
            exception: e.toString(),
            errorDescription: "On Audio Stop Golden Cat Background Music2");
      }
    }
    try {
      await FlameAudio.bgm
          .play('background_music/golden_cat_song.mp3', volume: _musicVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Golden Cat Background Music2");
    }
  }

  Future<void> pauseBackgroundMusic() async {
    try {
      if (FlameAudio.bgm.isPlaying) {
        await FlameAudio.bgm.pause();
      }
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Pause Background Music");
    }
  }

  Future<void> stopBackgroundMusic() async {
    try {
      await FlameAudio.bgm.stop();
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Stop Background Music");
    }
  }

  Future<void> resumeBackgroundMusic() async {
    try {
      await FlameAudio.bgm.resume();
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Resume Background Music");
    }
  }

  Future<void> playChooseGameSwipeSound() async {
    try {
      await chooseGameSwipe!.start(volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Game Choose Swipe");
    }
  }

  Future<void> playOpponentFoundSound() async {
    try {
      await FlameAudio.play('waiting_room/opponent_found_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Opponent Found");
    }
  }

  Future<void> playPrizePoolSound() async {
    try {
      await FlameAudio.play('waiting_room/prize_pool_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Prize Pool");
    }
  }

  Future<void> playStartMultiplayerGameSound() async {
    try {
      await FlameAudio.play('waiting_room/start_multiplayer_game_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Game Multiplayer");
    }
  }

  Future<void> playCoinThrowSound() async {
    try {
      await coinThrowSoundSound!.start(volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio Play Coin");
    }
  }

  Future<void> playBombSound() async {
    try {
      await bombThrowSoundSound!.start(volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio Play Bomb");
    }
  }

  Future<void> playSelectSwordSound() async {
    try {
      await FlameAudio.play('locker_view/select_sword_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Select Sword");
    }
  }

  Future<void> playSelectCatSound() async {
    try {
      await FlameAudio.play('locker_view/select_cat_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Select Cat");
    }
  }

  Future<void> playGameOverBombSound() async {
    try {
      await gameOverBombSound!.start(volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play GameOver Bomb");
    }
  }

  Future<void> playGameOverFruitSound() async {
    try {
      await FlameAudio.play('game_view/game_over_via_fruit_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play GameOver Fruit");
    }
  }

  Future<void> playNextLevelSound() async {
    try {
      await FlameAudio.play('game_view/next_level_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Next Level");
    }
  }

  Future<void> playClickSound() async {
    try {
      await clickSound!.start(volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio Play Click");
    }
  }

  /// Loading Game
  Future<void> playCountDownOneSound() async {
    try {
      await FlameAudio.play('loading_game/countdown_one.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Count Down One");
    }
  }

  Future<void> playCountDownTwoSound() async {
    try {
      await FlameAudio.play('loading_game/countdown_two.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Count Down Two");
    }
  }

  Future<void> playCountDownThreeSound() async {
    try {
      await FlameAudio.play('loading_game/countdown_three.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Count Down Thre");
    }
  }

  Future<void> playCountDownGoSound() async {
    try {
      await FlameAudio.play('loading_game/countdown_go.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Count Down Go");
    }
  }

  Future<void> playCountDownEndSoundSound() async {
    try {
      await FlameAudio.play('loading_game/countdown_end_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Count Down End");
    }
  }

  Future<void> playThunderSound() async {
    try {
      await FlameAudio.play('golden_cat_sound/thunder_sound.mp3',
          volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio Play Thunder");
    }
  }

  Future<void> playRandomSlicingSound() async {
    try {
      final int rand = Random().nextInt(3);
      if (rand == 0) await slicingSound0!.start(volume: _gameVolume);
      if (rand == 1) await slicingSound1!.start(volume: _gameVolume);
      if (rand == 2) await slicingSound2!.start(volume: _gameVolume);
      if (rand == 3) await slicingSound3!.start(volume: _gameVolume);
    } catch (e) {
      _exception(
          exception: e.toString(),
          errorDescription: "On Audio Play Random Slicing");
    }
  }

  Future<void> iniAudioPool() async {
    await disposeAudioPool();
    try {
      clickSound = await FlameAudio.createPool(
          'button_sound/button_click_sound.mp3',
          maxPlayers: 5);
      chooseGameSwipe = await FlameAudio.createPool(
          'choose_game_view/choose_game_swipe.mp3',
          maxPlayers: 10);
    } catch (e) {
      _exception(exception: e.toString(), errorDescription: "On Audio Init");
    }
    await iniGameAudioPool();
  }

  Future<void> iniGameAudioPool() async {
    await disposeGameAudioPool();
    try {
      slicingSound0 = await FlameAudio.createPool(
          'slicing_sound/slicing_sound0.mp3',
          maxPlayers: 5);
      slicingSound1 = await FlameAudio.createPool(
          'slicing_sound/slicing_sound1.mp3',
          maxPlayers: 5);
      slicingSound2 = await FlameAudio.createPool(
          'slicing_sound/slicing_sound2.mp3',
          maxPlayers: 5);
      slicingSound3 = await FlameAudio.createPool(
          'slicing_sound/slicing_sound3.mp3',
          maxPlayers: 5);
      coinThrowSoundSound = await FlameAudio.createPool(
          'coin_sound/coin_throw_sound.mp3',
          maxPlayers: 5);
      bombThrowSoundSound = await FlameAudio.createPool(
          'bomb_sound/bomb_throw_sound.mp3',
          maxPlayers: 5);
      gameOverBombSound = await FlameAudio.createPool(
          'game_view/game_over_via_bomb_sound.mp3',
          maxPlayers: 5);
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio Game Init");
    }
  }

  Future<void> disposeAudioPool() async {
    try {
      if (clickSound != null) await clickSound!.dispose();
      if (chooseGameSwipe != null) await chooseGameSwipe!.dispose();
      clickSound = null;
      chooseGameSwipe = null;
    } catch (e) {
      _exception(exception: e.toString(), errorDescription: "On Audio Dispose");
    }
  }

  Future<void> disposeGameAudioPool() async {
    try {
      if (slicingSound0 != null) await slicingSound0!.dispose();
      if (slicingSound1 != null) await slicingSound1!.dispose();
      if (slicingSound2 != null) await slicingSound2!.dispose();
      if (slicingSound3 != null) await slicingSound3!.dispose();
      if (coinThrowSoundSound != null) await coinThrowSoundSound!.dispose();
      if (bombThrowSoundSound != null) await bombThrowSoundSound!.dispose();
      if (gameOverBombSound != null) await gameOverBombSound!.dispose();
      slicingSound0 = null;
      slicingSound1 = null;
      slicingSound2 = null;
      slicingSound3 = null;
      coinThrowSoundSound = null;
      bombThrowSoundSound = null;
      gameOverBombSound = null;
    } catch (e) {
      _exception(
          exception: e.toString(), errorDescription: "On Audio Game Dispose");
    }
  }

  void _exception(
      {required String exception, required String errorDescription}) {
    final CRUDFirestore crudFirestore = CRUDFirestore();
    crudFirestore.exception(
        errorCode: "44974",
        exception: exception,
        showSelectedGameId: true,
        errorDescription: errorDescription);
  }
}

Are you interested in working on a PR for this?

  • I want to work on this
@spydon
Copy link
Member

spydon commented Nov 16, 2024

Can you check in the Flutter DevTools if you're having more audioplayers instances than you expect?
Other than that I would try to only play background sounds to see if it is the pools that are the problem, or the other way around.

@RawadZogheib
Copy link
Author

RawadZogheib commented Nov 16, 2024

Hello, @spydon, thank you for responding,

DevTools I can see all the flame Component but I can't see the AudioPool.

But I think "FlameAudio.bgm.initialize();" is called only once on the begin of the game and never disposed, because I always have background music in the game, and it's initialized in the First App load after signing.

I only use bgm.play(); and bam.stop() to switch background music?

It can be the issue?

@dipanshparmar
Copy link

I also experience a similar issue. This might work as a reproducible code but there is not going a lot here:

import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flame/components.dart';
import 'package:flame_audio/flame_audio.dart';

void main() {
  runApp(GameWidget(game: MyGame()));
}

class MyGame extends FlameGame {
  @override
  FutureOr<void> onLoad() {
    world.add(FpsComponent());
    world.add(FpsTextComponent());
    add(
      TimerComponent(
        period: .05,
        onTick: () {
          FlameAudio.play('audio.mp3');
        },
        repeat: true,
      ),
    );
  }
}

After an audio is played, I'm expecting that instance to be disposed but it doesn't seem like they are getting disposed and just piling up. The audio that is being played is only around .2 second long. Why do I have these many instances?

output

Also, I had another project where I had some components. While playing the audio over time, the fps was dropping to 5-6 fps, eventually crashing the game.
I'm not sure how is this supposed to work so I don't know if this is even a bug. Are we supposed to dispose manually?

@spydon
Copy link
Member

spydon commented Dec 6, 2024

Use the AudioPool class for such cases.
Or the flutter_soloud package.

@dipanshparmar
Copy link

So this is the correct behavior while playing the audio with FlameAudio directly?

@spydon
Copy link
Member

spydon commented Dec 6, 2024

So this is the correct behavior while playing the audio with FlameAudio directly?

The play method gives back a reusable AudioPlayer, so the user has to call dispose on that one when they don't want to use it anymore.

@dipanshparmar
Copy link

The play method gives back a reusable AudioPlayer, so the user has to call dispose on that one when they don't want to use it anymore.

That makes sense! Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants