Fred913.IosMediaSession 0.2.0

dotnet add package Fred913.IosMediaSession --version 0.2.0
                    
NuGet\Install-Package Fred913.IosMediaSession -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fred913.IosMediaSession" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fred913.IosMediaSession" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Fred913.IosMediaSession" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Fred913.IosMediaSession --version 0.2.0
                    
#r "nuget: Fred913.IosMediaSession, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Fred913.IosMediaSession@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Fred913.IosMediaSession&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Fred913.IosMediaSession&version=0.2.0
                    
Install as a Cake Tool

Fred913.IosMediaSession

A small C# library for reading iPhone media metadata and controlling playback from Windows over Bluetooth LE, using Apple Media Service (AMS).

Targets .NET Standard 2.0, with a Windows Bluetooth backend. The required APIs are available on Windows 10 version 1703 (build 15063) or later. A BLE adapter and an iPhone exposing AMS are required. This is a Windows client for an iPhone; it does not run inside an iOS app. The package contains the class library only: no WinForms UI, GSMTC publisher, or artwork search.

dotnet add package Fred913.IosMediaSession --version 0.2.0

No Windows-specific target framework is required in the consuming project. The same netstandard2.0 assembly has passed protocol tests and real Bluetooth discovery in .NET Framework 4.8 and .NET 8 applications on Windows 11. The Windows 10 minimum is based on the APIs used; this release has not been run on that older OS. Other .NET Standard 2.0 runtimes, including Unity, are not individually validated. macOS, Linux, Android, and iOS Bluetooth backends are not included.

Windows Runtime projections are embedded privately using C#/WinRT. Consumers do not need Microsoft.Windows.SDK.NET.dll, WinRT.Runtime.dll, or a Windows SDK reference. The package carries the standard async and memory dependencies.

Migrating from 0.1.0

InitializeAsync's supported-command callback and SupportedCommandsReceived now use IReadOnlyCollection<byte> instead of IReadOnlySet<byte>, which does not exist in .NET Standard 2.0. Update explicitly typed handlers and recompile. The collection still contains unique command IDs; commands.Contains(id) is available through System.Linq. Other public methods and the AMS protocol are unchanged.

Usage

using Fred913.IosMediaSession;

var devices = await BleDeviceDiscovery.GetDevicesAsync();
foreach (var device in devices)
    Console.WriteLine($"{device.AddressText}  {device.DisplayName}");

// Let your UI/user choose an address from the discovery results.
ulong address = Convert.ToUInt64(args[0].Replace(":", ""), 16);
using var stop = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) => { e.Cancel = true; stop.Cancel(); };

await using var client = await AmsClient.ConnectAsync(address, Console.WriteLine);
void OnUpdate(AmsUpdate update) =>
    Console.WriteLine($"{update.EntityId}/{update.AttributeId}: {update.Value}");
void OnCommands(IReadOnlyCollection<byte> commands) =>
    Console.WriteLine($"Supported commands: {string.Join(", ", commands)}");

client.UpdateReceived += OnUpdate;
client.SupportedCommandsReceived += OnCommands;
await client.InitializeAsync(OnUpdate, OnCommands, stop.Token);

// While RunAsync is active, UI handlers can call:
// client.QueueRemoteCommand(0); // Play, only if the reported set contains 0.
// client.QueueRemoteCommand(1); // Pause, only if the reported set contains 1.
// client.QueueProgressRefresh();
try
{
    await client.RunAsync(stop.Token);
}
catch (OperationCanceledException) when (stop.IsCancellationRequested)
{
    // Normal shutdown; await using releases the BLE connection.
}

Connect → initialize once → run once → cancel and await → dispose. On errors or disconnection, dispose and create a new connection; automatic reconnection and periodic progress refresh are left to the host application. Do not dispose during initialization or while the run loop is active. Cancellation stops the run loop; Windows pairing and an in-flight GATT operation may need time to finish.

Initialization sends its initial values through the supplied callbacks. Subsequent values arrive through the events during RunAsync. Use the same handlers for both. UpdateReceived and SupportedCommandsReceived run on the processing context; marshal to your UI as needed. NotificationReceived and TrackNotificationReceived run directly on the Bluetooth callback thread: keep handlers short and never throw.

Discovery scans for four seconds and merges nearby and paired BLE devices. SupportsAms is a hint from advertisements or the Windows service cache, not proof that a device is currently reachable. The BLE address may differ from the classic Bluetooth address. Unpaired devices require confirmation in Windows and on iPhone.

Attribute values

AmsUpdate preserves the AMS entity and attribute IDs. Values are strings; parse numbers using CultureInfo.InvariantCulture. Empty means the attribute is absent. Truncated notifications are read back in full before delivery.

Entity Attribute Meaning / format
0 Player 0 Player name
0 Player 1 state,rate,elapsedSeconds
0 Player 2 Volume, 0–1
1 Queue 0 Queue index, zero-based
1 Queue 1 Queue count
1 Queue 2 Shuffle: off (0), one (1), all (2)
1 Queue 3 Repeat: off (0), one (1), all (2)
2 Track 0 Artist
2 Track 1 Album
2 Track 2 Title
2 Track 3 Duration in seconds

Playback states: paused (0), playing (1), rewinding (2), fast-forwarding (3). Between notifications, estimated position is elapsedSeconds + secondsSinceUpdate * rate.

Remote commands

ID Command ID Command
0 Play 7 Advance repeat mode
1 Pause 8 Advance shuffle mode
2 Toggle play/pause 9 Skip forward
3 Next track 10 Skip backward
4 Previous track 11 Like track
5 Volume up 12 Dislike track
6 Volume down 13 Bookmark track

Only queue commands included in the latest supported-command set. A successful write means the command was forwarded, not that playback changed. AMS does not provide artwork or absolute seeking. Skip amounts are controlled by the media app.

Build

dotnet build -c Release
dotnet pack -c Release -o artifacts
dotnet run --project tests/SmokeTests.csproj -c Release -f net48
dotnet run --project tests/SmokeTests.csproj -c Release -f net8.0

Building from source requires Windows and a .NET 8+ SDK (C# 12). That compiler requirement does not apply to applications consuming the package. The Windows metadata and projection generator are restored from NuGet as build-only dependencies. Add -- --bluetooth to a test command to exercise discovery with a real BLE adapter.

Protocol reference: Apple Media Service and attribute / command IDs.

MIT licensed. Source: fred913/Fred913.IosMediaSession.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 122 9/7/2026
0.1.0 112 9/7/2026

Targets .NET Standard 2.0 with embedded C#/WinRT. Supported-command callbacks now use IReadOnlyCollection<byte>. Bluetooth discovery verified on .NET Framework 4.8 and .NET 8.