/// <summary> /// Called when we get a new buffer of recorded data /// </summary> private void Callback(IntPtr waveInHandle, WaveInterop.WaveMessage message, int userData, WaveHeader waveHeader, int reserved) { if (message == WaveInterop.WaveMessage.WaveInData) { GCHandle hBuffer = (GCHandle)waveHeader.userData; WaveInBuffer buffer = (WaveInBuffer)hBuffer.Target; length += buffer.BytesRecorded; if (DataAvailable != null) { DataAvailable(this, new WaveInEventArgs(buffer.Data, buffer.BytesRecorded)); } if (recording) { buffer.Reuse(); } else { if (RecordingStopped != null) { RecordingStopped(this, EventArgs.Empty); } } } }
internal MmResult WaveOutOpen(out IntPtr waveOutHandle, int deviceNumber, WaveFormat waveFormat, WaveInterop.WaveCallback callback) { MmResult result; if (Strategy == WaveCallbackStrategy.FunctionCallback) { result = WaveInterop.waveOutOpen(out waveOutHandle, deviceNumber, waveFormat, callback, 0, WaveInterop.CallbackFunction); } else { result = WaveInterop.waveOutOpenWindow(out waveOutHandle, deviceNumber, waveFormat, this.Handle, 0, WaveInterop.CallbackWindow); } return result; }
internal void Connect(WaveInterop.WaveCallback callback) { if (Strategy == WaveCallbackStrategy.NewWindow) { waveOutWindow = new WaveWindow(callback); waveOutWindow.CreateControl(); this.Handle = waveOutWindow.Handle; } else if (Strategy == WaveCallbackStrategy.ExistingWindow) { waveOutWindowNative = new WaveWindowNative(callback); waveOutWindowNative.AssignHandle(this.Handle); } }
/// <summary> /// Stop and reset the WaveOut device /// </summary> public void Stop() { if (playbackState != PlaybackState.Stopped) { MmResult result; playbackState = PlaybackState.Stopped; // set this here to avoid a problem with some drivers whereby // in the call to waveOutReset they don't return until an OnDone is called lock (waveOutLock) { result = WaveInterop.waveOutReset(hWaveOut); } if (result != MmResult.NoError) { throw new MmException(result, "waveOutReset"); } } }
public long GetPosition() { long result; lock (this.waveOutLock) { MmTime mmTime = default(MmTime); mmTime.wType = 4u; MmException.Try(WaveInterop.waveOutGetPosition(this.hWaveOut, out mmTime, Marshal.SizeOf(mmTime)), "waveOutGetPosition"); if (mmTime.wType != 4u) { throw new Exception(string.Format("waveOutGetPosition: wType -> Expected {0}, Received {1}", 4, mmTime.wType)); } result = (long)((ulong)mmTime.cb); } return(result); }
public void Stop() { if (this.playbackState != PlaybackState.Stopped) { this.playbackState = PlaybackState.Stopped; MmResult mmResult; lock (this.waveOutLock) { mmResult = WaveInterop.waveOutReset(this.hWaveOut); } if (mmResult != MmResult.NoError) { throw new MmException(mmResult, "waveOutReset"); } this.callbackEvent.Set(); } }
/// <summary> /// Pause the audio /// </summary> public void Pause() { if (playbackState == PlaybackState.Playing) { playbackState = PlaybackState.Paused; // set this here to avoid a deadlock problem with some drivers MmResult result; lock (waveOutLock) { result = WaveInterop.waveOutPause(hWaveOut); } if (result != MmResult.NoError) { throw new MmException(result, "waveOutPause"); } } }
private GCHandle hThis; // for the user callback /// <summary> /// creates a new wavebuffer /// </summary> /// <param name="waveInHandle">WaveIn device to write to</param> /// <param name="bufferSize">Buffer size in bytes</param> public WaveInBuffer(IntPtr waveInHandle, Int32 bufferSize) { this.bufferSize = bufferSize; this.buffer = new byte[bufferSize]; this.hBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); this.waveInHandle = waveInHandle; header = new WaveHeader(); hHeader = GCHandle.Alloc(header, GCHandleType.Pinned); header.dataBuffer = hBuffer.AddrOfPinnedObject(); header.bufferLength = bufferSize; header.loops = 1; hThis = GCHandle.Alloc(this); header.userData = (IntPtr)hThis; MmException.Try(WaveInterop.waveInPrepareHeader(waveInHandle, header, Marshal.SizeOf(header)), "waveInPrepareHeader"); //MmException.Try(WaveInterop.waveInAddBuffer(waveInHandle, header, Marshal.SizeOf(header)), "waveInAddBuffer"); }
private void Exit() { if (hWaveOut != IntPtr.Zero) { Stop(); WaveInterop.waveOutClose(hWaveOut); hWaveOut = IntPtr.Zero; } if (buffers != null) { for (int n = 0; n < numBuffers; n++) { buffers[n].Dispose(); } buffers = null; } }
private void CloseWaveInDevice() { if (this.waveInHandle == IntPtr.Zero) { return; } WaveInterop.waveInReset(this.waveInHandle); if (this.buffers != null) { for (int i = 0; i < this.buffers.Length; i++) { this.buffers[i].Dispose(); } this.buffers = null; } WaveInterop.waveInClose(this.waveInHandle); this.waveInHandle = IntPtr.Zero; }
public void StopRecording() { if (this.recording) { this.recording = false; MmException.Try(WaveInterop.waveInStop(this.waveInHandle), "waveInStop"); for (int i = 0; i < this.buffers.Length; i++) { int num = (i + this.lastReturnedBufferIndex + 1) % this.buffers.Length; WaveInBuffer waveInBuffer = this.buffers[num]; if (waveInBuffer.Done) { this.RaiseDataAvailable(waveInBuffer); } } this.RaiseRecordingStopped(null); } }
/// <summary> /// Gets the current position in bytes from the wave output device. /// (n.b. this is not the same thing as the position within your reader /// stream - it calls directly into waveOutGetPosition) /// </summary> /// <returns>Position in bytes</returns> public long GetPosition() { lock (waveOutLock) { var mmTime = new MmTime(); mmTime.wType = MmTime.TIME_BYTES; // request results in bytes, TODO: perhaps make this a little more flexible and support the other types? MmException.Try(WaveInterop.waveOutGetPosition(hWaveOut, out mmTime, Marshal.SizeOf(mmTime)), "waveOutGetPosition"); if (mmTime.wType != MmTime.TIME_BYTES) { throw new Exception(string.Format("waveOutGetPosition: wType -> Expected {0}, Received {1}", MmTime.TIME_BYTES, mmTime.wType)); } return(mmTime.cb); } }
private void CloseWaveInDevice() { if (waveInHandle == IntPtr.Zero) { return; } // Some drivers need the reset to properly release buffers WaveInterop.waveInReset(waveInHandle); if (buffers != null) { for (int n = 0; n < buffers.Length; n++) { buffers[n].Dispose(); } buffers = null; } WaveInterop.waveInClose(waveInHandle); waveInHandle = IntPtr.Zero; }
internal static void SetWaveOutVolume(float value, IntPtr hWaveOut, object lockObject) { if (value < 0f) { throw new ArgumentOutOfRangeException("value", "Volume must be between 0.0 and 1.0"); } if (value > 1f) { throw new ArgumentOutOfRangeException("value", "Volume must be between 0.0 and 1.0"); } int dwVolume = (int)(value * 65535f) + ((int)(value * 65535f) << 16); MmResult result; lock (lockObject) { result = WaveInterop.waveOutSetVolume(hWaveOut, dwVolume); } MmException.Try(result, "waveOutSetVolume"); }
public void Stop() { if (this.playbackState != PlaybackState.Stopped) { this.playbackState = PlaybackState.Stopped; MmResult mmResult; lock (this.waveOutLock) { mmResult = WaveInterop.waveOutReset(this.hWaveOut); } if (mmResult != MmResult.NoError) { throw new MmException(mmResult, "waveOutReset"); } if (this.callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback) { this.RaisePlaybackStoppedEvent(null); } } }
/// <summary> /// Resume playing after a pause from the same position /// </summary> public void Resume() { if (Thread.CurrentThread.ManagedThreadId != waveOutThread.ManagedThreadId) { lock (actionQueue) { actionQueue.Enqueue(new WaveOutAction(WaveOutFunction.Resume, null)); workAvailable.Set(); } return; } MmResult result = WaveInterop.waveOutRestart(hWaveOut); if (result != MmResult.NoError) { throw new MmException(result, "waveOutRestart"); } playbackState = PlaybackState.Playing; }
/// <summary> /// creates a new wavebuffer /// </summary> /// <param name="hWaveOut">WaveOut device to write to</param> /// <param name="bufferSize">Buffer size in bytes</param> /// <param name="bufferFillStream">Stream to provide more data</param> /// <param name="waveOutLock">Lock to protect WaveOut API's from being called on >1 thread</param> // Token: 0x06000BCD RID: 3021 RVA: 0x00023868 File Offset: 0x00021A68 public WaveOutBuffer(IntPtr hWaveOut, int bufferSize, IWaveProvider bufferFillStream, object waveOutLock) { this.bufferSize = bufferSize; this.buffer = new byte[bufferSize]; this.hBuffer = GCHandle.Alloc(this.buffer, GCHandleType.Pinned); this.hWaveOut = hWaveOut; this.waveStream = bufferFillStream; this.waveOutLock = waveOutLock; this.header = new WaveHeader(); this.hHeader = GCHandle.Alloc(this.header, GCHandleType.Pinned); this.header.dataBuffer = this.hBuffer.AddrOfPinnedObject(); this.header.bufferLength = bufferSize; this.header.loops = 1; this.hThis = GCHandle.Alloc(this); this.header.userData = (IntPtr)this.hThis; lock (waveOutLock) { MmException.Try(WaveInterop.waveOutPrepareHeader(hWaveOut, this.header, Marshal.SizeOf(this.header)), "waveOutPrepareHeader"); } }
/// <summary> /// Stop and reset the WaveOut device /// </summary> public void Stop() { if (playbackState != PlaybackState.Stopped) { // in the call to waveOutReset with function callbacks // some drivers will block here until OnDone is called // for every buffer playbackState = PlaybackState.Stopped; // set this here to avoid a problem with some drivers whereby MmResult result; lock (waveOutLock) { result = WaveInterop.waveOutReset(hWaveOut); } if (result != MmResult.NoError) { throw new MmException(result, "waveOutReset"); } callbackEvent.Set(); // give the thread a kick, make sure we exit } }
/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">WaveProvider to play</param> public void Init(IWaveProvider waveProvider) { this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (waveOutLock) { result = WaveInterop.waveOutOpenWindow(out hWaveOut, (IntPtr)DeviceNumber, waveStream.WaveFormat, callbackEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, WaveInterop.WaveInOutOpenFlags.CallbackEvent); } MmException.Try(result, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = PlaybackState.Stopped; for (int n = 0; n < NumberOfBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
/// <summary> /// Releases resources held by this WaveBuffer /// </summary> // Token: 0x06000BA8 RID: 2984 RVA: 0x00022E9C File Offset: 0x0002109C protected void Dispose(bool disposing) { if (this.waveInHandle != IntPtr.Zero) { WaveInterop.waveInUnprepareHeader(this.waveInHandle, this.header, Marshal.SizeOf(this.header)); this.waveInHandle = IntPtr.Zero; } if (this.hHeader.IsAllocated) { this.hHeader.Free(); } if (this.hBuffer.IsAllocated) { this.hBuffer.Free(); } if (this.hThis.IsAllocated) { this.hThis.Free(); } }
/// <summary> /// Stop and reset the WaveOut device /// </summary> public void Stop() { if (Thread.CurrentThread.ManagedThreadId != waveOutThread.ManagedThreadId) { lock (actionQueue) { actionQueue.Enqueue(new WaveOutAction(WaveOutFunction.Stop, null)); workAvailable.Set(); } return; } playbackState = PlaybackState.Stopped; buffersQueued = false; MmResult result = WaveInterop.waveOutReset(hWaveOut); if (result != MmResult.NoError) { throw new MmException(result, "waveOutReset"); } }
/// <summary> /// Stop recording /// </summary> public void StopRecording() { if (recording) { recording = false; MmException.Try(WaveInterop.waveInStop(waveInHandle), "waveInStop"); // report the last buffers, sometimes more than one, so taking care to report them in the right order for (int n = 0; n < buffers.Length; n++) { int index = (n + lastReturnedBufferIndex + 1) % buffers.Length; var buffer = buffers[index]; if (buffer.Done) { RaiseDataAvailable(buffer); } } RaiseRecordingStopped(null); } //MmException.Try(WaveInterop.waveInReset(waveInHandle), "waveInReset"); // Don't actually close yet so we get the last buffer }
/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">WaveProvider to play</param> public void Init(IWaveProvider waveProvider) { if (playbackState != PlaybackState.Stopped) { throw new InvalidOperationException("Can't re-initialize during playback"); } if (hWaveOut != IntPtr.Zero) { // normally we don't allow calling Init twice, but as experiment, see if we can clean up and go again // try to allow reuse of this waveOut device // n.b. risky if Playback thread has not exited DisposeBuffers(); CloseWaveOut(); } callbackEvent = new AutoResetEvent(false); waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize( (DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (waveOutLock) { result = WaveInterop.waveOutOpenWindow(out hWaveOut, (IntPtr)DeviceNumber, waveStream.WaveFormat, callbackEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, WaveInterop.WaveInOutOpenFlags.CallbackEvent); } MmException.Try(result, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = PlaybackState.Stopped; for (var n = 0; n < NumberOfBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
internal static void SetWaveOutVolume(float value, IntPtr hWaveOut, object lockObject) { if (value < 0) { throw new ArgumentOutOfRangeException("value", "Volume must be between 0.0 and 1.0"); } if (value > 1) { throw new ArgumentOutOfRangeException("value", "Volume must be between 0.0 and 1.0"); } float left = value; float right = value; int stereoVolume = (int)(left * 0xFFFF) + ((int)(right * 0xFFFF) << 16); MmResult result; lock (lockObject) { result = WaveInterop.waveOutSetVolume(hWaveOut, stereoVolume); } MmException.Try(result, "waveOutSetVolume"); }
protected void Dispose(bool disposing) { this.Stop(); if (disposing && this.buffers != null) { for (int i = 0; i < this.buffers.Length; i++) { if (this.buffers[i] != null) { this.buffers[i].Dispose(); } } this.buffers = null; } lock (this.waveOutLock) { WaveInterop.waveOutClose(this.hWaveOut); } if (disposing) { this.callbackInfo.Disconnect(); } }
/// <summary> /// Releases resources held by this WaveBuffer /// </summary> // Token: 0x06000BD0 RID: 3024 RVA: 0x000239A8 File Offset: 0x00021BA8 protected void Dispose(bool disposing) { if (this.hHeader.IsAllocated) { this.hHeader.Free(); } if (this.hBuffer.IsAllocated) { this.hBuffer.Free(); } if (this.hThis.IsAllocated) { this.hThis.Free(); } if (this.hWaveOut != IntPtr.Zero) { lock (this.waveOutLock) { WaveInterop.waveOutUnprepareHeader(this.hWaveOut, this.header, Marshal.SizeOf(this.header)); } this.hWaveOut = IntPtr.Zero; } }
//BPCM added internal static void SetWaveOutRate(float value, IntPtr hWaveOut, object lockObject) { if (value < 0) { throw new ArgumentOutOfRangeException("value", "Rate must be between 0.0 and 4.0"); } if (value > 4) { throw new ArgumentOutOfRangeException("value", "Rate must be between 0.0 and 4.0"); } ushort hi = (ushort)Math.Floor(value); ushort lo = (ushort)Math.Round(0xFFFF * (value - Math.Floor(value)), 0); int rateValue = lo + (hi << 16); //Debug.WriteLine("lo=" + lo.ToString() + " hi=" + hi.ToString() + " rateValue=" + rateValue.ToString("X")); MmResult result; lock (lockObject) { result = WaveInterop.waveOutSetPlaybackRate(hWaveOut, rateValue); } MmException.Try(result, "waveOutSetPlaybackRate"); }
/// <summary> /// Creates a cue list from the cue RIFF chunk and the list RIFF chunk /// </summary> /// <param name="cueChunkData">The data contained in the cue chunk</param> /// <param name="listChunkData">The data contained in the list chunk</param> internal CueList(byte[] cueChunkData, byte[] listChunkData) { int cueCount = BitConverter.ToInt32(cueChunkData, 0); Dictionary <int, int> cueIndex = new Dictionary <int, int>(); int[] positions = new int[cueCount]; int cue = 0; for (int p = 4; cueChunkData.Length - p >= 24; p += 24, cue++) { cueIndex[BitConverter.ToInt32(cueChunkData, p)] = cue; positions[cue] = BitConverter.ToInt32(cueChunkData, p + 20); } string[] labels = new string[cueCount]; int labelLength = 0; int cueID = 0; Int32 labelChunkID = WaveInterop.mmioStringToFOURCC("labl", 0); for (int p = 4; listChunkData.Length - p >= 16; p += labelLength + labelLength % 2 + 12) { if (BitConverter.ToInt32(listChunkData, p) == labelChunkID) { labelLength = BitConverter.ToInt32(listChunkData, p + 4) - 4; cueID = BitConverter.ToInt32(listChunkData, p + 8); cue = cueIndex[cueID]; labels[cue] = Encoding.Default.GetString(listChunkData, p + 12, labelLength - 1); } } for (int i = 0; i < cueCount; i++) { cues.Add(new Cue(positions[i], labels[i])); } }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; Interlocked.Decrement(ref queuedBuffers); // check that we're not here through pressing stop if (PlaybackState == PlaybackState.Playing) { // to avoid deadlocks in Function callback mode, // we lock round this whole thing, which will include the // reading from the stream. // this protects us from calling waveOutReset on another // thread while a WaveOutWrite is in progress lock (waveOutLock) { if (buffer.OnDone()) { Interlocked.Increment(ref queuedBuffers); } } } if (queuedBuffers == 0) { if (callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback && playbackState == Wave.PlaybackState.Stopped) { // the user has pressed stop // DO NOT raise the playback stopped event from here // since on the main thread we are still in the waveOutReset function // Playback stopped will be raised elsewhere } else { RaisePlaybackStoppedEvent(); } } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }
/// <summary> /// Called when we get a new buffer of recorded data /// </summary> private void Callback(IntPtr waveInHandle, WaveInterop.WaveMessage message, IntPtr userData, WaveHeader waveHeader, IntPtr reserved) { if (message == WaveInterop.WaveMessage.WaveInData) { GCHandle hBuffer = (GCHandle)waveHeader.userData; WaveInBuffer buffer = (WaveInBuffer)hBuffer.Target; Exception exception = null; if (DataAvailable != null) { DataAvailable(this, new WaveInEventArgs(buffer.Data, buffer.BytesRecorded)); } if (recording) { try { buffer.Reuse(); } catch (Exception e) { recording = false; exception = e; } } if (!recording) { RaiseRecordingStopped(exception); } } }
/// <summary> /// Reads the header part of a WAV file from a stream /// </summary> /// <param name="stream">The stream, positioned at the start of audio data</param> /// <param name="format">The format found</param> /// <param name="dataChunkPosition">The position of the data chunk</param> /// <param name="dataChunkLength">The length of the data chunk</param> /// <param name="chunks">Additional chunks found</param> public static void ReadWaveHeader(Stream stream, out WaveFormat format, out long dataChunkPosition, out int dataChunkLength, List <RiffChunk> chunks) { dataChunkPosition = -1; format = null; BinaryReader br = new BinaryReader(stream); if (br.ReadInt32() != WaveInterop.mmioStringToFOURCC("RIFF", 0)) { throw new FormatException("Not a WAVE file - no RIFF header"); } uint fileSize = br.ReadUInt32(); // read the file size (minus 8 bytes) if (br.ReadInt32() != WaveInterop.mmioStringToFOURCC("WAVE", 0)) { throw new FormatException("Not a WAVE file - no WAVE header"); } int dataChunkID = WaveInterop.mmioStringToFOURCC("data", 0); int formatChunkId = WaveInterop.mmioStringToFOURCC("fmt ", 0); dataChunkLength = 0; // sometimes a file has more data than is specified after the RIFF header long stopPosition = Math.Min(fileSize + 8, stream.Length); // this -8 is so we can be sure that there are at least 8 bytes for a chunk id and length while (stream.Position <= stopPosition - 8) { Int32 chunkIdentifier = br.ReadInt32(); Int32 chunkLength = br.ReadInt32(); if (chunkIdentifier == dataChunkID) { dataChunkPosition = stream.Position; dataChunkLength = chunkLength; stream.Position += chunkLength; } else if (chunkIdentifier == formatChunkId) { format = WaveFormat.FromFormatChunk(br, chunkLength); } else { // check for invalid chunk length if (chunkLength < 0 || chunkLength > stream.Length - stream.Position) { Debug.Assert(false, String.Format("Invalid chunk length {0}, pos: {1}. length: {2}", chunkLength, stream.Position, stream.Length)); // an exception will be thrown further down if we haven't got a format and data chunk yet, // otherwise we will tolerate this file despite it having corrupt data at the end break; } if (chunks != null) { chunks.Add(new RiffChunk(chunkIdentifier, chunkLength, stream.Position)); } stream.Position += chunkLength; } } if (format == null) { throw new FormatException("Invalid WAV file - No fmt chunk found"); } if (dataChunkPosition == -1) { throw new FormatException("Invalid WAV file - No data chunk found"); } }
public WaveWindow(WaveInterop.WaveCallback waveCallback) { this.waveCallback = waveCallback; }
/// <summary> /// Place this buffer back to record more audio /// </summary> // Token: 0x06000BA5 RID: 2981 RVA: 0x00022DDC File Offset: 0x00020FDC public void Reuse() { MmException.Try(WaveInterop.waveInUnprepareHeader(this.waveInHandle, this.header, Marshal.SizeOf(this.header)), "waveUnprepareHeader"); MmException.Try(WaveInterop.waveInPrepareHeader(this.waveInHandle, this.header, Marshal.SizeOf(this.header)), "waveInPrepareHeader"); MmException.Try(WaveInterop.waveInAddBuffer(this.waveInHandle, this.header, Marshal.SizeOf(this.header)), "waveInAddBuffer"); }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; Interlocked.Decrement(ref queuedBuffers); Exception exception = null; // check that we're not here through pressing stop if (PlaybackState == PlaybackState.Playing) { // to avoid deadlocks in Function callback mode, // we lock round this whole thing, which will include the // reading from the stream. // this protects us from calling waveOutReset on another // thread while a WaveOutWrite is in progress lock (waveOutLock) { try { if (buffer.OnDone()) { Interlocked.Increment(ref queuedBuffers); } } catch (Exception e) { // one likely cause is soundcard being unplugged exception = e; } } } if (queuedBuffers == 0) { if (callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback && playbackState == Wave.PlaybackState.Stopped) { // the user has pressed stop // DO NOT raise the playback stopped event from here // since on the main thread we are still in the waveOutReset function // Playback stopped will be raised elsewhere } else { playbackState = PlaybackState.Stopped; // set explicitly for when we reach the end of the audio RaisePlaybackStoppedEvent(exception); } } } }
/// <summary> /// Called when we get a new buffer of recorded data /// </summary> private void Callback(IntPtr waveInHandle, WaveInterop.WaveMessage message, IntPtr userData, WaveHeader waveHeader, IntPtr reserved) { if (message == WaveInterop.WaveMessage.WaveInData) { var hBuffer = (GCHandle)waveHeader.userData; var buffer = (WaveInBuffer)hBuffer.Target; if (recording) { lastReturnedBufferIndex = Array.IndexOf(buffers, buffer); RaiseDataAvailable(buffer); try { buffer.Reuse(); } catch (Exception e) { recording = false; RaiseRecordingStopped(e); } } } }
/// <summary> /// Stop recording /// </summary> public void StopRecording() { recording = false; this.callbackEvent.Set(); // signal the thread to exit MmException.Try(WaveInterop.waveInStop(waveInHandle), "waveInStop"); }
private void SetVolume(int stereoVolume) { MmException.Try(WaveInterop.waveOutSetVolume(hWaveOut, stereoVolume), "waveOutSetVolume"); }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; // check that we're not here through pressing stop if (PlaybackState == PlaybackState.Playing) { if(!buffer.OnDone()) { playbackState = PlaybackState.Stopped; RaisePlaybackStoppedEvent(); } } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }
public void StopRecording() { this.recording = false; this.callbackEvent.Set(); MmException.Try(WaveInterop.waveInStop(this.waveInHandle), "waveInStop"); }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, Int32 dwUser, WaveHeader wavhdr, int dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { // check that we're not here through pressing stop GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; lock(actionQueue) { actionQueue.Enqueue(new WaveOutAction(WaveOutFunction.BufferDone,buffer)); workAvailable.Set(); } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }