How do I delayed audioplayer in flutter? - flutter

I want to connect two other mp3 files, but it just plays one mp3 file because the audio player does not play the mp3 file sequentially.
And finally, I try to delay 5 seconds after below other mp3 file played like this.
void getAudio() async{
var url = _API_AUDIO_PREFIX;
var path;
int duration = 0;
Map<String, dynamic> json = await server.postReq(data);
print(json["voices"]);
for(int i=0;i<json["voices"].length;i++){
path = url + json["voices"][i]["title"];
print(path);
duration = i * 500;
Future.delayed(const Duration(milliseconds: duration), (){
playAudio(path);
});
}
}
Future<void> playAudio(var url) async {
int result = await audioPlayer.play(url);
if (result == 1){
print("success");
}
//duration = await audioPlayer.getDuration();
}
but in milliseconds, they have errors like this.
Evaluation of this constant expression throws an exception.
How do I fix this? And How do I played the mp3 file continue to other mp3 files?

I fixed error
Evaluation of this constant expression throws an exception.
to remove const in const Duration(milliseconds: duration).
but it can't work continue to next files because path variable is changed equally. :(

Related

Playing assets in just_audio for flutter web on Safari browser

Hello Flutter developers,
I am trying to play a beeping noise that has a duration of 250 milliseconds at a frequency for 30 to 300 Hz. This is part of a simulated medical monitor. I have tried multiple audio packages and my most recent attempt is with just_audio, which works very well for every platform except the desktop safari browser. The app can be tested at benmed.org/sim (login required unfortunately).
Here is the audio playlist:
final playlist = ConcatenatingAudioSource(children: [
AudioSource.uri(Uri.parse('asset:///assets/audio/beepfiles/98.wav')),
AudioSource.uri(Uri.parse('asset://assets//audio/beepfiles/96.wav')),
AudioSource.uri(Uri.parse('asset:///assets/audio/beepfiles/94.wav')),
AudioSource.uri(Uri.parse('asset:///assets/audio/beepfiles/92.wav')),
]);
Here is initilisation of the audio player:
Future\<void\> \_initAudio() async {
await player.setLoopMode(LoopMode.one);
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
try {
player.setAudioSource(playlist);
} catch (e) {
debugPrint("Error loading audio source: $e");
}
}
And here is the function that plays the beeping sounds with delays for variation in heart rate:
void playBeeps(WidgetRef ref) async {
var obs = ref.watch(obsProvider);
obs.whenData((obs) async {
Future.doWhile(() async {
var obs2 = ref.watch(testLocalObsProvider);
int hr = obs2.heartRate;
int sats = obs2.saturationsO2;
bool audioIsMuted = ref.read(muteAudio);
int track = (50 - ((sats / 2).round())).clamp(0, 15);
player.seek(Duration.zero, index: track);
await Future.delayed(
Duration(milliseconds: ((60 / hr) * 1000).round()));
player.play().catchError((e) {
debugPrint(e);
});
await Future.delayed(const Duration(milliseconds: 250));
player.pause().catchError((e) {
debugPrint(e);
});
return !audioIsMuted;
});
});
}
I have tried just_audio among many other audio packages but nothing worked
I tried removing the "/assets" from the files
I tried .mp3 and .wav files
I wonder if the sequence of loading and playing the audio files is incorrect when compiled by safari.
Many thanks for your help with this issue.

Flutter just-audio package - playing audio with await using a byte stream does not work?

I am looping over a set of byte streams (tts generated voices) and it seems that await for the play of just-audio does not wait for the audio to finish playing.
When I add a sleep for 3 seconds after the await call, all the audios are played, so it seems to be that await for the play does not work in this case.
Code (the last function is using the azure tts package for getting the byte stream):
final player = AudioPlayer();
...
playAudioByteStream(Uint8List? audio) async {
print('Play START');
await player.setAudioSource(ByteAudioSource(audio!), preload: false);
await player.play();
print('Play END');
}
...
class ByteAudioSource extends StreamAudioSource {
final Uint8List _buffer;
ByteAudioSource(this._buffer) : super(tag: 'MyAudioSource');
#override
Future<StreamAudioResponse> request([int? start, int? end]) async {
// Returning the stream audio response with the parameters
return StreamAudioResponse(
sourceLength: _buffer.length,
contentLength: (start ?? 0) - (end ?? _buffer.length),
offset: start ?? 0,
stream: Stream.fromIterable([_buffer.sublist(start ?? 0, end)]),
contentType: 'audio/mp3',
);
}
}
...
Future<Uint8List> getAudioByteStream(String text, Voice voice) async {
TtsParams params = TtsParams(
voice: voice,
audioFormat: AudioOutputFormat.audio16khz32kBitrateMonoMp3,
rate: 1.0,
text: text);
final ttsResponse = await AzureTts.getTts(params) as AudioSuccess;
return ttsResponse.audio;
}

How to Write or save Large files in memory in flutter

I'm currently facing an issue, where I'm trying to Save a large video file (586 Mb).
I'm able to download the entire file but, when I try to write this file to memory, I get an Error of “Out of memory”. It works for smaller video files like (80mb, 100 mb) but fails for the large files. I'm attaching the code snippet for reference.
Future download() async {
var request = http.Request('GET', Uri.parse(url!));
var response = httpClient.send(request).timeout(Duration(seconds: 3));
var chunks = <List<int>>[];
var downloaded = 0;
try{
response.asStream().listen((http.StreamedResponse r) {
if(r.statusCode==HttpStatus.ok){
r.stream.listen((List<int> chunk) {
// Display percentage of completion
chunks.add(chunk);
downloaded += chunk.length;
downloadingCallBack(downloaded / r.contentLength! * 100,filesize(downloaded),filesize(r.contentLength));
}, onDone: () async {
// Display percentage of completion
print('downloadPercentage: ${downloaded / r.contentLength! * 100}');
// Save the file
try{
var file = File('$dirPath/$fileName');
//The Uint8List below throws the error "Out of memory and I'm not able to write the file to memory"
***Error Here ==>*** final bytes = Uint8List(r.contentLength!); //Code fails here, (r.contentLength is 586900112 bytes)
var offset = 0;
for (var chunk in chunks) {
bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
await file.writeAsBytes(bytes);
downloadingDoneBack(true);
return;
}catch(fileException){
rethrow;
}finally{
httpClient.close();
}
});
}else{
downloadingDoneBack(false);
}
});
}catch(e){
downloadingDoneBack(false);
}finally{
httpClient.close();
}
}
Since it's a large file, I think it would be better to download your file using flutter_downloader plugin which also supports notifications and background mode.
Import and initialize flutter downloader
import 'package:flutter_downloader/flutter_downloader.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Plugin must be initialized before using
await FlutterDownloader.initialize(
debug: true // optional: set to false to disable printing logs to console (default: true)
ignoreSsl: true // option: set to false to disable working with http links (default: false)
);
runApp(const MyApp())
}
Create new download task
final taskId = await FlutterDownloader.enqueue(
url: 'your download link',
savedDir: 'the path of directory where you want to save downloaded files',
showNotification: true, // show download progress in status bar (for Android)
openFileFromNotification: true, // click on notification to open downloaded file (for Android)
);
Handle isolates
Important note: your UI is rendered in the main isolate, while download events come from a background isolate (in other words, codes in callback are run in the background isolate), so you have to handle the communication between two isolates. For example:
ReceivePort _port = ReceivePort();
#override
void initState() {
super.initState();
IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
setState((){ });
});
FlutterDownloader.registerCallback(downloadCallback);
}
#override
void dispose() {
IsolateNameServer.removePortNameMapping('downloader_send_port');
super.dispose();
}
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port');
send.send([id, status, progress]);
}
Load all download tasks
final tasks = await FlutterDownloader.loadTasks();

How to upload a video picked from user into firebase?

Im trying to upload a video into firebase .But theres a problem ,the more videos I upload, the more space a video needs. Im only uploading one video the same time . The video is picked from user . And when user picked the first video and when video duration is about 2 seconds long, it gets very fast uploaded. Then on the next also 2 or 3 seconds duration it takes a bit more time then the first but still ok . And then like on the 4 video ,its need very much time. And the video ist again 2 or 3 seconds recording but storage like 13 minutes . And im not getting why. This only is resolved when im using a new android emulator. it dont care when im deleting all data from firebase and like recording the first video into it .
Hope anyone can example why this error happen.
Heres my code
final allvideos = FirebaseStorage.instance.ref().child('allvideos');
final allimages = FirebaseStorage.instance.ref().child('allimages');
uploadVideo() async {
setState(() {
isuploading = true;
});
try {
var firebaseuseruid = FirebaseAuth.instance.currentUser.uid;
DocumentSnapshot userdoc = await FirebaseFirestore.instance
.collection('meinprofilsettings')
.doc(firebaseuseruid)
.get();
var alldocs = await FirebaseFirestore.instance.collection('videos').get();
int length = alldocs.docs.length;
String videourl = await uploadvideotostorage("Video $length");
String previewimage = await uploadimagetostorage("Video $length");
FirebaseFirestore.instance.collection('videos').doc("Video $length").set({
'username': userdoc.data()['username'],
'uid': firebaseuseruid,
'profilepic': userdoc.data()['url'],
'id':"Video $length",
'likes': [],
'commentcount': 0,
'sharecount': 0,
'hashtag1': hashtagcontroller.text,
'hashtag2': hashtagcontroller2.text,
'hashtag3': hashtagcontroller3.text,
'videourl': videourl,
'previewimage': previewimage,
'ratings': [],
});
Navigator.pop(context);
} catch (e) {
print(e.toString());
}
}
}
Heres how I upload it
the picture is for preview picture
getpreviewimage() async {
final previewimage = await flutterVideoCompress.getThumbnailWithFile(
widget.videopath_asstring,
);
return previewimage;
}
compressvideo() async {
if (widget.imageSource == ImageSource.gallery) {
return widget.videofile;
} else {
final compressvideo = await flutterVideoCompress.compressVideo(
widget.videopath_asstring,
quality: VideoQuality.MediumQuality);
return File(compressvideo.path);
}
}
uploadvideotostorage(String id) async {
final video = await allvideos.child(id).putFile(await compressvideo());
String url = await video.ref.getDownloadURL();
return url;
}
uploadimagetostorage(String id) async {
final video = await allimages.child(id).putFile(await getpreviewimage());
String url = await video.ref.getDownloadURL();
id=url;
return url;
}
Use something like this to generate your random ID:
import 'dart:math';
import 'package:intl/intl.dart';
String generateId() {
int randomNumber = Random().nextInt(9999999);
String now = DateTime.now().millisecondsSinceEpoch.toString().substring(7);
String formatted = DateFormat('MMdh').format(DateTime.now());
return randomNumber.toString() + formatted + now;
}
Change your upload function to look like this:
Future<String> uploadvideotostorage(String id) async {
final video = await allvideos.child(id).putFile(await compressvideo());
String url = await video.ref.getDownloadURL();
return url;
}
When you create a video, assign it a random id like this:
String randomlyGeneratedId = generateId();
Finally, to get your download URL back:
String finalVideoURL = await uploadvideotostorage(randomlyGeneratedId);

Flutter just_audio package how play audio from bytes

I'm using just_audio plugin and it has on description a feature: Read from byte stream.
Basically when I put a file (from url) to play, I'm saving the bytes from file so after this step I want to play it locally.
I have a question about how play from byte stream. Can anyone provide an example how to do this? I need to put this on my playlist so it has to be a child of ConcatanatingAudioSource.
The only Audio Source that I found was using it from Uri.
final _playlist = ConcatenatingAudioSource(
children: [
AudioSource.uri(
Uri.parse(
"https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"),
tag: AudioMetadata(
album: "Science Friday",
title: "ddddd",
artwork:
"https://media.wnyc.org/i/1400/1400/l/80/1/ScienceFriday_WNYCStudios_1400.jpg",
),
)
]
)
This is how I save the bytes:
void getBytes() async {
Uri uri = Uri.parse(url);
var rng = new Random();
// get temporary directory of device.
Directory tempDir = await getTemporaryDirectory();
// get temporary path from temporary directory.
String tempPath = tempDir.path;
// create a new file in temporary path with random file name.
File file = new File('$tempPath' + (rng.nextInt(100)).toString() + '.mp3');
// call http.get method and pass imageUrl into it to get response.
http.Response response = await http.get(uri);
// write bodyBytes received in response to file.
await file.writeAsBytes(response.bodyBytes);
}
Thanks in advance
So it seems that you need to create your own class as an extension of StreamAudioSource.
import 'dart:typed_data';
import 'package:just_audio/just_audio.dart';
class MyJABytesSource extends StreamAudioSource {
final Uint8List _buffer;
MyJABytesSource(this._buffer) : super(tag: 'MyAudioSource');
#override
Future<StreamAudioResponse> request([int? start, int? end]) async {
// Returning the stream audio response with the parameters
return StreamAudioResponse(
sourceLength: _buffer.length,
contentLength: (start ?? 0) - (end ?? _buffer.length),
offset: start ?? 0,
stream: Stream.fromIterable([_buffer.sublist(start ?? 0, end)]),
contentType: 'audio/wav',
);
}
}
And then invoke it like so
await thePlayer.setAudioSource(MyJABytesSource(bytes));
You can call thePlayer.play(). after, but I prefer to use this as a listener.
thePlayer.processingStateStream.listen((ja.ProcessingState state) {
if (state == ja.ProcessingState.ready) {
// I'm using flutter_cache_manager, and it serves all the file
// under the same name, which is fine, but I think this is why
// I need to pause before I can play again.
// (For tracks after the first, the first plays fine.)
// You probably won't need to pause, but I'm not sure.
thePlayer.pause();
thePlayer.play();
} else if (state == ja.ProcessingState.completed) {
// What to do when it completes.
}
});
The nice part about doing this way, is that you don't actually need await keyword, which can be situationally useful. I have it there just to make clear that this is an async function.