/// <summary> /// Destroys the instance. /// </summary> protected override void Destroy() { base.Destroy(); if (IsDisposed) { return; } Stop(); sound?.UnregisterInstance(this); if (engine.State == AudioEngineState.Invalidated) { return; } if (soundSource == null) { AudioLayer.SourceDestroy(Source); } else { soundSource.Dispose(); } }
private static unsafe void Worker() { var utilityBuffer = new UnmanagedArray <short>(SamplesPerBuffer * MaxChannels); var toRemove = new List <CompressedSoundSource>(); while (true) { toRemove.Clear(); while (!NewSources.IsEmpty) { CompressedSoundSource source; if (!NewSources.TryTake(out source)) { continue; } source.compressedSoundStream = ContentManager.FileProvider.OpenStream(source.soundStreamUrl, VirtualFileMode.Open, VirtualFileAccess.Read, VirtualFileShare.Read, StreamFlags.Seekable); source.decoder = new Celt(source.sampleRate, SamplesPerFrame, source.channels, true); source.compressedBuffer = new byte[source.maxCompressedSize]; source.reader = new BinarySerializationReader(source.compressedSoundStream); Sources.Add(source); } foreach (var source in Sources) { if (!source.Disposed) { while (!source.Commands.IsEmpty) { AsyncCommand command; if (!source.Commands.TryDequeue(out command)) { continue; } switch (command) { case AsyncCommand.Play: if (source.Playing && !source.Paused) { break; } if (!source.Paused) { source.Restart(); SourcePrepare(source); SourcePlayAsync(source); } else { AudioLayer.SourcePlay(source.SoundInstance.Source); } source.playing = true; source.Playing = true; source.Paused = false; source.PlayingQueued = false; break; case AsyncCommand.Pause: source.Paused = true; AudioLayer.SourcePause(source.SoundInstance.Source); break; case AsyncCommand.Stop: source.Paused = false; source.Playing = false; source.playing = false; AudioLayer.SourceStop(source.SoundInstance.Source); break; case AsyncCommand.SetRange: source.Restart(); SourcePrepare(source); break; case AsyncCommand.Dispose: AudioLayer.SourceDestroy(source.SoundInstance.Source); source.Destroy(); source.Disposed = true; toRemove.Add(source); break; default: throw new ArgumentOutOfRangeException(); } } source.PlayingState = (source.Playing && !source.Ended.Task.IsCompleted) || AudioLayer.SourceIsPlaying(source.SoundInstance.Source); if (!source.Playing || !source.CanFill || !source.playing) { continue; } const int passes = SamplesPerBuffer / SamplesPerFrame; var offset = 0; var bufferPtr = (short *)utilityBuffer.Pointer; var startingPacket = source.startingPacketIndex == source.currentPacketIndex; var endingPacket = false; for (var i = 0; i < passes; i++) { endingPacket = source.endPacketIndex == source.currentPacketIndex; //read one packet, size first, then data var len = source.reader.ReadInt16(); source.compressedSoundStream.Read(source.compressedBuffer, 0, len); source.currentPacketIndex++; var writePtr = bufferPtr + offset; if (source.decoder.Decode(source.compressedBuffer, len, writePtr) != SamplesPerFrame) { throw new Exception("Celt decoder returned a wrong decoding buffer size."); } offset += SamplesPerFrame * source.channels; if (source.compressedSoundStream.Position != source.compressedSoundStream.Length && !endingPacket) { continue; } if (source.looped) { //prepare again to play from begin SourcePrepare(source); } else { source.playing = false; source.Ended.TrySetResult(true); } break; } var finalPtr = new IntPtr(bufferPtr + (startingPacket ? source.startPktSampleIndex : 0)); var finalSize = (offset - (startingPacket ? source.startPktSampleIndex : 0) - (endingPacket ? source.endPktSampleIndex : 0)) * sizeof(short); var bufferType = AudioLayer.BufferType.None; if (endingPacket) { bufferType = source.looped ? AudioLayer.BufferType.EndOfLoop : AudioLayer.BufferType.EndOfStream; } else if (source.begin) { bufferType = AudioLayer.BufferType.BeginOfStream; source.begin = false; } source.FillBuffer(finalPtr, finalSize, bufferType); } else { toRemove.Add(source); } } foreach (var source in toRemove) { Sources.Remove(source); } Utilities.Sleep(20); } }