What I understood from plugin is that :
we have 2 way of communication with plugin , one is from the UI and the other is from background like headset , notifications control and ... .
in UI , we have some callbacks like : connect,start,pause,play,disconnect , ...
also in background we have these callbacks :onStart,onStop,onPlay,onPause , ...
these callbacks used separately (UI and Background don't have communication with other) when the queue has nothing to change.
but when we need to change queue we need to start a communication from UI to Background to handle queue changes.
Is what I understood right?
Please correct me if I'm in the wrong understood . Thanks Ryan.
What I understood from plugin is that :
we have 2 way of communication with plugin , one is from the UI and the other is from background like headset , notifications control and ... .
Actually, you should think about it like a client/server architecture where your implementation of BackgroundAudioTask is the server, and where there are multiple CLIENTS, including:
These are all clients because they make playback requests to the server and the server broadcasts state changes to all clients. So if one client requests skipToNext, that request is communicated to the server. Your server can handle that in whatever way is desired, and then the server should then broadcast the new state to ALL clients. Typically, by calling AudioServiceBackground.setMediaItem and AudioServiceBackground.setState.
in UI , we have some callbacks like : connect,start,pause,play,disconnect , ...
These are not callbacks. These are calls.
also in background we have these callbacks :onStart,onStop,onPlay,onPause , ...
Yes, these are the callbacks. So when you call pause() from the client, then a message gets sent to the server and translate to your onPause() callback being called. So onPause is not a method that you're intended to call, rather it's a method that gets called by the plugin making your code on the receiving end of the call, not the initiator. In the Flutter API, too, callbacks are easily identified because they are named with the on- prefix.
these callbacks used separately (UI and Background don't have communication with other) when the queue has nothing to change.
Are you just talking about the queue? Because even if the queue doesn't change, that just means no changes will be communicated between the client/server related to the queue, but still there may be communication related to other non-queue state changes such as the play/pause state. But if you're just talking about the queue, then you're right. Between the Flutter UI (client) and the background task (server), nothing will ever get communicated until either the client or server decides to send a message to the other side. The sending side makes a call, and the receiving side implements a callback or listens to a stream (in the case of server -> client communication).
but when we need to change queue we need to start a communication from UI to Background to handle queue changes.
When you use this word "start", I am not sure if you mean calling the start method, or simply initiating a communication (e.g. by calling AudioService.setQueue), which are very different things.
To explain both of these in context, what you need to understand is that the server doesn't actually exist until you call start, so you can't communicate with it before then. After the server is started, you can communicate with it via any of the other calls, such as setQueue, pause and so on. Generally, you should not keep the server running all the time since it takes up system resources, not the least of which is to keep the CPU alive while the screen off which is a battery drain.
So maybe your question is when you need to start the server so that you can communicate with it. Do you need to start the server just to set the queue? Well, you should store your queue in a database or something like that, and so the idea of setting or modifying the queue should not be tied together with the presence of the server. When your app first starts, you do not need to start the server. When the user interacts with your UI to manipulate the queue, you do not need to start the server. You can record those queue changes in your database. You start the server when the user hits the play button if the server is not already running. You stop the server when the user has decided they are finished listening to audio in your app. When you start the server, you would basically use the setQueue method to initialise the server so that it can broadcast the queue to all clients, and so typically what you would do here is read the queue out of your database and pass those items into setQueue, and if the user continues to manipulate the queue from the UI while the server is running, you need to keep calling setQueue so that the server can handle that and broadcast the queue changes to all clients. After the server is stopped, there is no need to keep coummunicating with the server via setQueue and you can handle any user interactions with the queue by recording them solely in your database.
Hi @ryanheise,
Really useful explanation, thanks a lot. If I understand this correctly, it means you can build different player UI in Flutter (extended player, small bottom player, etc) in different screens of your app, and have them hooked to AudioService to control audio? The point being to have multiple screens you can navigate to without stopping the audio. Is that correct?
Thanks, @CaerCam . I've decided to pin this issue in case others also find it helpful (although in the future I will hopefully open a wiki).
To answer your question, the whole Flutter UI should be treated as one client, and you can only maintain a single connection at any time between your Flutter UI and the audio service. However, your app may still have two screens wanting to connect to the audio service, but you either need to look for the widget higher up the tree where the connection can be maintained and shared, or if you do the connection within a page route, you need to disconnect from the first screen before connecting in the second screen.
I wish we had a documentation for at least the entries of each component and an example that is actually not overcomplicated like the one we have now.
Yeah, like @moda20 said, the example we have has like a ton of stuff going on, i dont even know where to start. Would be nice to have some info like:
-> Start here
-> Declare this, for this use
-> Now we need this function
-> Start the server here
-> Call the function here
An so on.
Hey! I agree with @renanmgs. I'm struggling implementing and understanding the communication workflow. I was trying to reach the owner to get a better explanation to implement this on my app, but I don't know where to get information from. Any ideas? Or anyone that can help me out to understand better? Thanks
@TheChileanKink I wrote a tutorial in the Wiki to follow a more "start here", "then do this", type of approach. But let me know if it is still unclear.
Most helpful comment
Actually, you should think about it like a client/server architecture where your implementation of
BackgroundAudioTaskis the server, and where there are multiple CLIENTS, including:These are all clients because they make playback requests to the server and the server broadcasts state changes to all clients. So if one client requests skipToNext, that request is communicated to the server. Your server can handle that in whatever way is desired, and then the server should then broadcast the new state to ALL clients. Typically, by calling
AudioServiceBackground.setMediaItemandAudioServiceBackground.setState.These are not callbacks. These are calls.
Yes, these are the callbacks. So when you call
pause()from the client, then a message gets sent to the server and translate to youronPause()callback being called. SoonPauseis not a method that you're intended to call, rather it's a method that gets called by the plugin making your code on the receiving end of the call, not the initiator. In the Flutter API, too, callbacks are easily identified because they are named with theon-prefix.Are you just talking about the queue? Because even if the queue doesn't change, that just means no changes will be communicated between the client/server related to the queue, but still there may be communication related to other non-queue state changes such as the play/pause state. But if you're just talking about the queue, then you're right. Between the Flutter UI (client) and the background task (server), nothing will ever get communicated until either the client or server decides to send a message to the other side. The sending side makes a call, and the receiving side implements a callback or listens to a stream (in the case of server -> client communication).
When you use this word "start", I am not sure if you mean calling the
startmethod, or simply initiating a communication (e.g. by callingAudioService.setQueue), which are very different things.To explain both of these in context, what you need to understand is that the server doesn't actually exist until you call
start, so you can't communicate with it before then. After the server is started, you can communicate with it via any of the other calls, such assetQueue,pauseand so on. Generally, you should not keep the server running all the time since it takes up system resources, not the least of which is to keep the CPU alive while the screen off which is a battery drain.So maybe your question is when you need to start the server so that you can communicate with it. Do you need to start the server just to set the queue? Well, you should store your queue in a database or something like that, and so the idea of setting or modifying the queue should not be tied together with the presence of the server. When your app first starts, you do not need to start the server. When the user interacts with your UI to manipulate the queue, you do not need to start the server. You can record those queue changes in your database. You start the server when the user hits the play button if the server is not already running. You stop the server when the user has decided they are finished listening to audio in your app. When you start the server, you would basically use the
setQueuemethod to initialise the server so that it can broadcast the queue to all clients, and so typically what you would do here is read the queue out of your database and pass those items intosetQueue, and if the user continues to manipulate the queue from the UI while the server is running, you need to keep callingsetQueueso that the server can handle that and broadcast the queue changes to all clients. After the server is stopped, there is no need to keep coummunicating with the server viasetQueueand you can handle any user interactions with the queue by recording them solely in your database.