Improve Remote Desktop frame rate to 60fps by enabling AVC 4:4:4 encoding

I am a great fan of Remote Desktop and have been using it for over a decade. It’s built in and just works. One gripe of mine has always been the poor framerate which makes animations and transitions super janky by default.

In RDP 10 it turns out this can be massively improved by enabling a screen encoding based on AVC/H.264 video. By enabling the group policy “Prioritize H.264/AVC 444 graphics mode for Remote Desktop Connections” under Computer Configuration > Administrative Templates > Windows Components > Remote Desktop Services > Remote Desktop Session Host > Remote Session Environment, I was able to get a glorious 60fps, almost double what I was getting before.

There is also another group policy to use your GPU to do the encoding, “Configure H.264/AVC hardware encoding for Remote Desktop connections”. Turn this on and you can see your GPU in task manager doing a little bit of work to encode the video, potentially saving the CPU from some effort. However in my testing I actually saw slightly worse performance in this mode, as you can see from this video:

Improve Remote Desktop frame rate up to 60fps!
Watch this video on YouTube.

I do wonder why this option is buried in Group Policy and not more user accessible – it appears to be enabled by default in cloud hosted environments with virtual GPUs (such as the Azure GPU instances). I also wonder if you can actually game using it?

Using Google APIs and Auth in Xamarin Forms

I’m working on porting Net Writer from UWP to Android using Xamarin Forms. The Google authentication is a little bit tricky as it is constantly changing. Working off this amazing blog post by Timothé Larivière got me 90% of the way there but there are some updates to the process in 2020.

Pre-requisites to register an app with Google

At this point in time you’ll need to do the following before you can register a Public app:

  •  Create a project in GCP via the Google Developer Console
  •  Verify a domain via the Google Search Console. To do this you will need access to your nameserver and DNS records in order to copy and paste a TXT record. Access this here.
  •  Know the SHA-1 fingerprint of the key that will be used to sign your package

Getting the SHA-1 fingerprint used to sign a locally deployed debug Xamarin Forms app

You’ll need to do this:

  •  In Visual Studio, go to Tools > Android > Android Adb Command Prompt
  •  Navigate to C:\Users\{username}\AppData\Local\Xamarin\Mono for Android

Run the command

keytool -keystore debug.keystore -list -v

And when prompted enter the keystore password “android”.

You’ll see a result like this:

The SHA1 value is what you need.

Registering the application

You should have everything you need now. Go to Credentials in the GCP panel and create the OAuth consent screen. Fill in the details (you’ll need the verified domain you created earlier).

Then you can create an OAuth 2.0 Client ID. Select “Android” as the platform and enter the package name from AndroidManifest.xml and the SHA-1 fingerprint you figured out earlier. You’ll see something like the below:

Adding the code

The approach I have taken is to create a class in the main Android project to encapsulate everything, rather than putting the logic inside the Mobile/PCL project. This is because the Android version needs references to Activities and other Android-specific concepts to work effectively. It’s not just a case of adding Xamarin.Auth and calling a method unfortunately.

Using Xamarin Forms dependency injection I can refer to and call this class within the portable Mobile project when I need an access token from the API.

The token reader class

There are some nuget dependencies you’ll need for this – the “Google.Apis.Auth” libraries for the TokenResponse class (although you can probably remove the dependency from the below code if you’d like), “Xamarin.Auth”, “Xamarin.Auth.XamarinForms” and “Plugin.CurrentActivity”. The last one allows code outside of an Activity to get access to the current Activity.

    public class GoogleAccessTokenReader : IGoogleAccessTokenReader
    {
        public static readonly string[] GoogleAPIScopes =
        {
            DriveService.Scope.DriveFile,
            BloggerService.Scope.Blogger
        };

        public static TokenResponse Token { get; set; }

        public static OAuth2Authenticator Auth;

        public async Task<TokenResponse> GetOrNullAsync()
        {
            if (Auth == null)
            {
                Auth = new OAuth2Authenticator(
                "your-client-id",
                string.Empty,
                String.Join(" ", GoogleAPIScopes),
                new Uri("//accounts.google.com/o/oauth2/v2/auth"),
                new Uri("com.yourpackageid:/oauth2redirect"),
                new Uri("//www.googleapis.com/oauth2/v4/token"),
                isUsingNativeUI: true);

                Auth.Completed += OnAuthenticationCompleted;
            }

            if (Token != null) return Token;


            Xamarin.Auth.CustomTabsConfiguration.CustomTabsClosingMessage = null;

            var intent = Auth.GetUI(CrossCurrentActivity.Current.AppContext);

            CrossCurrentActivity.Current.Activity.StartActivity(intent);

            while(!Auth.HasCompleted)
            {
                await Task.Delay(500);
            }

            return Token;
        }

        private void OnAuthenticationCompleted(object sender, AuthenticatorCompletedEventArgs e)
        {
            if (e.IsAuthenticated)
            {
                Token = new TokenResponse()
                {
                    AccessToken = e.Account.Properties["access_token"],
                    TokenType = e.Account.Properties["token_type"],
                    Scope = e.Account.Properties["scope"],
                    ExpiresInSeconds = int.Parse(e.Account.Properties["expires_in"]),
                    RefreshToken = e.Account.Properties["refresh_token"]
                };

             }
         }

    }

Add the following dependency injection declaration to the namespace:

[assembly: Dependency(typeof(NetWriter.Mobile.Droid.GoogleAccessTokenReader))]

Where NetWriter.Mobile.Droid should be replaced with your namespace.

You can use this interface too as IGoogleAccessTokenReader (or change depending on your needs):

using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Responses;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace BlogWriter.Shared.NetStandard.Interfaces
{
    public interface IGoogleAccessTokenReader
    {
        Task<TokenResponse> GetOrNullAsync();
    }
}

Add the activity that receives the response

Somewhere in your main Android app you should add the following:

 [Activity(Label = "GoogleAuthInterceptor")]
    [IntentFilter(actions: new[] { Intent.ActionView },
              Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
              DataSchemes = new[]
              {
                  "com.yourpackageid"
              },
              DataPaths = new[]
              {
                   "/oauth2redirect"
              })]
    public class GoogleAuthInterceptor : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            Android.Net.Uri uri_android = Intent.Data;

            var uri_netfx = new Uri(uri_android.ToString());

            GoogleAccessTokenReader.Auth?.OnPageLoading(uri_netfx);

            var intent = new Intent(this, typeof(MainActivity));
            intent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
            StartActivity(intent);

            Finish();
        }
    }

The last three lines before Finish() are really important as they actually make the Google login window go away after logging in. if you don’t add them it will stay there and the user will need to manually close the window.

Retrieving the token from within your app

Using the Xamarin Forms dependency injection system, you can get an instance of the token reader like:

var reader = DependencyService.Get<IGoogleAccessTokenReader>();
var token = await reader.GetOrNullAsync();

Coming soon

Refresh tokens, remembering the login and other stuff. Oh my!

Demo video

If you want a walkthough of doing this, you can watch the following video:

How to add Google Login and Auth to Xamarin Forms
Watch this video on YouTube.

UWP and Xamarin Forms – How to display your app’s version number

Assume we want to automatically show the version number of your app in your UI, for example, the settings page or elsewhere. Your version number will normally be updated by your CI/CD system (updating Package.appxmanifest for UWP and AndroidManifest.xml for an Android Xamarin app).

Create a property to bind to

ViewModels and how they bind to your UI are out of scope for this post (as you’ll have already got this far). However, if you add a property to your view model like this:

        public string VersionString 
        { 
            get
            {
                return "hello";
            } 
        }

We can use this to test the binding before updating to the actual version number later.

Bind to it using UWP

For UWP you’ll need to use the TextBlock control and bind the Text property:

<TextBlock Text="{Binding VersionString}"></TextBlock>

Bind to it in Xamarin Forms

Xamarin Forms has a slightly different flavour, so you’ll need to use the Label control:

<Label Text="{Binding VersionString}"></Label>

Check the UI

You’ll see the following in your app:

Updating the binding to show the version number

Because getting the version number differs by platform, you should use the super awesome Xamarin Essentials library.

Add nuget package to your Mobile class library and your UWP app following the documentation.

Then add the following using statement to the top of your ViewModel:

using Xamarin.Essentials;

And update your property code:

        public string VersionString 
        { 
            get
            {
                return "Version " + AppInfo.VersionString;
            } 
        }

That’s it! Xamarin Essentials handles the cross platform bits.

Confirm the version number is displayed 

Relaunch your UWP app and you’ll see:

Launch the Xamarin app and you’ll see:

These values are pulled from Package.appxmanifest and AndroidManifest.xml respectively.

Demo video

Here is a nice YouTube Style™ video demo of the above:

Display App Version Number in Xamarin Forms and UWP
Watch this video on YouTube.