/// Version 1.0.0 /// Last modified 24.5.2014 /// /// Copyright (C) 2014 Veli-Mikko Puupponen /// /// Halyri-system is a prototype emergency call system. Its purpose is to /// demonstrate the use of the advanced capabilities available in the current /// generation smartphones in facilitating the emergency service dispatcher's /// capability to determine the nature of the emergency and to dispatch help. /// /// For more information, see the README file of this package. /// /// The MIT License (MIT) /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to /// deal in the Software without restriction, including without limitation the /// rights to use, copy, modify, merge, publish, distribute, sublicense, /// and/or sell copies of the Software, and to permit persons to whom the /// Software is furnished to do so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in /// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING /// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS /// IN THE SOFTWARE. /// using NAudio.Wave; using System; using System.Collections.Generic; using System.Threading; namespace Hake_WPF.AudioVideoManagers { /// Veli-Mikko Puupponen /// /// This class provides a NAudio WaveStream with an infinite length to /// facilitate streaming audio playback. It contains an internal /// buffer for the audio samples. If the buffer is empty, all /// read requests will return the desired length of silence. /// If there is a pcm audio available in the buffer, it will /// be returned to the reader, possibly padded with silence to /// meet the desired read length. /// /// class BufferWaveStream: WaveStream { private Queue completePcmSegments; private byte[] overflowFromLastSegment; private readonly WaveFormat waveFormat; private object queueLock; private long lengthInSamples = 1; private long defaultPosition = 0; /// /// Gets the streams format type. /// public override WaveFormat WaveFormat { get { return waveFormat; } } /// /// Gets the length of stream. /// public override long Length { get { return lengthInSamples; } } /// /// Sets and gets the position. It specifies the position of stream. /// public override long Position { get { return defaultPosition; } set { throw new NotImplementedException(); } } /// /// The function initializes a new BufferWaveStream that has a WaveFormat /// defined by the provided parameters. The audio buffer is /// empty and has no length limit. /// /// /// The aample rate im samples per second. /// The number of bytes per PCM sample. /// The number of channels. public BufferWaveStream(int sampleRate, int bytesPerSample, int channels) { completePcmSegments = new Queue(); waveFormat = new WaveFormat(sampleRate, bytesPerSample * 8, channels); queueLock = new object(); } /// /// The function writes the provided audio data to the outgoing PCM segment /// buffer. /// /// The bytes to write. /// The offset at which the bytes to write start. /// The count of the bytes to write public override void Write(byte[] buffer, int offset, int count) { Monitor.Enter(queueLock); try { byte[] newSamples = new byte[count]; Array.Copy(buffer, offset, newSamples, 0, count); completePcmSegments.Enqueue(newSamples); } finally { Monitor.Exit(queueLock); } } /// /// The function reads PCM samples from the underlying buffer. If no data is /// available, returns silent simples. /// /// The bffer to which the data is copied to. /// The offset for the data at the target buffer. /// The desired count of data. /// Processed data. public override int Read(byte[] buffer, int offset, int count) { Monitor.Enter(queueLock); int actualRead = 0; try { if (overflowFromLastSegment != null && overflowFromLastSegment.Length > 0) { int fromOverflow = overflowFromLastSegment.Length > count ? count : overflowFromLastSegment.Length; Array.Copy(overflowFromLastSegment, 0, buffer, offset, fromOverflow); actualRead += fromOverflow; if (fromOverflow < overflowFromLastSegment.Length) { byte[] temporaryArray = overflowFromLastSegment; overflowFromLastSegment = new byte[temporaryArray.Length - fromOverflow]; Array.Copy(temporaryArray, fromOverflow, overflowFromLastSegment, 0, overflowFromLastSegment.Length); } else overflowFromLastSegment = null; } if (actualRead < count) { if (completePcmSegments.Count > 0) { byte[] outgoing = completePcmSegments.Dequeue(); int fromComplete = outgoing.Length < (count - actualRead) ? outgoing.Length : (count - actualRead); Array.Copy(outgoing, 0, buffer, offset + actualRead, fromComplete); if (fromComplete < outgoing.Length) { overflowFromLastSegment = new byte[outgoing.Length - fromComplete]; Array.Copy(outgoing, fromComplete, overflowFromLastSegment, 0, overflowFromLastSegment.Length); } actualRead += fromComplete; } } if (actualRead < count) { short zero = 0; byte[] zeroBytes = BitConverter.GetBytes(zero); int addedZero = 0; for (int i = (offset + actualRead); i < (offset + count); i += 2) { buffer[i] = zeroBytes[0]; buffer[i+1] = zeroBytes[1]; addedZero += 2; } actualRead += addedZero; } } finally { Monitor.Exit(queueLock); } return actualRead; } } }