Tag Archives: Windows Phone

Playing Media in Windows Universal Apps

I recently had cause to write a universal app that has voice capabilities. Hopefully it will shortly be available on the Windows Store.

Adding voice synthesis, while a seemingly basic task, proved to be anything but. What follows is a series of trials and tribulations that I have overcome in order to bring this app to the public!

The Code

Here’s the basic code to get started.

                var voiceStream = await synth.SynthesizeTextToStreamAsync("Hello");
                
                MediaElement mediaElement = new MediaElement();

                mediaElement.SetSource(voiceStream, voiceStream.ContentType);
                mediaElement.AutoPlay = false;
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;

                mediaElement.Play();

Windows Phone

The first issue I encountered with Windows Phone was the volume. Having maxed out my laptop speakers, I managed get a faint whimper. What I finally deduced is that, for some reason, when the emulator starts, it starts at half volume. To increase it you have to press the phone’s volume buttons (which I initially assumed were just there for aesthetics. Clearly Microsoft haven’t entirely abandoned skeuomorphism.

Phone

The volume controls are the top right buttons (which I happened to know because I have owned a Windows Phone in the past). Once you press it then a more sensible interface appears and you can change either the ringer volume, or the game volume.

Overtalking

Although the code above does work, try calling the code in a loop (or just twice). What happens is that it doesn’t wait for itself to finish.

What I didn’t realise (until I asked this) was that there are some events which supposedly fire when the media element has finished playing.

                var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
                
                MediaElement mediaElement = new MediaElement();

                mediaElement.Loaded += mediaElement_Loaded;
                mediaElement.MediaEnded += mediaElement_MediaEnded;
                mediaElement.MediaFailed += mediaElement_MediaFailed;

                mediaElement.SetSource(voiceStream, voiceStream.ContentType);
                mediaElement.AutoPlay = false;
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;
                
                mediaElement.Play();

I say supposedly, because when I first tried to capture the events, they did nothing. After a bit of searching, it turns out that the element needs to be part of the visual tree! Which of course makes total sense – an AUDIO media element must be part of the VISUAL tree.

In the Visual Tree

The code below now looks for the media element in the visual tree, and if it can’t find one, adds it. It also uses the TaskCompletionSource object to await the audio stream.

            using (SpeechSynthesizer synth = new SpeechSynthesizer())
            {
                var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
                
                MediaElement mediaElement;
                
                mediaElement = this.rootControl.Children.FirstOrDefault(m => (m as MediaElement) != null) as MediaElement;
                if (mediaElement == null)
                {
                    mediaElement = new MediaElement();
                    this.rootControl.Children.Add(mediaElement);
                }
                
                mediaElement.SetSource(voiceStream, voiceStream.ContentType);                
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;

                var tcs = new TaskCompletionSource<bool>();
                mediaElement.MediaEnded += (o, e) => { tcs.TrySetResult(true); };
                mediaElement.Play();

                await tcs.Task;
                
            }

That works. At least, it works on Windows Phone. Because it uses a media element, I thought putting it on a shared XAML page would work… but it doesn’t. Windows 8.1 just sits there quietly and says nothing.

Windows Store

After much trial and error, it occurred to me (prompted by a comment on the above question) that if the problem was down to a deadlock, then destroying and recreating the control might clear this up.

Amazingly, that did seem to work; the working code is:

            using (SpeechSynthesizer synth = new SpeechSynthesizer())
            {
                var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);

                MediaElement mediaElement;

                mediaElement = rootControl.Children.FirstOrDefault(a => a as MediaElement != null) as MediaElement;
                if (mediaElement == null)
                {
                    mediaElement = new MediaElement();
                    
                    rootControl.Children.Add(mediaElement);
                }

                mediaElement.SetSource(voiceStream, voiceStream.ContentType);
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;

                var tcs = new TaskCompletionSource<bool>();                
                mediaElement.MediaEnded += (o, e) => { tcs.TrySetResult(true); };               

                mediaElement.Play();                

                await tcs.Task;

                rootControl.Children.Remove(mediaElement);

            }

And this does seem to work on both platforms.

Adding a tile to Windows Phone (Annoying and unhelpful errors – Part 2)

Following on from this post, I encountered the following error:

Value does not fall within the expected range.

Here’s the culpable code again:

SecondaryTile tileData = new SecondaryTile()
{
    TileId = title,
    DisplayName = title,
    Arguments = arguments
};
tileData.VisualElements.Square150x150Logo = new Uri("ms-appx:///assets/TileIcon150x150.png");
tileData.VisualElements.ShowNameOnSquare150x150Logo = true;

And, as is typical with these things, it worked yesterday, when I wrote the above post. So, why now, when I run it, does it point to the instantiation of `SecondaryTile` above and cry foul?

This time, it was caused by the ID containing an invalid character (a space). Something similar to the following will fix it:

SecondaryTile tileData = new SecondaryTile()
{
    TileId = title.Replace(" ", ""),
    DisplayName = title,
    Arguments = arguments
};
tileData.VisualElements.Square150x150Logo = new Uri("ms-appx:///assets/TileIcon150x150.png");
tileData.VisualElements.ShowNameOnSquare150x150Logo = true;

Windows Tile Updater (Part 6 – Binding a command parameter)

We’re still missing functionality to show the text, or show the text and an image where both are specified.

Add text

Let’s start with the text field. It’s currently just hard coded – that’s pretty straightforward:

        <StackPanel Orientation="Horizontal" Margin="20" Grid.Row="1">
            <TextBlock FontSize="30" Margin="10">Text</TextBlock>
            <TextBox Text="{Binding DisplayText, Mode=TwoWay}" Margin="10"/>
        </StackPanel>

Next, let’s hook this up to the command.

<Button Grid.Row="2" Command="{Binding UpdateCommand}" CommandParameter="{Binding DisplayText}">Update</Button>

So that works, and the logic to show the text tile is quite straightforward:

        public static void UpdateTileText(string text)
        {
            XmlDocument xmlDoc = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150Text01);

            XmlElement textNode = (XmlElement)xmlDoc.GetElementsByTagName("text")[0];
            textNode.InnerText = text;

            Windows.UI.Notifications.TileUpdater tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
            TileNotification tileNotification = new TileNotification(xmlDoc);
            tileUpdater.Update(tileNotification);
        }

So, we can call this, or we can call the UpdateImage. At the moment, we can’t call both. In the next post I’ll look at how we can do this using Multibinding.

iPhone versus Windows Phone – Why Nokia / Microsoft lost my business

In a divergence from my usual software development ramblings, I thought I’d post my opinions on my latest phone (an iPhone 5c), along with how it stacks up against my previous Nokia Lumia 800

Why Windows Phone

If you have a look through my previous posts, you’ll see the reason for my choosing a Windows Phone last time. I spend a lot of time programming for mobile devices, and I have one Windows Phone 8 app published. Of course I can’t run that on the Lumia… and here’s where Microsoft first started to lose me.

Before getting the phone I looked around at some other phones. I’ve had Apple products before, and have generally been satisfied. I’m not a mad Apple fan, but I have a couple of iPods and an iPad. They work okay. And all the apps that are likely to be written have been written 15 times over.

Windows Phone was new, and it had a very small app base – there was the opportunity! Also, I’d had a Nokia phone before (5120 I think), and it was indestructible!

In general, the Nokia did mostly what I expected – it was very sturdy; I frequently dropped it, scuffed it, and generally treated it the same way that I treated my previous Nokia. The touch screen was excellent and reacted as expected. The Windows 7.1 phone interface was nice. The iPhone feels flimsy and breakable by comparison (as evidenced by the number of people that everyone knows using an iPhone with a smashed screen).

Another excellent feature was the tethering. Given that this was the first phone I’d had that I could tether to, I didn’t realise how good it was until I got the iPhone. Here’s my laptop network screen sat next to the iPhone with Personal Hotspot switched on:

hotspot

To get the laptop to recognise the iPhone I have to turn the personal hotspot of and on again a few times. Windows Phone always worked first time; I’m very aware that I’m pointing out that Windows works with Windows, but if you tether a lot, this can be a factor.

Bad Stuff

There were a number of annoying factors, but the absolute worse was the heat. I couldn’t keep the phone in my pocket, because it literally burned me. I imagine a related factor was the battery life, which was abysmal (I basically needed to charge it 2 – 3 times a day just for basic use).

Zune was also a let-down. I couldn’t fit all my music on the device, so I tried to use playlists, as I’d previously done with the iPhone, but Zune insisted on clearing and re-filling the phone every time; meaning that syncing it took prohibitively long. The playback on the phone was also a poor experience: I’d be listening to a the latest edition of DotNetRocks, pause it, and then if I continued to use the phone, it would forget the position I’d listened to and start again. Of all the bad features, this was the absolute worse.

My last gripe about Windows Phone it what Microsoft did when they introduced Windows Phone 8. As I said earlier, I bought this to do development, and after having it for 6 months, it felt like a giant two finger solute from Microsoft, saying that Phone 8 was out and old phones would not upgrade. I know apple and Android both do this, but they can afford to; they have large and loyal user bases.

Happy with the iPhone?

Like I said, it’s flimsy, and overpriced; however:
– It has an excellent GPS.
– I can carry it in my pocket without having to be treated for second degree burns.
– It has a mature and large app base.
– iTunes is not perfect, but it does work.
– The stuff I play on it remembers where it was stopped.

I did consider getting another Windows Phone when it was time to renew, but ultimately, I couldn’t justify it. The Nokia Phones that are available for 8 didn’t strike me as particularly good this time around (they don’t even look that sturdy now), and ultimately, I couldn’t risk MS releasing Windows Phone 9 and leaving me behind again.

Windows Tile Updater (Part 2 – creating the project and tile update logic)

In my first post of this series I looked at some considerations of designing a store / phone app. This post will cover the basics of creating a new Phone / Store app.

Universal App

The new type of application is called a Universal App – so let’s create one:

NewUniversal

I’m going to select a blank app, and create the project. What this gives me is a solution containing three separate projects.

UniversalSolutionExplorer

If I select to run the Windows app I get a blank Windows Store App, and if I select to run the phone app I get a blank phone app. The shared project can be used to create a common application lifecycle, share events and logic. However, the UI is separate (ish – we’ll come back to that in a later post). Let’s start with the Window 8 app

Create the tile image

You can’t update a tile that doesn’t exist; for this example, we’re going to update the wide tile, so you’ll need one. Just create any image 310 x 150 as a png file and point your Windows app at it:

universalmanifest

The app will use a wide tile if it is present on the first install only. If you miss this, then uninstall using the following option:

universaluninstall

Create the tile updater

Next, create another tile image – just copy the first and change the text or draw something on it. Add this to your Windows 8.1 project, and call it test.png (place it under the Assets folder).

The code to update a tile in Windows 8 is as follows:

        private static void UpdateTileImage(string image)
        {
            XmlDocument xmlDoc = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150Image);

            XmlElement imageNode = (XmlElement)xmlDoc.GetElementsByTagName("image")[0];
            imageNode.SetAttribute("src", string.Format("ms-appx://{0}", image));

            Windows.UI.Notifications.TileUpdater tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
            TileNotification tileNotification = new TileNotification(xmlDoc);
            tileUpdater.Update(tileNotification);
        }

A little (actually not so little) gotcha is that Live Tiles don’t work in the simulator (http://social.msdn.microsoft.com/Forums/windowsapps/en-US/8357462e-f97b-48c2-8fea-57d47c7ead2a/do-live-tiles-updated-properly-in-the-simulator?forum=toolsforwinapps)

Testing is further complicated because tiles are not automatically pinned to the start menu; so you may deploy and not see your tile. Even worse, I noticed a few times that despite the tile not being on the start screen, on searching for it, Windows claimed it was (so I had to un-pin and re-pin).

Just write the code for Windows

Okay, so let’s just create the tile updater inside Windows 8.1 (this is the code for MainPage.xaml.cs):

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            UpdateTileImage();
        }

        private void UpdateTileImage(string image)
        {
            XmlDocument xmlDoc = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150Image);

            XmlElement imageNode = (XmlElement)xmlDoc.GetElementsByTagName("image")[0];
            imageNode.SetAttribute("src", string.Format("ms-appx://{0}", image));

            Windows.UI.Notifications.TileUpdater tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
            TileNotification tileNotification = new TileNotification(xmlDoc);
            tileUpdater.Update(tileNotification);
        }

        public void UpdateTileImage()
        {
            string image = "/Assets/test.png";
            UpdateTileImage(image);
        }

If you need the XAML, it’s here:

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="20" Grid.Row="0">
            <TextBlock FontSize="30" Margin="10">Image</TextBlock>            
            <TextBox Text="c:locationimage.png" Margin="10"/>
        </StackPanel>
        
        <StackPanel Orientation="Horizontal" Margin="20" Grid.Row="1">
            <TextBlock FontSize="30" Margin="10">Text</TextBlock>
            <TextBox Text="My Phone Number: 123456 890 12" Margin="10"/>
        </StackPanel>

        <Button Grid.Row="2" Click="Button_Click">Update</Button>

Conclusion

You now have a little program for Windows 8.1 that updates tiles based on a button click. In the next post, we’ll move this into the shared project and call it from the phone app, too. In later posts, I’ll change and refactor the architecture, too.

Windows Tile Updater (Part 1 – design)

A walkthrough of creating a Windows Universal App from scratch

There is a new type of project that allows the creation of Windows 8 and Windows Phone apps. I thought I’d run through creating a simple app (I’m also going to try and publish it in the store).

Design

This seems a little extravagant – a design. Having said that (I believe) you should at least be able to state what your program is intended to do in one or two sentences:

My program will display a tile notification on the start screen that can be defined by the user.

You should also try to decide the answers to the following questions:
1. Will all or part of your app be required to run outside Windows?
2. Do you expect to make money, and if so, how?
3. Does your idea have any competition, and if so, why will anyone look at your idea?

My answers are:
1. No – this is a demo app, so it will be entirely Windows. If the answer is yes then research mono, portable class libraries and Xamarin.
2. No. I may however add some advertising in a later post just to show how it’s done (to make money from advertising, you need very high usage of your app – also, at the time of writing, Microsoft’s fill rate for adverts was a little over 30%).
3. Yes – there are other apps that do this. At the time of writing, I hadn’t spotted an app that shared the tiles between phone and desktop – although I’m confident there will be one. The only reason anyone might choose to use this over another one would be because the source code will be publicly available. You might want a more convincing argument than this for your own work.

So, you’ve decided what the app will do, whether and how it will earn you a fortune, and why people will choose your app over the competition. The next thing is deciding what it will look like. Windows doesn’t leave too much scope for imaginative designs here – it needs to look Metro; having said that, I don’t think I’ve ever had an app fail on appearance.

Here’s my design for Windows:

Win8DT

For Windows Phone:

WP8

And:

TileAppDesign

As you can see, this is a complex and detailed design. Although, from my experience, anything more detailed than this back-of-a-fag-packet screenshot and general concept is a waste at this stage. However, there is one more thing that you should probably do:

Minimum Viable Product (MVP)

You need to decide what you can release with. I think this applies regardless of whether you’re a big company or just some bloke on a train writing software for fun. This should be the absolute least that your application can accomplish and still be your application.

In my case, it’s pretty minimalist as it is, so there’s little point, but you should probably decide the features that are necessary:

– Ability to set text for a tile
– Ability to set image for a tile

Maybe my MVP doesn’t need to include an image – just text? If you release and people download, then add the other features. This is basically a fallback for people who can’t or don’t use a product backlog. It’s essentially the same idea, but it doesn’t come with the overhead of the word agile*.

Conclusion

Now we have a design, in the next post, I’ll post some code.

* My opinion of agile is not that it is an overhead – simply that the word carries a lot of misconceptions and assumptions that may detract from its purpose and primary benefits.