xamarin.ios the mp3 stops playing when the screen goes off

advertisements

i'm developing an app, and i need to play music from url. i'm using this code, and it works fine. But, while a song is playing, and the screen switches off, then the music stops. I need that the music continues playing until its end, even if the screen switches off.

i suppose i have to change this file, but i don't know how:

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 && 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 && Finished != null)
            Finished (this, new EventArgs ());
    }
}
}

how can i change the code to allow that?

thanks in advance for helps.


Apps get suspended when the phone is put to sleep. If you wan't your app to continue executing, you have to register for background execution.

Here is a nice guide Jonathan Sagorin (if you don't mind putting it over from Swift/obj-c).

Basically the class you are looking for is AVAudioSession and it's SetActive Method to activate a background audio session.