In the first part of this series on Background Audio the architecture of the Background Audio feature of the phone was introduced. The Marketplace Certification guidelines that are relevant to Background Audio were highlighted. Then a code sample explaining how to integrate with the Music and Videos Hub was presented.
This part of the series will cover the following topics:
As we will see in more detail later in this blog post audio track information has to be provided from the agent side, not the app UI side of your code. However of course in most cases the app UI will gather information from the user to specify which audio to play. It is therefore inevitable that there needs to be some communication between the app UI and the agent code.
The architecture for background audio application means that the app code and agent code run in different processes and don’t have any common memory where they can place shared C#/VB objects.
The advantage of this approach is that this allows the Windows Phone operating system to treat the background audio app UI part as any other app, with the same app lifecycle.
The OS can then call the background agent when required without needing to start the main app: usually when changing tracks or dealing with input from the Universal Volume Control (UVC). That also means that the OS is free to aggressively shutdown agents once the agent’s piece work is done - or if the agent is taking too long or using too much RAM or CPU for the OS’s liking.
Because of this it is also not possible to predict when the app code and the agent code will run simultaneously so care must be taken when sharing data between the two.
There are several ways to pass or share data between the app code and the agent:
While choosing the right approach, we will face following challenges:
(As discussed above the OS controls when the agent code runs so the reverse problem is not something you can do anything about)
For this there are two possibilities:
As mentioned above it is possible for app and agent code to run simultaneously and care must be taken to guard against data corruption.
If you use isolated storage or local database APIs to communicate between app code and agent code you will typically need to share code between the app and the agent.
However care must be taken when doing this:
The agent code must not reference a class library which contains banned APIs (even if these are not called from the agent).
To check whether agents are using banned APIs, you can use the Marketplace Test Kit which checks for common faults in Windows Phone applications.
Let’s explore how the background audio events are raised – to do this we will go back to the architecture diagram of background audio introduced in the previous blog post.
Remember, the BackgroundAudioPlayer (BAP) object appears to be the same from both the application side and agent side, however we will see there are some important differences in practice when we look at the events that flow from some common usage scenarios. Let’s look at these now:
In this case no background audio is playing – the first surprise is that the app-side BAP returns “Unknown” state. Clearly there is no need to involve the agent side BAP to check the state of background audio.
Understanding what is going on in this diagram is critical to understanding how the Background Audio player works. It seems quite complex but it is worth bearing in mind that all of this is implemented for you in the template background audio project. All that remains for the developer is to add their own logic for finding tracks for the agent to play.
Firstly, the app calls the BackgroundAudioPlayer.Instance.Play() method. This will cause the audio agent to start up (and if necessary to load into memory which can clearly be seen if you are using the debugger).
Once loaded the agent code will receive the Play user action – and it should respond by calling the Play method on the agent side BAP.
In response to a Play() request with no track set, the agent side BAP will raise the TrackEnded event on the agent. At this point your agent code should find the next track to play (if it is available). The agent then needs to set the Track property on the agent-side BAP.
Once the BAP has made the track ready to play the agent receives the TrackReady event. In response to this the agent should call Play() to start playback of the new track.
At this point, the app code should receive the Playing event (if it is registered to receive BAP events).
And the audio should start playing – there are a couple of further events on the agent side, BufferingStopped and Playing which are only significant for streaming audio scenarios which will be expanded upon in the next blog post.
These actions are fairly straightforward as expected.
These diagrams is similar to the initial playback case – when the agent receives the SkipNext user action or TrackEnded event it should find the new track to play, and set the Track property on the agent-side BAP.
However note that there is an Unknown state reported to the app when there is a change of tracks. This creates a potential challenge for the app UI to display the correct currently playing track information.
The MSDN docs which state that the audio agent gives no guarantee as to how long it will take for a command like Play() to be processed. It could take a few seconds to get the Playing event after the play command (even for non-streaming audio).
This is a challenge in the context of Marketplace Certification requirement 5.1.3
5.1.3 Application Responsiveness If an application performs an operation that causes the device to appear to be unresponsive for more than three seconds, such as downloading data over a network connection, the application must display a visual progress or busy indicator.
5.1.3 Application Responsiveness
If an application performs an operation that causes the device to appear to be unresponsive for more than three seconds, such as downloading data over a network connection, the application must display a visual progress or busy indicator.
In this case if no steps are taken the user will likely think that the app has ignored the tap which they were expecting to start or pause the audio. In our Depth Partner Support program we have seen a few such applications which use the Background Audio feature which suffer from this.
For good user experience once a play/pause control has been pressed:
If you are in the “Now Playing” experience of your app you may want to have a control on your page which tells the user the current track location. This can be simply achieved by calling BackgroundAudioPlayer.Instance.Position method in the callback of a DispatcherTimer.
The next part of this blog series will deal with challenges with streaming audio.
Written by Paul Annetts