#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
метод активации фонового аудиосеанса.