Пишу метроном. Длина файла около 30 миллисекунд. На эмуляторе работает, на реальном аппарате звук обрезается.
Класс MediaPlayer воспроизводил неровно - используется класс AudioTrack.
Воспроизведение реализовано сервисом, ссылка на который передаётся из класса MainPage в конструктор класса Model.
Код сервиса
using Android.Content.Res;
using Android.Media;
using System;
using System.IO;
using Timetronome.Droid.Services;
using Xamarin.Forms;
using Timetronome.Services;
[assembly: Dependency(typeof(AudioService))]
namespace Timetronome.Droid.Services
{
internal class AudioService : IAudio
{
private AudioTrack audioTrack;
private byte[] audioBuffer;
public void Initialize(string assetName)
{
audioTrack?.Dispose();
audioBuffer = ReadAsset(assetName);
audioTrack = new AudioTrack.Builder()
.SetAudioAttributes(new AudioAttributes.Builder()
.SetUsage(AudioUsageKind.Media)
.SetContentType(AudioContentType.Music)
.Build())
.SetAudioFormat(new AudioFormat.Builder()
.SetEncoding(Encoding.Pcm16bit)
.SetSampleRate(44100)
.SetChannelMask(ChannelOut.Stereo)
.Build())
.SetBufferSizeInBytes(audioBuffer.Length)
.Build();
byte[] ReadAsset(string assetName)
{
if (string.IsNullOrEmpty(assetName))
throw new ArgumentNullException(nameof(assetName));
int maxReadSize = 256 * 1024;
byte[] content;
AssetManager assets = Android.App.Application.Context.Assets;
using (BinaryReader binaryReader = new BinaryReader(assets.Open(assetName)))
{
content = binaryReader.ReadBytes(maxReadSize);
}
return content;
}
}
public void PlayTrack()
{
audioTrack.Play();
audioTrack.Write(audioBuffer, 0, audioBuffer.Length);
audioTrack.Stop();
}
}
}
Часть кода моделиinternal Model(IAudio audioService)
{
this.audioService = audioService;
audioService.Initialize("click.wav");
...
}
internal async void ToogleMetronomeState(int receivedTempo, int receivedTimer)
{
...
if (IsRunningMetronome)
{
int clickDelay = 60000 / SettedTempo;
timer = new Timer(clickDelay);
Timer returnedTimer;
while (IsRunningMetronome)
{
returnedTimer = await timer.GetTimerAfterTheDelay();
if (returnedTimer == timer)
audioService.PlayTrack();
else
break;
}
}
else
{
timer = null;
}
}
private class Timer
{
internal int Delay { get; private set; }
internal Timer(int delay) => Delay = delay;
internal async Task<Timer> GetTimerAfterTheDelay()
{
await Task.Delay(Delay);
return this;
}
}
Что нужно учесть/применить для реального устройства?