Just audio: How to avoid skipped samples at first playback on Android? - flutter

The app loads a few short (4-5 Seconds long) audio files during startup and plays them at certain events. It's basically working, except for one little detail on Android:
The first time an audio file is played, it sounds as if playback starts a few seconds into the file, instead of at the beginning. Any following attempts to play the file work as expected. It's just the very first playback that starts a little too late into the file.
Question now is, how can it be fixed?
This is how the files are loaded during initialization of the app:
late AudioPlayer _someAudio;
init() async {
AudioLoadConfiguration loadCfg = AudioLoadConfiguration(
androidLoadControl: AndroidLoadControl(
prioritizeTimeOverSizeThresholds: true,
minBufferDuration: const Duration(seconds: 10),
maxBufferDuration: const Duration(seconds: 20),
bufferForPlaybackDuration: const Duration(seconds: 10),
),
);
_someAudio = AudioPlayer(audioLoadConfiguration: loadCfg);
await _someAudio.setAsset('assets/audio/someeffect.mp3');
}
Note 1: AudioLoadConfiguration doesn't seem to have any effect here. It has just been added in an attempt to fix the issue.
And this is how the files are played:
void playSomeEffect() async {
await _someAudio.seek(Duration.zero);
await _someAudio.play();
}
Note 2: It seems to be an Android issue (iOS is working as expected). Happens on a Samsung and a Motorola - other devices have not yet been tested.
Do you have any ideas how to ensure that first playback starts at the beginning? Any advise is appreciated. Thank you.

Related

How can I get the details of currently playing song in miniplayer?

I am working on a music player app in flutter.
I fetch the songs from devices using on_audio_query package and display them in listview. When I click on a song, i set the plylist of all songs and play the one thats clicked using just_audio package like this.
await player.setAudioSource(
ConcatenatingAudioSource(
useLazyPreparation: true,
shuffleOrder: DefaultShuffleOrder(),
children: allSongsList! // allSongsList is the list of
songs(on_audio_query)
.map((songModel) =>
AudioSource.uri(Uri.parse(songModel.data)))
.toList(),
),
initialIndex: index, // Listview Index
initialPosition: Duration.zero);
await item.player.play();
I want to show miniplayer at the bottom only when there is a song playing(paused),refresh the song descriptions,how do I get the song description(Artist/song)?
I will let you the implementation of the mini player widget for you, however, I will consider that I have a shouldMiniPlayerBeVisible, in the Scaffold of your page:
First, declare and initialize a shouldMiniPlayerBeVisible variable that will manage the show/hide of the mini player:
bool shouldMiniPlayerBeVisible = false;
and a currentAudio which will take the song and pass it in the mini player.
YourAudioModel currentAudio = YourAudioModel();
Here, I supposed that I have a simple YourAudioModel which will hold information about audio such as title, description, length, URL (or local) path ...
I recommend not setting it to null initially , you can initialize it with a placeholder YourAudioModel audio model that has some dummy data, or loading data information for example...
now in your Scaffold:
Scaffold(
floatingActionButton: Visibility(
visible: shouldMiniPlayerBeVisible,
child: shouldMiniPlayerBeVisible(songToPlay: currentAudio),
),
),
I will consider that you are using a StatefulWidget, but the steps are the same as you need just to get the idea of it to implement it in other state management solutions.
in the initState, you need to listen to the playerStateStream stream like this:
player.playerStateStream.listen((state) {
if (state.playing) {
shouldMiniPlayerBeVisible = true;
} else {
shouldMiniPlayerBeVisible = false;
}
setState(() {});
});
this basically will track if any audio is playing or not, then show the mini player based on it.
now before your run the await item.player.play();, set your currentAudio variable to the new audio which is running, you can do it with a function like this:
Future<void> playCurrentAudioANdShowItInMiniPlayer(YourAudioModel audio) async {
currentAudio = YourAudioModel;
await item.player.play();
}
now from your UI, for each item in ListView, you can just call the playCurrentAudioANdShowItInMiniPlayer method with its YourAudioModeland expect it to work fine.
from here, you should implement the actual mini player widget, and you will need also a custom Navigator widget so that mini player will be on the screen even if you navigated to other screens, well I faced this issue before and the miniplayer worked just really fine and good as I expected, I recommend you to use it.

How to get the duration of the audio recorded using flutter_sound package?

I am using flutter_sound package for Audio recording. I want to ge the duration of the recorded audio, to send it through an API and also display it in the UI. So, how to approach this?
I was using audioplayers package in my project. So I managed to get the total duration of the audio using the package.
Future<int> _getAudioduration(String audioPath) async {
final AudioPlayer audioPlayer = AudioPlayer();
await audioPlayer.setUrl(audioPath, isLocal: true);
return Future.delayed(
const Duration(seconds: 2),
() => audioPlayer.getDuration(),
);
}
**There may be another solutions for getting the total duration of an audio. This may not be the proper solution. I am posting this here so that someone might find this helpful

flutter AssetsAudioPlayer stop other instances

I'm working on a quiz app and if the user selects a correct answer the app should play a success sound and if the answer is wrong the sound should be another one (e.g please try again )
my problem is when the user taps on another answer the old player are already working I need to check if there is another instance of the player are playing and stop it
I'm using assets_audio_player: ^3.0.4+1
if (_correctAns != _selectedAns) {
AssetsAudioPlayer.newPlayer().open(
Audio("assets/audios/tryAgin.mp3"),
showNotification: true,
);
}
if (_correctAns == _selectedAns) {
_assetsAudioPlayer.open(
Audio("assets/audios/success.mp3"),
showNotification: true,
);
Future.delayed(
Duration(seconds: 2),
() {
nextQuestion();
},
);
_numOfCorrectAns++;
}
I think u can use isPlaying to check if there is an audio playing .... and as another solution u can stop the current playing sound in onPressed then play the new sound ... if u have any question I can help u

Flutter video_player sound sometimes not in sync with video

I am having an issue with Flutter video_player where sometimes the video hangs and the sound is not in sync with the video. There is a delay of ~1 second between the video and sound. This only happens when playing certain videos, most videos are fine. I've checked that one of the affected videos is in the same format (mp4) as other videos and also have downloaded that video from my S3 bucket and have confirmed that it plays correctly in that case, so I believe it must be an issue with the video_player plugin. Here is my code to load the video controller. Is there any reason that videos would behave differently with this plugin where the audio and video are not in sync?
void loadVideo() async {
videoController =
VideoPlayerController.network(videoLink);
videoController.initialize().then((_) {
if (!mounted) {
// displays an error message if the video controller doesn't load
videoError = true;
setState(() {});
return;
}
setState(() {});
});
videoController.addListener(_listenForError);
}
void playVideo() async {
videoController.play();
}
Widget cameraWidget = Transform.scale(
scale: videoController.value.aspectRatio / deviceRatio,
child: AspectRatio(
aspectRatio: videoController.value.aspectRatio,
child: VideoPlayer(videoController),
),
);

How to jump to frame with flutter video player?

Is it possible to jump to certain timestamp and display the frame without starting the video using flutter video_player?
I was able to change a frame only when I call play immediately after seekTo.
_videoPlayerController.seekTo(Duration(milliseconds: value));
_videoPlayerController.play();
I also tried
_videoPlayerController.seekTo(Duration(milliseconds: value));
_videoPlayerController.play();
_videoPlayerController.pause();
but it does not change displayed frame of video.
This answer probably comes a bit late, and is totally a hack
It shouldn't really be used, but it allowed me to have a similar behaviour
From what I could find, VideoPlayerController doesn't have any way to interact with the video regarding frames, only timestamps with the seekTo method you used. You just need to play and pause with a little delay in between actions and have it wrapped in an async function so that you can wait for the actions to complete, essentially this:
void moveOneFrameForward() async {
//Gets the current time point at where the video is at in a "Duration" type object
var currentTime = await _videoPlayerController.position;
//Seeks to the current time + an interval, in this case 100ms
await _videoPlayerController.seekTo(
Duration(milliseconds: currentTime!.inMilliseconds + 100),
);
//Plays the video so to render a frame
await _videoPlayerController.play();
//Delay so that the frame is rendered
await Future.delayed(Duration(milliseconds: 10));
//Video is paused to display the frame
await _videoPlayerController.pause();
}