Reputation: 409
I'm trying to create an alarm in Flutter where an alarm tone should go off after a certain time. It seems like this is easier said than done in Flutter!
Tried to use the audioplayer plugin to achieve this. Used the playLocal function wherein the asset is loaded from the rootbundle into the app directory and then played
According to an answer in the audioplayer github repo, this is the code that should do the trick:
class SoundManager {
AudioPlayer audioPlayer = new AudioPlayer();
Future playLocal(localFileName) async {
final dir = await getApplicationDocumentsDirectory();
final file = new File("${dir.path}/$localFileName");
if (!(await file.exists())) {
final soundData = await rootBundle.load("assets/$localFileName");
final bytes = soundData.buffer.asUint8List();
await file.writeAsBytes(bytes, flush: true);
}
await audioPlayer.play(file.path, isLocal: true);
}
}
I keep getting an error: "Unable to load asset". The asset (mp3/wav file) is obviously in the folder, and the folder is included in the pubspec.yaml file correctly (other image assets are loading properly from this folder, so specifying the folder itself is not the issue here)
Upvotes: 3
Views: 6220
Reputation: 489
This works well for both iOS and Android. Note: this downloads from url if not available locally.
AudioProvider audioProvider;
_playSound() async {
audioProvider = AudioProvider("http:...");
var soundToPlay = "myLocalSound";
String localUrl = await audioProvider.load(soundToPlay);
SoundController.play(localUrl);
}
}
audio_provider.dart
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart';
typedef void OnError(Exception exception);
class AudioProvider {
String url;
AudioProvider(String url) {
this.url = url;
}
Future<Uint8List> _loadFileBytes(String url, {OnError onError}) async {
Uint8List bytes;
try {
bytes = await readBytes(url);
} on ClientException {
rethrow;
}
return bytes;
}
Future<String> load(fileName) async {
final dir = await getApplicationDocumentsDirectory();
final file = new File('${dir.path}/$fileName');
if (await file.exists()) {print("file exists");
return file.path;
}
var filePath = url +fileName;
final bytes = await _loadFileBytes(filePath,
onError: (Exception exception) =>
print('audio_provider.load => exception ${exception}'));
await file.writeAsBytes(bytes);
if (await file.exists()) {
return file.path;
}
return '';
}
}
soundController.dart
import 'package:flutter/foundation.dart';
import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'dart:io' show Platform;
void audioPlayerHandler(AudioPlayerState value) => null;
class SoundController {
static AudioPlayer audioPlayer = AudioPlayer(mode: PlayerMode.LOW_LATENCY);
static AudioCache audioCache = AudioCache(prefix: "assets/audio/", fixedPlayer: audioPlayer);
static void play(String sound) {
if (!kIsWeb && Platform.isIOS) {
audioPlayer.monitorNotificationStateChanges(audioPlayerHandler);
}
audioPlayer.play(sound, isLocal: true);
}
}
Upvotes: 0
Reputation: 562
You can use another audio library https://pub.dev/packages/audioplayers
AudioCache documentation. https://github.com/luanpotter/audioplayers/blob/master/doc/audio_cache.md
Simple example:
import 'package:audioplayers/audio_cache.dart';
AudioCache player = AudioCache();
player.play('sounds/test_sound.m4a');
In this example my assets folder looks like this: assets/sounds/test_sound.m4a
This library cached audio as local file and then play audio
PS: If you want to play music from local files you can use AudioPlayer().
My example with listener on return, onPlayCompletion will be called when music end
AudioPlayer _advancedPlayer = AudioPlayer();
Stream<void> playFromLocal(int unitId, int id) {
var link = '/media/$unitId/words/$id.m4a';
_advancedPlayer.stop();
_advancedPlayer.release();
_advancedPlayer = AudioPlayer();
_advancedPlayer.play(Const.basePath + link, isLocal: true);
return _advancedPlayer.onPlayerCompletion;
}
Upvotes: 8