How to control volume using avaudioplayer in Xamarin iOS?

Lydafspilning i Xamarin: En Komplet Guide

31/03/2022

Rating: 4.83 (2992 votes)

Lydafspilning i Xamarin: En Komplet Guide

Lyd er en uundværlig del af mange mobile applikationer. Det kan forbedre brugeroplevelsen markant, hvad enten det er baggrundsmusik, lydeffekter eller talebeskeder. Selvom Xamarin.Forms ikke tilbyder en direkte API til lydafspilning, kan denne funktionalitet nemt implementeres ved hjælp af DependencyService. Denne artikel vil guide dig gennem processen med at oprette en lydafspiller i Xamarin.Forms, integrere den med et simpelt MVVM-mønster og endda vise, hvordan du styrer lydstyrken specifikt på iOS.

How to play audio files in Xamarin?
Play any audio files by using DependencyService with MediaPlayer for Android and AVAudioPlayer for iOS Audio, sound, or music can be an essential part of mobile apps. Unfortunately, Xamarin.Forms doesn't support this directly from their API. But of course, it can be implemented easily by using DependencyService.
Indholdsfortegnelse

Grundlæggende Opsætning af Lydafspilleren

For at komme i gang skal du først oprette et nyt Xamarin.Forms-projekt. Vi anbefaler at bruge en Portable Class Library (PCL) eller .NET Standard-bibliotek til din kerne-logik og XAML til brugergrænsefladen. Lad os kalde vores projekt AudioPlayerDemo.

Et typisk Xamarin.Forms-projekt vil bestå af flere projekter: et fælles bibliotek (Portable Class Library eller .NET Standard), et iOS-projekt og et Android-projekt. Vi vil fokusere på at definere den nødvendige service i det fælles bibliotek og derefter implementere den specifikt for hver platform.

1. Definér Lydafspillerens Interface (Portable Library)

I dit fælles bibliotek skal du oprette en ny interface, som vi kalder IAudioPlayerService. Denne interface vil definere de kernefunktioner, som vores lydafspiller skal have. Disse funktioner giver en abstraktion, så vi kan bruge lydafspilleren på tværs af platforme uden at bekymre os om de underliggende implementeringsdetaljer.

De essentielle funktioner i vores interface er:

  • Play(string pathToAudioFile): Starter afspilning af en lydfil, hvor stien til filen er angivet.
  • Play(): Genoptager afspilning af den aktuelle lydfil, hvis den var sat på pause.
  • Pause(): Sætter den aktuelle lydafspilning på pause.
  • Action OnFinishedPlaying { get; set; }: En handling (event delegate), der udløses, når lydfilen er afspillet færdig. Dette er nyttigt til at opdatere brugergrænsefladen eller starte en ny handling.

Her er et eksempel på, hvordan IAudioPlayerService-interfacet kan se ud:

public interface IAudioPlayerService { void Play(string pathToAudioFile); void Play(); void Pause(); Action OnFinishedPlaying { get; set; } } 

Dette interface fungerer som en kontrakt, der sikrer, at alle platformspecifikke implementeringer vil have de samme grundlæggende metoder.

2. Implementering for iOS

Nu skal vi implementere IAudioPlayerService for iOS-platformen. Gå til dit iOS-projekt, opret en ny klasse kaldet AudioPlayerService, og lad den implementere IAudioPlayerService-interfacet. Husk at tilføje [assembly: Dependency(typeof(AudioPlayerService))] over namespace-deklarationen for at gøre klassen tilgængelig via DependencyService.

På iOS bruger vi den indbyggede AVAudioPlayer klasse til at håndtere lyd. Vi deklarerer en privat variabel _audioPlayer af typen AVAudioPlayer.

using System; using AVFoundation; using Foundation; [assembly: Dependency(typeof(AudioPlayerService))] namespace AudioPlayerDemo.iOS { public class AudioPlayerService: IAudioPlayerService { private AVAudioPlayer _audioPlayer; public Action OnFinishedPlaying { get; set; } public AudioPlayerService() { // Ingen initialisering nødvendig her } // ... Implementering af metoder ... } } 

Play(string pathToAudioFile) for iOS

Denne metode skal finde lydfilen og starte afspilningen. På iOS placeres lydfiler typisk i Resources-mappen i iOS-projektet. Stien til filen skal være relativ til denne mappe. For eksempel, hvis din fil hedder Galway.mp3 og ligger direkte i Resources-mappen, kan du kalde metoden med Play("Galway.mp3").

Før vi starter en ny afspilning, er det god praksis at stoppe den eventuelle igangværende afspilning og fjerne den gamle FinishedPlaying event listener for at undgå fejl. Derefter oprettes et nyt AVAudioPlayer-objekt, en ny FinishedPlaying event listener tilføjes, og til sidst kaldes _audioPlayer.Play().

public void Play(string pathToAudioFile) { // Stop og fjern event listener hvis _audioPlayer allerede er i brug if (_audioPlayer != null && _audioPlayer.Playing) { _audioPlayer.FinishedPlaying -= Player_FinishedPlaying; _audioPlayer.Stop(); } // Opretter den nye AVAudioPlayer var url = NSUrl.FromFilename(pathToAudioFile); _audioPlayer = AVAudioPlayer.FromUrl(url); // Tilføj ny event listener _audioPlayer.FinishedPlaying += Player_FinishedPlaying; // Afspil _audioPlayer.Play(); } 

Håndtering af OnFinishedPlaying og andre metoder for iOS

Vi skal også implementere Pause() og Play() (resume) metoderne. Disse metoder kalder simpelthen de tilsvarende metoder på AVAudioPlayer-objektet.

OnFinishedPlaying-handlingen udløses via en privat metode, Player_FinishedPlaying, som er knyttet til AVAudioPlayers FinishedPlaying event.

private void Player_FinishedPlaying(object sender, AVStatusEventArgs e) { OnFinishedPlaying?.Invoke(); // Udløs den definerede handling } public void Pause() { _audioPlayer?.Pause(); } public void Play() { _audioPlayer?.Play(); // Genoptager afspilning } 

3. Implementering for Android

For Android-platformen følger vi en lignende proces. Opret en ny klasse AudioPlayerService i dit Android-projekt, som implementerer IAudioPlayerService og har [assembly: Dependency(typeof(AudioPlayerService))] attributten.

På Android bruger vi MediaPlayer klassen til lydafspilning. Vi erklærer en privat variabel _mediaPlayer af typen MediaPlayer.

using System; using Android.Media; using Android.Content.Res; using Xamarin.Forms; [assembly: Dependency(typeof(AudioPlayerService))] namespace AudioPlayerDemo.Droid { public class AudioPlayerService: IAudioPlayerService { private MediaPlayer _mediaPlayer; public Action OnFinishedPlaying { get; set; } public AudioPlayerService() { // Ingen initialisering nødvendig her } // ... Implementering af metoder ... } } 

Play(string pathToAudioFile) for Android

På Android placeres lydfiler i Assets-mappen i Android-projektet. Ligesom med iOS er stien relativ til denne mappe. F.eks. Assets/Galway.mp3 kaldes med Play("Galway.mp3").

Androids MediaPlayer kræver en lidt anderledes tilgang. Vi skal bruge AssetFileDescriptor til at få adgang til filen i assets. Derefter skal MediaPlayer forberedes ved at kalde PrepareAsync(). Denne proces er asynkron, så vi skal håndtere Prepared-eventet.

How to play audio files in Xamarin?
Play any audio files by using DependencyService with MediaPlayer for Android and AVAudioPlayer for iOS Audio, sound, or music can be an essential part of mobile apps. Unfortunately, Xamarin.Forms doesn't support this directly from their API. But of course, it can be implemented easily by using DependencyService.
public void Play(string pathToAudioFile) { // Stop og fjern event listener hvis _mediaPlayer allerede er i brug if (_mediaPlayer != null) { _mediaPlayer.Completion -= MediaPlayer_Completion; _mediaPlayer.Stop(); _mediaPlayer.Release(); // Frigiv ressourcer _mediaPlayer = null; } AssetFileDescriptor afd = null; try { // Åbn filen fra Android Assets afd = Forms.Context.Assets.OpenFd(pathToAudioFile); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Fejl ved åbning af fil: {ex.Message}"); return; // Afslut hvis filen ikke kan åbnes } if (afd != null) { _mediaPlayer = new MediaPlayer(); _mediaPlayer.SetDataSource(afd.FileDescriptor, afd.StartOffset, afd.Length); // Tilføj Prepared event listener _mediaPlayer.Prepared += (sender, args) => { _mediaPlayer.Completion += MediaPlayer_Completion; _mediaPlayer.Start(); // Start afspilning når klar }; // Start den asynkrone forberedelse _mediaPlayer.PrepareAsync(); } } 

Håndtering af OnFinishedPlaying og andre metoder for Android

Pause() og Play() (resume) implementeres ved at kalde de tilsvarende metoder på MediaPlayer. OnFinishedPlaying-handlingen udløses fra MediaPlayer_Completion-eventet.

private void MediaPlayer_Completion(object sender, EventArgs e) { OnFinishedPlaying?.Invoke(); // Udløs den definerede handling _mediaPlayer.Release(); // Frigiv ressourcer efter afspilning _mediaPlayer = null; } public void Pause() { _mediaPlayer?.Pause(); } public void Play() { _mediaPlayer?.Start(); // Genoptager afspilning } 

4. Integration i Xamarin.Forms Appen (MVVM)

Nu hvor vi har platformspecifikke implementeringer, skal vi integrere dem i vores Xamarin.Forms-applikation. Vi vil bruge et simpelt ViewModel for at håndtere logikken og forbinde brugergrænsefladen med vores IAudioPlayerService.

Placering af Lydfiler

Først skal du placere dine lydfiler (f.eks. Galway.mp3) i de korrekte mapper:

  • Android:YourProject.Droid/Assets/
  • iOS:YourProject.iOS/Resources/

Husk at sætte Build Action for disse filer til Content (Android) eller BundleResource (iOS) i filens egenskaber.

Opret ViewModel (AudioPlayerViewModel)

Opret en ny klasse kaldet AudioPlayerViewModel i dit fælles bibliotek. Denne klasse skal implementere INotifyPropertyChanged eller bruge et MVVM-framework som MvvmCross eller Prism.

Vi tilføjer et par egenskaber og en kommando:

  • CommandText: En streng, der bruges som tekst på en knap (f.eks. "Afspil" eller "Pause").
  • PlayPauseCommand: En ICommand, der udløses, når brugeren interagerer med knappen.

ViewModel'en modtager IAudioPlayerService som en afhængighed via konstruktøren.

using System.ComponentModel; using System.Windows.Input; using Xamarin.Forms; public class AudioPlayerViewModel: INotifyPropertyChanged { private readonly IAudioPlayerService _audioPlayer; private bool _isPlaying = false; public event PropertyChangedEventHandler PropertyChanged; public string CommandText => _isPlaying ? "Pause": "Afspil"; public ICommand PlayPauseCommand { get; } public AudioPlayerViewModel(IAudioPlayerService audioPlayer) { _audioPlayer = audioPlayer; _audioPlayer.OnFinishedPlaying = () => { _isPlaying = false; OnPropertyChanged(nameof(CommandText)); }; PlayPauseCommand = new Command(() => { if (_isPlaying) { _audioPlayer.Pause(); _isPlaying = false; } else { // Ved første afspilning skal filnavnet angives // Ellers genoptages den forrige afspilning if (!_audioPlayer.IsPlaying()) // Antag vi tilføjer IsPlaying() { _audioPlayer.Play("Galway.mp3"); // Angiv din lydfil her } else { _audioPlayer.Play(); } _isPlaying = true; } OnPropertyChanged(nameof(CommandText)); }); } protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } 

Bemærk: I ovenstående eksempel mangler en IsPlaying() metode på IAudioPlayerService. Denne kunne tilføjes for bedre kontrol, eller man kan stole på `_isPlaying` flaget i ViewModel'en.

Brugergrænseflade (XAML)

Nu opretter vi en simpel side med en knap, der binder til PlayPauseCommand og CommandText fra vores ViewModel.

<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="AudioPlayerDemo.AudioPlayerPage"> <StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand" Padding="20"> <Button Text="{Binding CommandText}" Command="{Binding PlayPauseCommand}" HorizontalOptions="Center" /> <Label Text="Musik: Galway by Kevin MacLeod" HorizontalOptions="Center" VerticalOptions="Center" FontSize="Micro" /> </StackLayout> </ContentPage> 

Opsætning af BindingContext

I din AudioPlayerPage.xaml.cs skal du sætte BindingContext til en ny instans af AudioPlayerViewModel og bruge DependencyService til at få fat i den korrekte IAudioPlayerService-implementering.

public partial class AudioPlayerPage: ContentPage { public AudioPlayerPage() { InitializeComponent(); // Hent den platformspecifikke implementering via DependencyService var audioPlayerService = DependencyService.Get<IAudioPlayerService>(); // Sæt BindingContext til ViewModel'en BindingContext = new AudioPlayerViewModel(audioPlayerService); } } 

5. Volumenkontrol på iOS

Den anden del af artiklen berører volumenkontrol på iOS. Mens vores generelle IAudioPlayerService ikke inkluderer volumenkontrol, kan dette nemt tilføjes for iOS-specifikke behov.

For at styre lydstyrken på iOS med AVAudioPlayer, kan du tilføje en Volume-egenskab til din iOS-implementering af IAudioPlayerService eller oprette en separat service.

I AudioPlayerService.iOS-klassen kan du tilføje en Volume-egenskab:

public float Volume { get { return (float?)_audioPlayer?.Volume ?? 0f; } // Giver 0 hvis _audioPlayer er null set { if (_audioPlayer != null && value >= 0f && value <= 1f) // AVAudioPlayer Volume er mellem 0.0 og 1.0 { _audioPlayer.Volume = value; } } } 

Du kan derefter eksponere denne funktionalitet i din IAudioPlayerService eller oprette en ny interface som IAudioPlayerServiceiOS, der arver fra IAudioPlayerService og tilføjer volumenegenskaben.

I din XAML kan du tilføje en Slider-kontrol, der binder til denne volumenegenskab. Du skal muligvis bruge en ValueConverter, hvis din ViewModel's volumen-egenskab er i et andet interval (f.eks. 0-100), mens AVAudioPlayer forventer 0.0-1.0.

Eksempel på XAML for Slider

<!-- Tilføj dette i din StackLayout --> <Slider Minimum="0" Maximum="1" Value="{Binding AudioVolume}" VerticalOptions="Center" HorizontalOptions="FillAndExpand" /><Label Text="{Binding VolumeDisplay}" HorizontalOptions="Center" />

Og i din AudioPlayerViewModel, tilføj egenskaber for volumen:

public float AudioVolume { get { return _audioPlayer.Volume; } // Antaget at IAudioPlayerService har en Volume property set { _audioPlayer.Volume = value; OnPropertyChanged(nameof(AudioVolume)); OnPropertyChanged(nameof(VolumeDisplay)); } } public string VolumeDisplay => $"{Math.Round(AudioVolume * 100)}%" ; 

Vigtigt: Husk at den ovenstående volumenkontrol kun virker for iOS-implementeringen. For en cross-platform løsning skal du muligvis tilføje yderligere logik eller en separat service for Android.

Tabel: Platformspecifikke Lydklasser

PlatformPrimær KlasseFilplacering (typisk)Bemærkninger
iOSAVAudioPlayerResourcesKræver NSUrl for filsti. Volumen fra 0.0 til 1.0.
AndroidMediaPlayerAssetsKræver AssetFileDescriptor. Forberedelse er asynkron. Volumen fra 0.0 til 1.0.

Fejlfinding og Overvejelser

  • Filstier: Sørg for, at filstierne er korrekte, og at filerne er inkluderet i projektets build output (BundleResource/Content).
  • Ressourcefrigørelse: Husk at frigive ressourcer (f.eks. _mediaPlayer.Release() på Android) når lydfilen er færdig eller ikke længere er i brug for at undgå hukommelseslækager.
  • Bagggrundsafspilning: For at afspille lyd i baggrunden skal du konfigurere de relevante baggrundstilstande i hvert platforms projektindstillinger.
  • Fejlhåndtering: Implementer robust fejlhåndtering, især når du åbner filer eller initialiserer afspillere.
  • Medieformater: Tjek kompatible medieformater for både iOS (primært AAC, MP3, ALAC, PCM) og Android (MP3, AAC, WAV, OGG m.fl.).

Konklusion

Selvom Xamarin.Forms ikke tilbyder indbygget lydfunktionalitet, gør DependencyService det muligt at skabe en ren og effektiv løsning. Ved at definere et fælles interface og implementere det platformspecifikt, kan du nemt tilføje lyd til dine cross-platform applikationer. Husk at teste grundigt på begge platforme og håndtere ressourcer korrekt for en optimal brugeroplevelse.

Med denne guide har du nu et solidt fundament for at implementere lydafspilning i dine egne Xamarin-projekter.

Kredit: Musikken brugt i eksemplet er "Galway" af Kevin MacLeod, licenseret under Creative Commons: By Attribution 3.0 License. (http://creativecommons.org/licenses/by/3.0/)

Hvis du vil læse andre artikler, der ligner Lydafspilning i Xamarin: En Komplet Guide, kan du besøge kategorien Teknologi.

Go up