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 becomes choppy when in the background #87

Open
ntatko opened this issue Jan 7, 2022 · 4 comments
Open

Audio becomes choppy when in the background #87

ntatko opened this issue Jan 7, 2022 · 4 comments

Comments

@ntatko
Copy link

ntatko commented Jan 7, 2022

I'm running soundpool: ^2.2.0 on flutter 2.8.1.

WidgetsBinding.instance?.addObserver(this); is used to keep the event loop running in the background. I'm using a set of recursive timers that call one another to make the sound play, in the foreground and the background.

Untitled.mp4

Looking for some insight. Lemme know what I can do to make this stop, eh?

@ukasz123
Copy link
Owner

@ntatko, can you provide a minimal example showing the problem? I don't have idea on how to reproduce the issue.

@ntatko
Copy link
Author

ntatko commented Jan 13, 2022

Yeah, here's a simple widget that would have this effect - simple being a relative word. My implementation is a bit more complex, but this should hit the main points.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:soundpool/soundpool.dart';
import 'package:flutter/services.dart';

class BreatheBar extends StatefulWidget {
  const BreatheBar({Key? key}) : super(key: key);

  @override
  _BreathBarState createState() => _BreathBarState();
}

class _BreathBarState extends State<BreatheBar> with WidgetsBindingObserver {
  Timer? backgroundTimer;
  late Map<String, Map<String, int>> soundIds;
  Soundpool pool = Soundpool.fromOptions(
      options: const SoundpoolOptions(
          streamType: StreamType.alarm,
          iosOptions: SoundpoolOptionsIos(
              audioSessionCategory: AudioSessionCategory.ambient)));

  void waitingPlaySound() {
    setState(() {
      backgroundTimer = Timer(const Duration(seconds: 5), () {
        playSound(pool, soundIds);
        waitingPlaySound();
      });
    });
  }

  @override
  void initState() {
    loadSounds(pool).then((Map<String, Map<String, int>> codes) {
      soundIds = codes;
    }).then((_) {
      waitingPlaySound();
    });
    WidgetsBinding.instance?.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        padding: const EdgeInsets.all(30),
        child: const Text("Playing a sound every 5 seconds"));
  }
}

Map<String, Map<String, String>> sounds = {
  'Notify': {
    'inhale': 'assets/sounds/notify_inhale.mp3',
    'exhale': 'assets/sounds/notify_exhale.mp3'
  }
};

Future<Map<String, Map<String, int>>> loadSounds(Soundpool pool) async {
  Map<String, Map<String, int>> loadedSounds = {};
  sounds.forEach((key, value) async {
    int inId =
        await rootBundle.load(value['inhale']!).then((ByteData soundData) {
      return pool.load(soundData);
    });
    int outId =
        await rootBundle.load(value['exhale']!).then((ByteData soundData) {
      return pool.load(soundData);
    });
    loadedSounds[key] = {'inhale': inId, 'exhale': outId};
  });
  return loadedSounds;
}

void playSound(Soundpool pool, Map<String, Map<String, int>> loaded) {
  pool.play(loaded['Notify']!['inhale']!);
}

@ukasz123
Copy link
Owner

Thank you for the sample.

Unfortunately I could not reproduce the problem using the code you provided. I tried both on simulator and real device. I noticed that on real device (iPhone SE 2020) the sound was silenced when app was moved to the background unless I had changed the audioSessionCategory to AudioSessionCategory.playback.
Can you reproduce the problem with this sample?
How long are sounds in your application? I wonder if they may overlap somehow and do this "mixed" sound.

PS. I suggest to change the recursive call chain with Timer.periodic() factory method. I won't promise it would fix anything but it may simplify your code.

@ukasz123
Copy link
Owner

I've prepared a sample app using your example. Source code.

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

No branches or pull requests

2 participants