Getting help from a Designer

It’s already more than half a year ago when I started working on the Chain app. I tried to make the app as beautiful as possible, while thinking about all the Modern UI design principles.

But I’ve had help almost from the beginning. One of the users of my app wanted to help me, make the app even better. Martin Fujak sent me some pictures of improvements I could make. And that’s how both the Montly and Dashboard view came to be, along with some other improvements. Without his help I wouldn’t have come up with ideas on how to visualize the Monthly view. But this isn’t all yet, Martin came up with even more ideas for improvement complete with visual design that I will try to implement in future versions of the Chain app.

Thanks for all the help I got from you so far! I can really recommend you to others who need help with the design of their app.

Monthly-ViewDashboard-View

Martin wasn’t the only Designer who helped with the Design of the Chain app. More on that in a next post.

Windows Phone 8.1–Background Audio in Windows Phone Store apps

With the introduction of Windows Phone 8.1 you’ve the choice to either continue with the Windows Phone Silverlight 8.1 option or to use the Windows Phone Store Apps model similar to Windows 8 Store Apps.

However you can’t just upgrade to Windows Phone Silverlight 8.1 in every situation. Some features just aren’t supported in Silverlight 8.1, one of them being the AudioPlayerAgent which we use when implementing Background Audio in Windows Phone 8.

Upgrading to the Windows Phone Store Apps model isn’t an easy task either, the Background Audio is implemented in a completely different way. But there are reasons for people to do upgrade to the Windows Phone Store Apps model. One of these is the ability to change the speed of playback, an often requested feature for the P | Cast podcast app I created. Another option is to share a lot of the code by creating a Universal app which will enable both a Windows Store app and a Windows Phone Store app. I will not go into the details of the Background Audio for the Windows Store apps, but they are a little bit different compared to the implementation of the Background Audio in the Windows Phone Store apps. Different, but still similar though!

Alright, enough about the background, let’s start building a very basic app with Background Audio!

A little bit of architecture

We want to play audio which stays playing while our user interface isn’t active. So we need to have a background process that’s capable of playing audio. See the green blocks at the right in below diagram. The actual audio playback occurs in the background process while the foreground process has access to the MediaPlayer information via a Proxy Object.

Background Audio Architecture Windows Phone 8.1

To manage the Universal Volume Control, like the one below we’ll need to talk to the SystemMediaTransportControl. This API that also exists in Windows 8.1 so if we ever want to create a Universal App this will come in handy.

Universal Volume Control Windows Phone 8.1

But the actual communication between the foreground process aka the UI and the background process happens through messaging. You can pass messages from foreground to background, but also the other way around. A message consists of a string message, but can also pass an additional value (only simple value types).

Life Cycle of the Background Task

The Background Task is initiated the first time the Foreground Process does a call to BackgroundMediaPlayer.Current. Upon initiation the IBackgroundTask.Run is called.

You want the background audio to continue playing, so you have to get a BackgroundTaskDeferral in the Run method of the IBackgroundTask. You’ll have to complete the deferral upon the Canceled or Completed events of the task. The actual Run method should run to the end in a timely fashion, if it’s more or less waiting in the Run method the Background Task could be terminated to release resources.

The background task for running audio can be cancelled in a couple of situations:

  • When another app with audio playback starts
  • When the background task is running but no audio is playing (paused or never started) and the foreground app is suspended

The playback will be automatically paused by media interruptions like a phone call or VoIP call. When the phone call or VoIP call ends within 5 minutes, the background audio is resumed by executing the Run method and sending a ButtonPressed (PlayButton) event on the SystemMediaTransportControls instance. When the call takes longer than 5 minutes the playback doesn’t start but the Universal Volume Control doesn’t loose state and hitting the play button will restart the Background Audio manually.

Termination of the background task happens without warning when:

  • A VoIP call comes in and there is not enough memory
  • A resource policy is violated
  • Task cancellation or completion does not end gracefully

Project Setup

Besides the creation of a Windows Phone 8.1 app, it’s required to create a Windows Runtime Component (Windows Phone).

image

Add the BackgroundAudioTask which implement IBackgroundTask, like below. The details of the implementation will be filled in later.

public sealed class BackgroundAudioTask : IBackgroundTask
{
    public void Run(IBackgroundTaskInstance taskInstance)
    {
            
    }
}

 

In the Windows Phone 8.1 App project you can add a reference to the Windows Runtime Component project. Please don’t make it a class library.

Go to the Package.appxmanifest to the Declarations tab and add a Background Task. Give it the the task type Audio and set the Entry point to the BackgroundAudioTask we created by using the full type name (namespace+type name).

image

The UI of the Player

Because I want to focus on the background audio, I made the UI simple, very simple. One Button, just the play button.

SNAGHTML4308a0c9

So the little bit of xaml that’s there to create a button with the click handler.

<Grid>
    <Button Content="Play" Click="PlayButtonClick"></Button>
</Grid>

We need the Background Task to fire up, so we have to access the BackgroundMediaPlayer.Current property. We do this in the OnNavigatedTo of the MainPage.

private MediaPlayer _mediaPlayer;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    _mediaPlayer = BackgroundMediaPlayer.Current;
}

 

And the PlayButtonClick is almost empty as well. We send a message to the background task. The message has a key indicating the operation Play, the value being a url to the background media we want to play. We will have to handle this in the background audio, but this is all we do in the UI.

private void PlayButtonClick(object sender, RoutedEventArgs e)
{
    var message = new ValueSet
                    {
                        {
                            "Play",
                            "http://media.ch9.ms/ch9/a092/c301b08c-1acc-4f2c-b636-61f4e917a092/3-159.mp3"
                        }
                    };
    BackgroundMediaPlayer.SendMessageToBackground(message);
}

Code a Background Task for Background Audio

After all the explanation above it’s time to write some real code. In the below piece of code you can see that all we do in the Run method is preparation. My advice to you is to keep this as short as possible as well. In line 3, we get a reference to the SystemMediaTransportControls, being the Universal Volume Control, and enable the Universal Volume Control.

In line 6 we subscribe to the receiving of the messages that are sent from the UI and line 7 does subscribe to the MediaPlayer state changes like Stopped, Playing and Paused.

To make sure the background task keeps running we get a deferral and also subscribe the Canceled and Completed events (line 10 – 13).

public void Run(IBackgroundTaskInstance taskInstance)
{
    _systemMediaTransportControl = SystemMediaTransportControls.GetForCurrentView();
    _systemMediaTransportControl.IsEnabled = true;
            
    BackgroundMediaPlayer.MessageReceivedFromForeground += MessageReceivedFromForeground;
    BackgroundMediaPlayer.Current.CurrentStateChanged += BackgroundMediaPlayerCurrentStateChanged;

    // Associate a cancellation and completed handlers with the background task.
    taskInstance.Canceled += OnCanceled;
    taskInstance.Task.Completed += Taskcompleted;

    _deferral = taskInstance.GetDeferral();
}

private SystemMediaTransportControls _systemMediaTransportControl;
private BackgroundTaskDeferral _deferral;

 

Let’s first make sure we handle the closing of the background task correctly. The implementation of playing music can wait a bit. Make sure that you save some state if required in the OnCanceled implementation before completing the deferral.

private void Taskcompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
    BackgroundMediaPlayer.Shutdown();
    _deferral.Complete();
}

private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    // You get some time here to save your state before process and resources are reclaimed
    BackgroundMediaPlayer.Shutdown();
    _deferral.Complete();
}

 

Yes I know, now it’s time to implement the Play back code. Our UI did send a Message to the Background Audio Task, so we need to handle that message. The handling of the message happens in the MessageReceivedFromForeground method. We’re getting the ValueSet message as an argument and need to loop through the ValueSet keys to process the message. If we find a key with the value “Play” (line 8), we want to start the playback of the value passed to the message (line 10).

private void MessageReceivedFromForeground(object sender, MediaPlayerDataReceivedEventArgs e)
{
    ValueSet valueSet = e.Data;
    foreach (string key in valueSet.Keys)
    {
        switch (key)
        {
            case "Play":
                Debug.WriteLine("Starting Playback");
                Play(valueSet[key].ToString());
                break;
        }
    }
}

 

The implementation isn’t that difficult, most of the code behind the Play method is the updating of the Universal Volume Control with the correct information. For the playing we set AutoPlay and the UriSource (lines 3-5).

private void Play(string toPlay)
{
    var mediaPlayer = BackgroundMediaPlayer.Current;
    mediaPlayer.AutoPlay = true;
    mediaPlayer.SetUriSource(new Uri(toPlay));

    //Update the universal volume control
    _systemMediaTransportControl.ButtonPressed += MediaTransportControlButtonPressed;
    _systemMediaTransportControl.IsPauseEnabled = true;
    _systemMediaTransportControl.IsPlayEnabled = true;
    _systemMediaTransportControl.DisplayUpdater.Type = MediaPlaybackType.Music;
    _systemMediaTransportControl.DisplayUpdater.MusicProperties.Title = "Test Title";
    _systemMediaTransportControl.DisplayUpdater.MusicProperties.Artist = "Test Artist";
    _systemMediaTransportControl.DisplayUpdater.Update();
}

 

Now we have audio playing, but the Universal Volume Control isn’t working completely yet. We need to make sure that PlaybackStatus of the SystemMediaTransportControl is reflecting the MediaPlayer state. The code is straightforward but needs to be there.

private void BackgroundMediaPlayerCurrentStateChanged(MediaPlayer sender, object args)
{
    if (sender.CurrentState == MediaPlayerState.Playing)
    {
        _systemMediaTransportControl.PlaybackStatus = MediaPlaybackStatus.Playing;
    }
    else if (sender.CurrentState == MediaPlayerState.Paused)
    {
        _systemMediaTransportControl.PlaybackStatus = MediaPlaybackStatus.Paused;
    }
}

 

The Universal Volume Control has buttons we need to handle as well. In this example we just handle the Play and Pause button, but you can think about implementing the Next and Previous buttons as well.

private void MediaTransportControlButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
{
    switch (args.Button)
    {
        case SystemMediaTransportControlsButton.Play:
            BackgroundMediaPlayer.Current.Play();
            break;
        case SystemMediaTransportControlsButton.Pause:
            BackgroundMediaPlayer.Current.Pause();
            break;
    }
}

 

Yes that was all. I know there’s quite a lot of preparations for getting the Background Audio working, but now we can expand this base into a fully fledged audio app.

You can download the full solution here.

∞ Chain now available for Windows Phone

 

To really get good at something you need to do it every day. Chain helps you form these habit in order to achieve your goals. Define the daily actions for the goals you want to achieve. For each day you do that action check it off in the app. After a few days you’ll have a chain. Just keep at it and the chain will grow longer very day. Don’t break the chain!

Don’t break the chain is a productivity method by Jerry Seinfeld which is loosely implemented in Chain.

FEATURES

* Multiple chains tracked individually

* Configurable reminder per chain

* Chains can be pinned as Live Tile to the home screen

* Configurable color per chain

* Forgot to track yesterday? You can track for past days

IDEAS TO TRY OUT

* Drink more water

* Eat breakfast

* Sleep at least 8 hours

* Listen more than talk

* Have an inbox zero

The app can be found in the Windows Phone Store here.

Chain

The journey towards resumable downloads on Windows Phone

First of all, most of you would advise me to use the Background Transfers that are available in Windows Phone. And you are right! Yes you are.

But we can’t initiate a Background Transfer from a Background Agent. I still want do download files in the Background Agent. I know the standard Background Agents won’t help, because they can’t be run any longer than 25 seconds. However we still have the Resource Intensive Agents. And yes the constraints for Resource Intensive are even harder to meet. But when the constrains are met, it can run for 10 minutes. For your information these are the hard constraints to meet.

  • External power is required
  • A WiFi connection, or connected to the internet through a pc
  • The device’s battery level is greater than 90%
  • The screen is locked
  • No active phone call

 

Yes I know, in practice these constraints are only met when the phone is on charger during the night. But still it will happen. So I want to download large files, sometimes the download won’t even complete in the 10 minutes that are available. Which could be cause by a slow or medium WiFi/Internet connection in combination with very large files. So I would like to continue the unfinished downloads the next time the Resource Intensive agent gets to run. So I’ve been working on a solution.

Resumable Downloads

Yes I found a solution, you can find it at the end of this post, but you can read my journey as well. There are interesting parts in my journey, but that’s up to you to read or ignore.

Cheapest request to know the size of the download

I started with a little bit of experimentation, just a simple console app. I know that’s not completely equal to a Windows Phone app, specially a Windows Phone Background Agent. But it’s easy experimenting and because I wanted to use the HttpClient, I expected them to be largely equal. They were equal for the API parts, but not the implementation. But back to my idea, I want to know the size of the download I’m about to start. The cheapest way to get to know this, is by a HTTP HEAD request, instead of a HTTP GET. The HEAD request is identical to GET, but it doesn’t contain the body, being the file in my case.

So how do we do a HTTP Head request, and get the Content Length Header? It’s as easy as the following piece of code.

public static async Task<long?> GetRemoteSize(HttpClient client, Uri uri)
{
    var headRequest = new HttpRequestMessage(HttpMethod.Head, uri);
    HttpResponseMessage response = await client.SendAsync(headRequest);
    return response.Content.Headers.ContentLength;
}

 

It’s interesting code, however for Windows Phone you can immediately forget this. It works in the Command line app, but the ContentLength header is somehow not available for Windows Phone when doing a HEAD request, it’s always returning 0. This could be caused by the HttpClient implementation, or it’s maybe at a lower level, I don’t know.

If I modify the method above, to a HTTP GET request where I ask the method to complete as early as when the headers are read. I don’t want to wait for the whole 80 MiB file to be downloaded, just to know the size of the Download.

private async Task<long?> GetRemoteSize(HttpClient client, Uri uri)
{
    var headRequest = new HttpRequestMessage(HttpMethod.Get, uri);
    HttpResponseMessage response = await client.SendAsync(headRequest, HttpCompletionOption.ResponseHeadersRead);
    return response.Content.Headers.ContentLength;
}

That’s working, nice! So I can at least get the length of the download when I start the download. That will enable me to check if they bytes I’ve written to the file are the complete download. I will not make this call as a separate method call, like the method above. This was just experimentation.

The Range Header, or better the Header that enables a partial download aka resume

Let’s say we’ve been downloading for 10 minutes, but the download did not finish yet. We’ve already downloaded 45 MiB of the in total 80 MiB file. We want to continue with the download as soon as our Resource Intensive Agent gets run. So we need to tell the remote server which of the bytes we want from them. Here we have the HTTP Range header to help us out. It’s not available via method or properties, but we can set it very easily. So in below example I wanted to download all the content starting from 45 MiB. The HttpRequestMessage would read like this.

var readRequest = new HttpRequestMessage(HttpMethod.Get, originToDownload);
readRequest.Headers.Add("Range", string.Format("bytes={0}-", 45*1024*1024));

 

The range that you add to the Range header can end with a dash when you want to get all the remaining bytes. This works fine on the Console application, but it fires an InvalidOperationException telling “Nullable object must have a value” on Windows Phone. Sounds like the upper range being empty isn’t supported on Windows Phone.

I did investigate it a little bit, but not too much. I now fill the upper part of the range with long.MaxValue and that seems to work.

var readRequest = new HttpRequestMessage(HttpMethod.Get, originToDownload);
readRequest.Headers.Add("Range", string.Format("bytes={0}-{1}", 45*1024*1024, long.MaxValue));

Be aware that the ContentLength header you’re getting in the response will contain the actual length of bytes that are sent. So in the above case it will show the amount of bytes remaining 45 MiB done of the 80 MiB, means 35 MiB in the Content and 36700160 (35*1024*1024) as ContentLength.

The Solution

If you combine the Range header with the knowledge we gained about getting the ContentLength we can write a method like this:

private async Task<bool> Download(HttpClient client, Uri originToDownload, string targetToDownloadTo)
{
    var readRequest = new HttpRequestMessage(HttpMethod.Get, originToDownload);

    StorageFile fileToDownloadTo = await ApplicationData.Current.LocalFolder
        .CreateFileInPathAsync(targetToDownloadTo, CreationCollisionOption.OpenIfExists);
    using (Stream writeStream = await fileToDownloadTo.OpenStreamForWriteAsync())
    {
        writeStream.Seek(0, SeekOrigin.End);
        long currentLength = writeStream.Length;
        if (currentLength > 0)
            readRequest.Headers.Add("Range",
                string.Format("bytes={0}-{1}", currentLength, long.MaxValue));
        using (HttpResponseMessage response =
            await client.SendAsync(readRequest, HttpCompletionOption.ResponseHeadersRead))
        {
            long? remoteSize = response.Content.Headers.ContentLength;
            long totalRead = 0L;
            if (remoteSize == 0)
            {
                //All bytes have already been read.
                return true;
            }
            using (Stream stream = await response.Content.ReadAsStreamAsync())
            {
                var buffer = new byte[1024*64];
                int bytesRead;
                do
                {
                    bytesRead = stream.Read(buffer, 0, buffer.Length);
                    writeStream.Write(buffer, 0, bytesRead);
                    await writeStream.FlushAsync();
                    totalRead += bytesRead;
                } while (bytesRead != 0);
            }
            if (remoteSize == totalRead)
            {
                return true;
            }
            return false;
        }
    }
}

If you want to copy paste, you will need the helper method to CreateFileInPathAsync.

public static async Task<StorageFile> CreateFileInPathAsync(this StorageFolder parentFolder, string path,
                                                            CreationCollisionOption collisionOption)
{
    string folderPath = path.Substring(0, path.LastIndexOf('/'));
    string fileName = path.Substring(path.LastIndexOf('/') + 1);
    StorageFolder targetFolder = await EnsureFolderExistsAsync(parentFolder, folderPath);
    if (targetFolder != null)
    {
        return await targetFolder.CreateFileAsync(fileName, collisionOption);
    }
    return null;
}

public static async Task<StorageFolder> EnsureFolderExistsAsync(this StorageFolder parentFolder, string path)
{
    StorageFolder currentFolder = parentFolder;
    var pathElements = path.Trim('/').Split('/');
    foreach (string name in pathElements)
    {
        currentFolder = await currentFolder.CreateFolderAsync(name, CreationCollisionOption.OpenIfExists);
    }
    return currentFolder;
}

Memory Usage

It’s very nice we now have a way to download large files, and when required resume them. However be careful around memory usage. In my application I already have the SQLite db-engine in memory, so there’s not much memory left. So even though you can download multiple files after each other the memory usage increases. I stop downloading more files when I’ve less than 1.5 MiB of memory left. Not sure if this will be the sweet spot for your app, I’ve tried keeping that thresshold smaller but got Out of Memory exceptions quite often. So you’ve been warned.

Final notes

Now I created a method to download large files and even resume downloads, I can’t recommend to use it in every place. Use it where appropriate and where the better alternative Background Transfers can’t be used. I can’t think of any place other than a background agent to use this. But there might be others.

In the end this is something that can be used in any other .NET application, with a small set of modifications maybe to suit the targeted platform.

Better reaction on the activation by the Universal Volume Control

As most of you know, you can always start or activate the audio application from which the background audio originates by tapping the Universal Volume Control. Have you noticed that it rarely activates the screen you expect? I did!

To be even honest my own audio playing app P | Cast failed here as well. Specially with the secondary tiles. When you’ve activated the app and playback with from the car mode secondary tile, the reactivation by tapping the Universal Volume Control would always launch the main page.

How can we change the page that’s activated through the Universal Volume Control?

We can’t change it really. It’s just how the Universal Volume Control works. It activates the main form. However, it does add something, an URI parameter. It’s adding the parameter tag and the value is equal to the tag you can provide to the Audio Track you ask the Background Audio to play.

So very interesting we should be able to for example activate a details page that’s belonging to the playing track. I did something differently, I wanted to make sure that the last tile that’s used to activate the app (primary or secondary) is used when activated by the Universal Volume Control.

My app already contains an implementation of the UriMapperBase which allows to convert a request URI into a new URI based on my own mapping rules. So I only had to add a specific rule when the URI contains tag=. I would like to remind you that the implementation inside the if-statement can be modified to your own needs.

internal class AssociationUriMapper : UriMapperBase
{
    public override Uri MapUri(Uri uri)
    {
        Debug.WriteLine("MapUri {1}: {0}", uri, DateTime.Now.ToLongTimeString());
        if (uri.ToString().Contains("tag="))
        {
            App currentApp = (App)Application.Current;

            Debug.WriteLine("Activation through Universal Volume Control, so map to: {0}", currentApp.LastActivationUrl);
            if (currentApp.LastActivationUrl != null)
                return currentApp.LastActivationUrl;
            return uri;
        }
        // Eventually add some other mapping rules.
        // Otherwise perform normal launch.            
        return uri;
    }
}