audio_waveforms
audio_waveforms copied to clipboard
Page needs to be reloaded before audiowave works
Hello there and great plugin. I'm having an issue where after I create the audiofile and display the waveform widget it doesnt populate. I have to go to another screen then back for the widget to load in the audio data. Just a quick background. I have chat list screen, from there I click a button and it takes me to a separate audio recording screen. I do the recording fine. Choose to save file. File gets sent to firebase and then my app closes the audio recording screen and returns user to chat list screen. The list now shows the widget but its empty and I can click on the play button to start the recording(along with a log print in console to verify the action). So I have to go out of the chat screen and back in and then the widget loads the data and shows the waveform.
Not sure if there is something I'm missing or what. I've been trying to find a way to reload the page after the recording screen pops off the tree stack but I have yet to figure it out. Any help would be much appreciated.
Are you calling preparePlayer
before you get the recording? If yes then it will not show waves so only call preparePlayer after you have the file. Also, use this condition controller.playerState != PlayerState.stopped
above the widget because when you directly use the AudioFileWaveforms widget it will start reading data. Also you can use onPlayerStateChanged
stream if you want.
If this doesn't work can you please share some code?
Thanks for the reply, I just checked and I am grabbing the file and saving it onto the device before I'm preparingPlayer.
void _preparePlayer() async {
// Get file name from the download Url
final audioClipName = _storage.getFilenameFromUrl(widget.Message.mediaURL);
Utilities.logWarning('AudioFilename with key: ${widget.key} is: $audioClipName');
// Check to see if file already exists locally
bool checkAudioClipLocal = await _mediaController.checkFileExists(audioClipName);
// If file exists then prepare Player
if (checkAudioClipLocal) {
File localAudioClip = await _mediaController.getLocalFile(audioClipName);
Utilities.logWarning('local Audio Clip path is: ${localAudioClip.path}');
_playerController.preparePlayer(localAudioClip.path);
return;
} else {
Utilities.logError('Audio File doesnt not exist locally yet, downloading');
final File? downloadedAudioClip = await _storage.getFileFromStorage(widget.vMessage.mediaURL);
if (downloadedAudioClip != null) {
await downloadedAudioClip.readAsBytes();
await _playerController.preparePlayer(downloadedAudioClip.path).then((value) {
if (mounted) {
setState(() {});
}
});
} else {
Utilities.showDialog('Loading Error', 'Something went wrong trying to download audioFile, please try again');
}
}
}
As you can see I'm trying to store the file onto the device before using it and if its not already downloaded I proceed to save it locally before I use the preparePlayer method.
I apologize but I'm still learning flutter and I'm not sure how I'd use the onPlayerStateChanged
stream. I tried putting the controller.playerState != PlayerState.stopped
right above the audioFileWaveForms widget and put just a Container() as the alternative but it still shows the bubble empty when I tried to record another audioClip
I also initialize the playerController after I preparePlayer if that makes a difference.
@override
void initState() {
super.initState();
_preparePlayer();
initializePlayerController();
}
initializePlayerController() {
_playerController = PlayerController()
..addListener(() {
if (mounted) {
setState(() {});
}
});
}
I know I'm close lol, but once I have multiple audio "bubbles" in the chat screen I'm hoping they all load as they appear from the firestore stream in the chat window.
Hers a screenshot I just took, the filled in one was previous and I had to go out and back into the chat screen and the top one I just made and thats how it appeared. I also use a UniqueKey() on each audio bubble that gets created, wasnt sure if that helps if there are many in the chat over time.
I think you are using a single controller for every waveform widget. If yes then you will need a unique PlayerController
for every waveform widget.
If that's not the case then you can initialize a controller whenever you want just initialize it before you use it.
so something like this,
late PlayerController controller;
@override
void initState() {
super.initState();
controller = PlayerController()..preparePlayer(path);
}
As for a chat screen where audio chats will come dynamically what you can do is create a separate stateful widget with a controller initializing in its initState and also it would have all AudioFileWaveforms controls in it so that you don't have to think of managing your controllers.
And just for your info, an onPlayerStateChaged
provides events whenever there is a change in the state of the player so there may be a chance that controller.playerState
doesn't get updated so what you can do is listen to this stream like this,
controller.onPlayerStateChanged.listen((event) {
//event is PlayerState
});
so you can assign the latest event to your state variable and update the UI based on it.
Thank you again for your help trying to cypher where i'm going wrong.
So the hierarchy goes like this. In my chat screen I have a button that brings me to a new separate audioRecording screen where the user clicks a button, records the audioclip, once done user can review it on the same screen, this all works flawlessly I might add, once user confirms they are happy with recording the file it gets sent to the cloud and returns user back to chat screen. after a few seconds the chat screen gets the stream that theres a new message and creates an individual audio bubble as seen in the previous pics. Each bubble has its own uniqueKey. Does the playerController have the option to use keys? I didnt see, if there was.
As far as I thought, each bubble is its own identity. I have the stateful bubble widget itself using a uniqueKey as well as the audioFileWaveForm widget also using a UniqueKey.
This comment box doesnt take dart files so I saved it as a pdf if that helps you help me hash out any stupid mistakes I might have made. lol. I appreciate your help with this issue.
@Technorocker I reviewed the file but I haven't been able to find any mistake there. And for your question playerController internally manages a unique to identify a player. You can access it with controller.playerKey
. Providing a key to the waveform widget won't make any difference unless you are using it for something on your side.
Can you please check if controller.bufferData
is not null or empty? If not then most probably it's something to do with the waveform widget being shown before it had time to read data.
thanks for checking out my file. When you suggested I put the controller.playerState != PlayerState.stopped
above the audioFileWaveForms widget i did try that but it didnt work.
I did notice theres a PlayerState.readingComplete
so I also tried that above the widget and show an empty container otherwise but that didnt seem to make a difference either. I guess I'll have to find a way to trigger a rebuild of either the bubble widget or even the chat screen when the stream sends a new audioClip to the user.
for the controller.bufferData
check, would I do that above the waveform widget or just do a print statement to check it somewhere in the file?
@Technorocker just check it with print
. It is not required in the UI part because we have playerState
for it. I'm asking this because if bufferData is null or empty then it will show empty waveforms in the UI.
So i checked the bufferdata with a print statement right at the top of the build method and it is indeed empty when it first comes through. I also tried to put that Playerstate check at the top of the build return statement(both readCompleted and stopped) and it would trigger the empty container widget so it wouldnt show up in the UI, or it would show up and when I clicked on the play button the widget would disappear. lol
I'm looking at the different keys available to use for widgets and am going to try a ValueKey
I appreciate your help, I'll keep tinkering and see what I can come up with
@ujas-m-simformsolutions Hi, for my part the playerController.bufferData
return null; Do you have any idea how I can solve this?