Jalui
@Jalui

Как полностью воспроизвести короткий аудиофайл?

Пишу метроном. Длина файла около 30 миллисекунд. На эмуляторе работает, на реальном аппарате звук обрезается.
Вместо тысячи слов
Пример звучания: https://disk.yandex.by/d/3X9mbcYAiQIdHw

Класс 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;
            }
        }

Что нужно учесть/применить для реального устройства?
  • Вопрос задан
  • 106 просмотров
Решения вопроса 1
Jalui
@Jalui Автор вопроса
Установка размера буфера равным значению, возвращённого методом AudioTrack.GetMinBufferSize, решает проблему на целевой версии ОС (Android 11).
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы