xamarin.ios mp3 перестает воспроизводиться при выключении экрана

#c# #ios #xamarin #xamarin.ios #streaming

#c# #iOS #xamarin #xamarin.ios #потоковая передача

Вопрос:

я разрабатываю приложение, и мне нужно воспроизводить музыку с url. я использую этот код, и он работает нормально. Но во время воспроизведения песни и выключения экрана музыка останавливается. Мне нужно, чтобы музыка продолжала воспроизводиться до конца, даже если экран выключается.

я полагаю, мне нужно изменить этот файл, но я не знаю как:

 using System;
using AudioToolbox;
using System.Threading;
using System.Collections.Generic;
using System.Linq;

namespace SecondoSenso
{
/// <summary>
/// A Class to hold the AudioBuffer with all setting together
/// </summary>
internal class AudioBuffer
{

    public IntPtr Buffer { get; set; }

    public List<AudioStreamPacketDescription> PacketDescriptions { get; set; }

    public int CurrentOffset { get; set; }

    public bool IsInUse { get; set; }
}

/// <summary>
/// Wrapper around OutputQueue and AudioFileStream to allow streaming of various filetypes
/// </summary>
public class StreamingPlayback : IDisposable
{
    public bool boolDispose = false;

    public event EventHandler Finished;
    public event Action<OutputAudioQueue> OutputReady;

    // the AudioToolbox decoder
    AudioFileStream fileStream;
    int bufferSize = 128 * 256;
    List<AudioBuffer> outputBuffers;
    AudioBuffer currentBuffer;
    // Maximum buffers
    int maxBufferCount = 4;
    // Keep track of all queued up buffers, so that we know that the playback finished
    int queuedBufferCount = 0;
    // Current Filestream Position - if we don't keep track we don't know when to push the last uncompleted buffer
    long currentByteCount = 0;
    //Used to trigger a dump of the last buffer.
    bool lastPacket;

    public OutputAudioQueue OutputQueue;

    public bool Started  { get; private set; }

    public float Volume {
        get {
            return OutputQueue.Volume;
        }

        set {
            OutputQueue.Volume = value;
        }
    }

    /// <summary>
    /// Defines the size forearch buffer, when using a slow source use more buffers with lower buffersizes
    /// </summary>
    public int BufferSize {
        get {
            return bufferSize;
        }

        set {
            bufferSize = value;
        }
    }

    /// <summary>
    /// Defines the maximum Number of Buffers to use, the count can only change after Reset is called or the
    /// StreamingPlayback is freshly instantiated
    /// </summary>
    public int MaxBufferCount {
        get {
            return maxBufferCount;
        }

        set {
            maxBufferCount = value;
        }
    }

    public StreamingPlayback () : this (AudioFileType.MP3)
    {
    }

    public StreamingPlayback (AudioFileType type)
    {
        fileStream = new AudioFileStream (type);
        fileStream.PacketDecoded  = AudioPacketDecoded;
        fileStream.PropertyFound  = AudioPropertyFound;
    }

    public void Reset ()
    {
        if (fileStream != null) {
            fileStream.Close ();
            fileStream = new AudioFileStream (AudioFileType.MP3);
            currentByteCount = 0;
            fileStream.PacketDecoded  = AudioPacketDecoded;
            fileStream.PropertyFound  = AudioPropertyFound;
        }
    }

    public void ResetOutputQueue ()
    {
        if (OutputQueue != null) {
            OutputQueue.Stop (true);
            OutputQueue.Reset ();
            foreach (AudioBuffer buf in outputBuffers) {
                buf.PacketDescriptions.Clear ();
                OutputQueue.FreeBuffer (buf.Buffer);
            }
            outputBuffers = null;
            OutputQueue.Dispose ();
        }
    }

    /// <summary>
    /// Stops the OutputQueue
    /// </summary>
    public void Pause ()
    {
        OutputQueue.Pause ();
        Started = false;
    }

    /// <summary>
    /// Starts the OutputQueue
    /// </summary>
    public void Play ()
    {
        OutputQueue.Start ();
        Started = true;
    }

    /// <summary>
    /// Main methode to kick off the streaming, just send the bytes to this method
    /// </summary>
    public void ParseBytes (byte[] buffer, int count, bool discontinuity, bool lastPacket)
    {
        this.lastPacket = lastPacket;
        fileStream.ParseBytes (buffer, 0, count, discontinuity);
    }

    public void Dispose ()
    {
        Dispose (true);
        GC.SuppressFinalize (this);
    }
    public void Dispose(int tt) { 

    }
    /// <summary>
    /// Cleaning up all the native Resource
    /// </summary>
    protected virtual void Dispose (bool disposing)
    {
        if (disposing) {

            if (OutputQueue != null)
                OutputQueue.Stop(true);

            if (outputBuffers != null) {
                foreach (var b in outputBuffers)
                    OutputQueue.FreeBuffer (b.Buffer);

                outputBuffers.Clear ();
                outputBuffers = null;
            }

            if (fileStream != null) {
                fileStream.Close ();
                fileStream = null;
            }

            if (OutputQueue != null) {
                OutputQueue.Dispose ();
                OutputQueue = null;
            }
        }
    }

    /// <summary>
    /// Saving the decoded Packets to our active Buffer, if the Buffer is full queue it into the OutputQueue
    /// and wait until another buffer gets freed up
    /// </summary>
    void AudioPacketDecoded (object sender, PacketReceivedEventArgs args)
    {
        foreach (var p in args.PacketDescriptions) {
            currentByteCount  = p.DataByteSize;

            AudioStreamPacketDescription pd = p;

            int left = bufferSize - currentBuffer.CurrentOffset;
            if (left < pd.DataByteSize) {
                EnqueueBuffer ();
                WaitForBuffer ();
            }

            AudioQueue.FillAudioData (currentBuffer.Buffer, currentBuffer.CurrentOffset, args.InputData, (int)pd.StartOffset, pd.DataByteSize);
            // Set new offset for this packet
            pd.StartOffset = currentBuffer.CurrentOffset;
            // Add the packet to our Buffer
            currentBuffer.PacketDescriptions.Add (pd);
            // Add the Size so that we know how much is in the buffer
            currentBuffer.CurrentOffset  = pd.DataByteSize;
        }

        if ((fileStream != null amp;amp; currentByteCount == fileStream.DataByteCount) || lastPacket)
            EnqueueBuffer ();
    }

    /// <summary>
    /// Flush the current buffer and close the whole thing up
    /// </summary>
    public void FlushAndClose ()
    {
        if (OutputQueue != null) {
            EnqueueBuffer ();
            OutputQueue.Flush ();
        }

        Dispose ();
    }

    /// <summary>
    /// Enqueue the active buffer to the OutputQueue
    /// </summary>
    void EnqueueBuffer ()
    {
        currentBuffer.IsInUse = true;
        OutputQueue.EnqueueBuffer (currentBuffer.Buffer, currentBuffer.CurrentOffset, currentBuffer.PacketDescriptions.ToArray ());
        queuedBufferCount  ;
        StartQueueIfNeeded ();
    }

    /// <summary>
    /// Wait until a buffer is freed up
    /// </summary>
    void WaitForBuffer ()
    {
        int curIndex = outputBuffers.IndexOf (currentBuffer);
        currentBuffer = outputBuffers [curIndex < outputBuffers.Count - 1 ? curIndex   1 : 0];

        lock (currentBuffer) {
            while (currentBuffer.IsInUse)
                Monitor.Wait (currentBuffer);
        }
    }

    void StartQueueIfNeeded ()
    {
        if (Started)
            return;

        Play ();
    }

    /// <summary>
    /// When a AudioProperty in the fed packets is found this callback is called
    /// </summary>
    void AudioPropertyFound (object sender, PropertyFoundEventArgs args)
    {
        if (args.Property == AudioFileStreamProperty.ReadyToProducePackets) {
            Started = false;

            if (OutputQueue != null)
                OutputQueue.Dispose ();

            OutputQueue = new OutputAudioQueue (fileStream.StreamBasicDescription);
            if (OutputReady != null)
                OutputReady (OutputQueue);

            currentByteCount = 0;
            OutputQueue.BufferCompleted  = HandleBufferCompleted;
            outputBuffers = new List<AudioBuffer> ();

            for (int i = 0; i < MaxBufferCount; i  ) {
                IntPtr outBuffer;
                OutputQueue.AllocateBuffer (BufferSize, out outBuffer);
                outputBuffers.Add (new AudioBuffer () {
                    Buffer = outBuffer,
                    PacketDescriptions = new List<AudioStreamPacketDescription> ()
                });
            }

            currentBuffer = outputBuffers.First ();

            OutputQueue.MagicCookie = fileStream.MagicCookie;
        }
    }

    /// <summary>
    /// Is called when a buffer is completly read and can be freed up
    /// </summary>
    void HandleBufferCompleted (object sender, BufferCompletedEventArgs e)
    {
        queuedBufferCount--;
        IntPtr buf = e.IntPtrBuffer;

        foreach (var buffer in outputBuffers) {
            if (buffer.Buffer != buf)
                continue;

            // free Buffer
            buffer.PacketDescriptions.Clear ();
            buffer.CurrentOffset = 0;
            lock (buffer) {
                buffer.IsInUse = false;
                Monitor.Pulse (buffer);
            }
        }

        if (queuedBufferCount == 0 amp;amp; Finished != null)
            Finished (this, new EventArgs ());
    }
}
}
  

как я могу изменить код, чтобы разрешить это?

заранее спасибо за помощь.

Ответ №1:

Поместите следующий код в свой AppDelegate.cs FinishedLaunching метод.

 NSError sessionError = null;
                AVAudioSession.SharedInstance().SetCategory(AVAudioSession.CategoryAmbient, out sessionError);

AVAudioSession.SharedInstance().SetActive(true, out sessionError);
  

Комментарии:

1. Мне пришлось использовать следующий код для воспроизведения аудиофайла mp3, когда экран был заблокирован: AVAudioSession. sharedInstance() . SetCategory(AVAudioSession. CategoryPlayback, out NSError sessionError); AVAudioSession. sharedInstance() . SetActive(true, ошибка out sessionError);

Ответ №2:

Приложения приостанавливаются, когда телефон переводится в спящий режим. Если вы не хотите, чтобы ваше приложение продолжало выполняться, вам необходимо зарегистрироваться для фонового выполнения.

Вот хорошее руководство Джонатана Сагорина (если вы не возражаете перенести его из Swift / obj-c).

В основном класс, который вы ищете, — это AVAudioSession, и это SetActive метод активации фонового аудиосеанса.