Using Avalonia UI framework and LibVLCSharp library to play URI based audio

Published:

Modified:

Introduction

Welcome to the Avalonia UI audio playback demo! We’ll be using Avalonia UI and LibVLCSharp library to play an audio file.

The complete source code is available within Monsalma Avalonia UI GitHub repository.

Avalonia is an open source framework for building beautiful, cross-platform applications from a single .NET codebase. To get familiar with the platform, please navigate to the official Avalonia UI website, documentation and GitHub page.

LibVLCSharp is a cross-platform audio and video API for .NET platforms based on VideoLAN’s LibVLC Library. To get a basic idea of the library, please check out the LibVLCSharp NuGet package and browse the official LibVLCSharp documentation. If you want to go straight to the official code samples, continue your research at the LibVLCSharp “How Do I do X” page.

The Goal

This demo is about:

This demo is NOT about:

Step by Step Walk-through

Now I’ll walk you through the process of creating the demo project from scratch.

Step 1 – Create the project

Launch Visual Studio 2022 and hit the “Create a new project” button:

Avalonia UI - Audio Test - Create a new project
Avalonia UI – Audio Test – Create a new project

Step 2 – Select project type

Let’s select “Avalonia C# project” and hit Next:

Avalonia UI - Audio Test - Select project type
Avalonia UI – Audio Test – Select project type

Step 3 – Configure the project (project name and location)

Enter the name you like, enter location or browse to the location and hit Create:

Avalonia UI - Audio Test - Enter project name and location
Avalonia UI – Audio Test – Enter project name and location

Step 4 – Avalonia project configuration 1/3 – Target platforms

Now it’s time to start configuring Avalonia UI related stuff. First we need to select target platforms. For this demo I used only Windows Desktop and Android, but feel free to play around with other platforms. Hit the Next button after you’re done selecting target platforms:

Avalonia UI - Audio Test - Select application platforms
Avalonia UI – Audio Test – Select application platforms

Step 5 – Avalonia project configuration 2/3 – Design pattern

As I stated earlier, this demo is not about MVVM design. I chose Community Toolkit because I’m used to it. We will not use view model so feel free to chose a pattern per your liking and hit Next:

Avalonia UI - Audio Test - Select application design pattern
Avalonia UI – Audio Test – Select application design pattern

Step 6 – Avalonia project configuration 3/3 – Features

We will not be using any of these (Compiled Bindings, Embedded Support, Meadow Support). I definitely recommend using compiled bindings for non-trivial projects. For now, just hit the Create button and that will finish the project creation phase:

Avalonia UI - Audio Test - Select application features
Avalonia UI – Audio Test – Select application features

At this point, you should see 3 projects within the solution:

Avalonia UI - Audio Test - Application projects (common, Android and Windows)
Avalonia UI – Audio Test – Application projects (common, Android and Windows)

Step 7 – Modify C# nullable context

For all 3 projects, let’s set the Nullable setting to “Disable”. This is just something I like to do. We need to access project properties by right-clicking the project and selecting Properties. Then we need to locate the setting either by scrolling down or by using the search feature.

Avalonia UI - Audio Test - Modify the Nullable setting
Avalonia UI – Audio Test – Modify the Nullable setting

Step 8 – Modify the default Avalonia UI greeting

This is the most important part of the demo 🙂 Let’s locate and open MainViewModel.cs under the ViewModels folder, and modify the Greeting value:

Avalonia UI - Audio Test - Modify view model
Avalonia UI – Audio Test – Modify view model

Step 9 – Change main window size

Let’s locate and open MainView.xaml, which should be under the Views folder. We need to specify Width and Height. Of course, this will only be applied when running on Windows. On Android, the window size will depend on the device itself.

Avalonia UI - Audio Test - Modify view
Avalonia UI – Audio Test – Modify view

Step 10 – Run the app

At this point we still haven’t added any audio related source code, but let’s try to build the solution and execute the Windows Desktop project (you can execute the Android one if that’s what you prefer). When building, you should get 0 errors. The main application window should look like this:

Avalonia UI - Audio Test - First Execution (Windows)
Avalonia UI – Audio Test – First Execution (Windows)

Step 11 – Install LibVLCSharp package

Now that we’ve verified that we can build and run our application, it’s time to install some NuGet packages. We should first install LibVLCSharp, but only in the main project. We don’t need the package in platform specific projects. After installing the package, NuGet Package Manager should show this:

Avalonia UI - Audio Test - Installing LibVLCSharp NuGet package to the common project
Avalonia UI – Audio Test – Installing LibVLCSharp NuGet package to the common project

Step 12 – Install VideoLAN.LibVLC.Android package

Next, we need to add VideoLAN.LibVLC.Android package, and only to the Android project:

Avalonia UI - Audio Test - Installing VideoLAN.LibVLC.Android NuGet package to the Android project
Avalonia UI – Audio Test – Installing VideoLAN.LibVLC.Android NuGet package to the Android project

Step 13 – Install VideoLAN.LibVLC.Windows package

Similarly, we need to add VideoLAN.LibVLC.Windows package to the Windows Desktop project:

Avalonia UI - Audio Test - Installing VideoLAN.LibVLC.Windows NuGet package to the Windows project
Avalonia UI – Audio Test – Installing VideoLAN.LibVLC.Windows NuGet package to the Windows project

Step 14 – The source code (code behind)

Finally we came to the interesting part – writing the source code! In this section, we’ll focus on the code behind and in the next, we’ll deal with XAML.

Defining main LibVLCSharp objects

private LibVLC MainLibVLC { get; set; }
private MediaPlayer MainMediaPlayer { get; set; }

MainLibVLC is the reference to an object of the LibVLC class, which is the core class within LibVLCSharp package.

We define MainMediaPlayer (MediaPlayer class), which will help us to initiate the playback and track playback progress.

Initializing main LibVLCSharp objects

private void InitMediaPlayer()
{
	MainLibVLC = new(enableDebugLogs: true);
	
	MainMediaPlayer = new(MainLibVLC);
	MainMediaPlayer.TimeChanged += MediaPlayer_TimeChanged;
}

We simply initialize MainLibVLC and then we use it to initialize MainMediaPlayer.

At this point we register handler for the TimeChanged event. We’ll use it to track playback progress.

Defining TimeChanged handler

private void MediaPlayer_TimeChanged(object sender, MediaPlayerTimeChangedEventArgs e)
{
	Dispatcher.UIThread.Invoke(
		new Action(
			() =>
			{
				PlaybackStatus.Text = $"{MainMediaPlayer.Time / 1000.0} / {MainMediaPlayer.Length / 1000.0}";
			}
		)
	);
}

Within the handler, we’re simply using the TextBlock (defined with x:Name in XAML) element to display the current position (MainMediaPlayer.Time) and total media duration (MainMediaPlayer.Length). Both values are in milliseconds, so we’re converting them to seconds.

Since this method updates UI elements, we need to execute it under the UI thread. We use Dispatcher.UIThread.Invoke for that. Without this bit of code, we would get an exception.

Defining the button clicked (Click) handler

public void ClickHandler(object sender, RoutedEventArgs args)
{
	Media media = new(MainLibVLC, new Uri(MediaURI.Text));
	MainMediaPlayer.Media = media;
	MainMediaPlayer.Play();
}

We create the Media object using MainLibVLC and the text from our TextBox control (defined with x:Name in XAML).

Then we link the newly created Media object and MainMediaPlayer.

Finally, we play the media!

Code behind – The complete source code

using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using LibVLCSharp.Shared;
using System;

namespace Monsalma_AvaloniaAudioTest.Views;

public partial class MainView : UserControl
{
    private LibVLC MainLibVLC { get; set; }
    private MediaPlayer MainMediaPlayer { get; set; }

    public MainView()
    {
        InitializeComponent();
        InitMediaPlayer();
    }

    private void InitMediaPlayer()
    {
        MainLibVLC = new(enableDebugLogs: true);
        
        MainMediaPlayer = new(MainLibVLC);
        MainMediaPlayer.TimeChanged += MediaPlayer_TimeChanged;
    }

    public void ClickHandler(object sender, RoutedEventArgs args)
    {
        Media media = new(MainLibVLC, new Uri(MediaURI.Text));
        MainMediaPlayer.Media = media;
        MainMediaPlayer.Play();
    }

    private void MediaPlayer_TimeChanged(object sender, MediaPlayerTimeChangedEventArgs e)
    {
        Dispatcher.UIThread.Invoke(
            new Action(
                () =>
                {
                    PlaybackStatus.Text = $"{MainMediaPlayer.Time / 1000.0} / {MainMediaPlayer.Length / 1000.0}";
                }
            )
        );
    }
}

Step 15 – The source code (XAML)

We’ll use vertical StackPanel to stack:

<StackPanel
		Orientation="Vertical"
		HorizontalAlignment="Center"
		VerticalAlignment="Center">

		<TextBlock
			Text="{Binding Greeting}"
			HorizontalAlignment="Center"
			VerticalAlignment="Center" />

		<TextBox
			x:Name="MediaURI"
			Text="https://github.com/rafaelreis-hotmart/Audio-Sample-files/raw/refs/heads/master/sample.mp3"
			HorizontalAlignment="Center"
			VerticalAlignment="Center" />

		<Button
			Content="Play"
			HorizontalAlignment="Center"
			VerticalAlignment="Center"
			Click="ClickHandler" />

		<TextBlock
			x:Name="PlaybackStatus"
			HorizontalAlignment="Center"
			VerticalAlignment="Center"
			Text="-" />

	</StackPanel>

XAML – The complete source code

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:vm="clr-namespace:Monsalma_AvaloniaAudioTest.ViewModels"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Monsalma_AvaloniaAudioTest.Views.MainView"
             x:DataType="vm:MainViewModel">
	<Design.DataContext>
		<!-- This only sets the DataContext for the previewer in an IDE,
         to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
		<vm:MainViewModel />
	</Design.DataContext>

	<StackPanel
		Orientation="Vertical"
		HorizontalAlignment="Center"
		VerticalAlignment="Center">

		<TextBlock
			Text="{Binding Greeting}"
			HorizontalAlignment="Center"
			VerticalAlignment="Center" />

		<TextBox
			x:Name="MediaURI"
			Text="https://github.com/rafaelreis-hotmart/Audio-Sample-files/raw/refs/heads/master/sample.mp3"
			HorizontalAlignment="Center"
			VerticalAlignment="Center" />

		<Button
			Content="Play"
			HorizontalAlignment="Center"
			VerticalAlignment="Center"
			Click="ClickHandler" />

		<TextBlock
			x:Name="PlaybackStatus"
			HorizontalAlignment="Center"
			VerticalAlignment="Center"
			Text="-" />

	</StackPanel>
</UserControl>

Step 16 – Run the app on Windows

At last – time to play some audio! Hit that Play button and enjoy that favorite song of yours!

Avalonia UI - Audio Test - Windows application demo
Avalonia UI – Audio Test – Windows application demo

Step 17 – Run the app on Android

I used Google Pixel 3 XL – API 30 Android simulator. This is the result:

Avalonia UI - Audio Test - Android application demo
Avalonia UI – Audio Test – Android application demo

Conclusion

In this demo we used Avalonia UI framework and LibVLCSharp library to play an URI based media.

We went step by step from creating and configuring our project and adding LibVLCSharp NuGet packages, to writing our source code in code behind and XAML.

We took a glance at LibVLC, MediaPlayer and Media classes. I hope this demo will serve as a good starting point for delving deeper into the Avalonia UI and LibVLCSharp magic.