/// <summary> /// Play the sound instance. /// </summary> /// <param name="stopSiblingInstances">if true any other istance of the same Sound will be stopped.</param> protected void Play(bool stopSiblingInstances) { if (engine.State == AudioEngineState.Invalidated || engine.State == AudioEngineState.Paused) { return; } if (PlayState == SoundPlayState.Playing) { return; } if (stopSiblingInstances) { sound?.StopConcurrentInstances(this); } if (soundSource == null) { AudioLayer.SourcePlay(Source); } else { soundSource.Play(); } playState = SoundPlayState.Playing; }
protected void PlayExtended(bool stopSiblingInstances) { if (engine.State == AudioEngineState.Invalidated || engine.State == AudioEngineState.Paused) { return; } if (PlayState == SoundPlayState.Playing) { return; } if (stopSiblingInstances) { StopConcurrentInstances(); } if (soundSource != null) { playingQueued = true; Task.Run(async() => { await soundSource.ReadyToPlay.Task; AudioLayer.SourcePlay(Source); playingQueued = false; }); } else { AudioLayer.SourcePlay(Source); } playState = SoundPlayState.Playing; }
private static void SourcePlayAsync(CompressedSoundSource source) { Task.Run(async() => { var playMe = await source.ReadyToPlay.Task; if (playMe) { AudioLayer.SourcePlay(source.SoundInstance.Source); } }); }
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); } }