public void Stop() { if (this.state == RecordingState.Opened || this.state == RecordingState.Closed) { throw new InvalidOperationException(); } if (this.state == RecordingState.Recording) { this.state = RecordingState.Stopping; // Get remaining data from the buffer, this causes a call to the callback function int mmr = MMInterop.waveInReset(this.hWaveIn); if (mmr != 0) { throw new SoundException("waveInReset", mmr); } // Wait for the recorder thread to stop recording if it is still alive if (this.recorderThread.IsAlive) { this.recorderThread.Join(); } } // Close stuff this.recordingSemaphore.Close(); // Here recording is stopped this.state = RecordingState.Opened; }
public SoundDevice[] GetDevices() { uint numDevices = MMInterop.waveInGetNumDevs(); List <SoundDevice> devices = new List <SoundDevice>((int)numDevices); for (uint i = 0; i < numDevices; i++) { // Get device capabilities MMInterop.WAVEINCAPS caps = new MMInterop.WAVEINCAPS(); int mmr = MMInterop.waveInGetDevCaps(i, ref caps, (uint)Marshal.SizeOf(caps)); if (mmr == MMInterop.MMSYSERR_NODRIVER) { // No device driver is present. continue; } if (mmr != 0) { throw new SoundException("waveInGetDevCaps", mmr); } // Compare device name to loopback device names to see if // it is a loopback device bool isLoopback = false; foreach (string loopbackName in loopbackDeviceNames) { if (loopbackName.Equals(caps.szPname)) { isLoopback = true; break; } } SoundDevice device = new SoundDevice(i.ToString(), caps.szPname, isLoopback); devices.Add(device); } return(devices.ToArray()); }
public SoundFormat[] GetDeviceFormats(string deviceId) { if (string.IsNullOrEmpty(deviceId)) { throw new ArgumentNullException("deviceId"); } uint uintId; if (!uint.TryParse(deviceId, out uintId)) { throw new ArgumentException("deviceId"); } uint nDevice = MMInterop.waveInGetNumDevs(); if (uintId <= nDevice - 1) { MMInterop.WAVEINCAPS caps = new MMInterop.WAVEINCAPS(); int mmr = MMInterop.waveInGetDevCaps(uintId, ref caps, (uint)Marshal.SizeOf(caps)); if (mmr != 0) { throw new SoundException("waveInGetDevCaps", mmr); } return(Util.WaveFormatToSoundFormats((MMInterop.WaveFormat)caps.dwFormats)); } throw new SoundException("Device not found."); }
public void Close() { // Stop recording first if (this.state == RecordingState.Recording) { this.Stop(); } // Delete headers (and associated buffers) if (this.gchHeaders != null) { foreach (GCHandle gchHeader in this.gchHeaders) { this.DeleteHeader(gchHeader); } this.gchHeaders = null; } // Close wave handle if (this.hWaveIn != IntPtr.Zero) { MMInterop.waveInClose(this.hWaveIn); this.hWaveIn = IntPtr.Zero; } if (this.pwfx != IntPtr.Zero) { Marshal.FreeHGlobal(this.pwfx); this.pwfx = IntPtr.Zero; } this.output = null; this.state = RecordingState.Closed; }
public static SoundFormat[] WaveFormatToSoundFormats(MMInterop.WaveFormat formats) { List<SoundFormat> soundFormats = new List<SoundFormat>(); Array allValues = Enum.GetValues(typeof(MMInterop.WaveFormat)); foreach (var value in allValues) { MMInterop.WaveFormat vformat = (MMInterop.WaveFormat)value; if ((int)value == 0) { // WAVE_INVALID_FORMAT continue; } if ((formats & vformat) == vformat) { SoundFormat format = WaveFormatToSoundFormat(vformat); soundFormats.Add(format); } } return soundFormats.ToArray(); }
public static SoundFormat WaveFormatToSoundFormat(MMInterop.WaveFormat format) { switch (format) { case MMInterop.WaveFormat.WAVE_FORMAT_1M08: return new SoundFormat(SoundFormatTag.PCM, 8, 1, 11025); case MMInterop.WaveFormat.WAVE_FORMAT_1M16: return new SoundFormat(SoundFormatTag.PCM, 16, 1, 11025); case MMInterop.WaveFormat.WAVE_FORMAT_1S08: return new SoundFormat(SoundFormatTag.PCM, 8, 2, 11025); case MMInterop.WaveFormat.WAVE_FORMAT_1S16: return new SoundFormat(SoundFormatTag.PCM, 16, 2, 11025); case MMInterop.WaveFormat.WAVE_FORMAT_2M08: return new SoundFormat(SoundFormatTag.PCM, 8, 1, 22050); case MMInterop.WaveFormat.WAVE_FORMAT_2M16: return new SoundFormat(SoundFormatTag.PCM, 16, 1, 22050); case MMInterop.WaveFormat.WAVE_FORMAT_2S08: return new SoundFormat(SoundFormatTag.PCM, 8, 2, 22050); case MMInterop.WaveFormat.WAVE_FORMAT_2S16: return new SoundFormat(SoundFormatTag.PCM, 16, 2, 22050); case MMInterop.WaveFormat.WAVE_FORMAT_44M08: return new SoundFormat(SoundFormatTag.PCM, 8, 1, 44100); case MMInterop.WaveFormat.WAVE_FORMAT_44M16: return new SoundFormat(SoundFormatTag.PCM, 16, 1, 44100); case MMInterop.WaveFormat.WAVE_FORMAT_44S08: return new SoundFormat(SoundFormatTag.PCM, 8, 2, 44100); case MMInterop.WaveFormat.WAVE_FORMAT_44S16: return new SoundFormat(SoundFormatTag.PCM, 16, 2, 44100); case MMInterop.WaveFormat.WAVE_FORMAT_48M08: return new SoundFormat(SoundFormatTag.PCM, 8, 1, 48000); case MMInterop.WaveFormat.WAVE_FORMAT_48M16: return new SoundFormat(SoundFormatTag.PCM, 16, 1, 48000); case MMInterop.WaveFormat.WAVE_FORMAT_48S08: return new SoundFormat(SoundFormatTag.PCM, 8, 2, 48000); case MMInterop.WaveFormat.WAVE_FORMAT_48S16: return new SoundFormat(SoundFormatTag.PCM, 16, 2, 48000); case MMInterop.WaveFormat.WAVE_FORMAT_96M08: return new SoundFormat(SoundFormatTag.PCM, 8, 1, 96000); case MMInterop.WaveFormat.WAVE_FORMAT_96M16: return new SoundFormat(SoundFormatTag.PCM, 16, 1, 96000); case MMInterop.WaveFormat.WAVE_FORMAT_96S08: return new SoundFormat(SoundFormatTag.PCM, 8, 2, 96000); case MMInterop.WaveFormat.WAVE_FORMAT_96S16: return new SoundFormat(SoundFormatTag.PCM, 16, 2, 96000); default: throw new ArgumentOutOfRangeException(); } }
public void Open() { if (this.state != RecordingState.Closed) { throw new InvalidOperationException(); } if (format == null) { throw new InvalidOperationException("Format is not specified."); } // Open wave this.pwfx = this.format.ToPtr(); int mmr = MMInterop.waveInOpen(ref this.hWaveIn, this.deviceId, this.pwfx, this.callback, 0, MMInterop.CALLBACK_FUNCTION); if (mmr != 0) { throw new SoundException("waveInOpen", mmr); } try { // Initialise buffers int bufferSize = (int)(((double)this.bufferLength / msPerSecond) * this.format.AverageBytesPerSecond); this.gchHeaders = new GCHandle[bufferCount]; if (bufferSize % this.format.BlockAlign != 0) { bufferSize += this.format.BlockAlign - (bufferSize % this.format.BlockAlign); } for (int i = 0; i < bufferCount; i++) { GCHandle gchHeader = this.CreateHeader(bufferSize); this.gchHeaders.SetValue(gchHeader, i); } this.nBytesLost = 0; this.output = new Queue <byte[]>(); this.state = RecordingState.Opened; } finally { if (this.state != RecordingState.Opened) { this.Close(); } } }
private void DeleteHeader(GCHandle gchHeader) { // Unprepare header int size = Marshal.SizeOf(typeof(MMInterop.WAVEHDR)); IntPtr pHeader = gchHeader.AddrOfPinnedObject(); MMInterop.waveInUnprepareHeader(this.hWaveIn, pHeader, (uint)size); // Free buffer (allocated in the CreateHeader method) MMInterop.WAVEHDR header = (MMInterop.WAVEHDR)gchHeader.Target; if (header.lpData != IntPtr.Zero) { Marshal.FreeHGlobal(header.lpData); header.lpData = IntPtr.Zero; } // Unpin header if (gchHeader.IsAllocated) { gchHeader.Free(); } }
private GCHandle CreateHeader(int bufferSize) { // Create header int size = Marshal.SizeOf(typeof(MMInterop.WAVEHDR)); MMInterop.WAVEHDR header = new MMInterop.WAVEHDR(); header.dwBufferLength = (uint)bufferSize; header.lpData = Marshal.AllocHGlobal(bufferSize); // Prepare header // Wave headers need to be fixed in memory GCHandle gchHeader = GCHandle.Alloc(header, GCHandleType.Pinned); IntPtr pHeader = gchHeader.AddrOfPinnedObject(); int mmr = MMInterop.waveInPrepareHeader(this.hWaveIn, pHeader, (uint)size); if (mmr != 0) { throw new SoundException("waveInPrepareHeader", mmr); } return(gchHeader); }
public int Read(byte[] buffer, int offset, int length, bool isEnd) { if (buffer == null) { throw new ArgumentNullException("buffer"); } int bytesRead = 0; if (isEnd && this.state == RecordingState.Recording) { lock (syncRoot) { this.state = RecordingState.Stopping; // Get remaining data from the buffer, this causes a call to the callback function int mmr = MMInterop.waveInReset(this.hWaveIn); if (mmr != 0) { throw new SoundException("waveInReset", mmr); } } // Wait for the recorder thread to stop recording if it is still alive if (this.recorderThread.IsAlive) { this.recorderThread.Join(); } } // Copy data from output queue to the buffer parameter lock (syncRoot) { if (nBytesLost > 0) { int nEmptyDataBytes = Math.Min(nBytesLost, length); for (int i = 0; i < nEmptyDataBytes; i++) { buffer[offset + i] = 0; } nBytesLost -= nEmptyDataBytes; bytesRead += nEmptyDataBytes; } while (bytesRead < length && output.Count > 0) { byte[] data = output.Peek(); int dataLength = data.Length; if (dataLength <= (length - bytesRead)) { Array.Copy(data, 0, buffer, bytesRead, dataLength); bytesRead += dataLength; output.Dequeue(); } else { if (isEnd) { // Copy data from the queue to the buffer as much as possible // since it is last read Array.Copy(data, 0, buffer, bytesRead, length - bytesRead); } break; } } if (isEnd) { output.Clear(); } } return(bytesRead); }
private void Record() { // Create buffer queue Queue <GCHandle> gchHeaderQueue = new Queue <GCHandle>(); // Pin buffers and add them to queue int size = Marshal.SizeOf(typeof(MMInterop.WAVEHDR)); int mmr; foreach (GCHandle gchHeader in this.gchHeaders) { IntPtr pHeader = gchHeader.AddrOfPinnedObject(); mmr = MMInterop.waveInAddBuffer(this.hWaveIn, pHeader, (uint)size); if (mmr != 0) { throw new SoundException("waveInStart", mmr); } gchHeaderQueue.Enqueue(gchHeader); } // Start recording mmr = MMInterop.waveInStart(this.hWaveIn); if (mmr != 0) { throw new SoundException("waveInStart", mmr); } // Recording loop while (this.state != RecordingState.Opened) { // Wait a buffer become full this.recordingSemaphore.WaitOne(); // Get the buffer from buffer queue GCHandle gchHeader = gchHeaderQueue.Dequeue(); MMInterop.WAVEHDR header = (MMInterop.WAVEHDR)gchHeader.Target; // Copy data from the buffer to the output queue int bytesRecorded = (int)header.dwBytesRecorded; if (bytesRecorded > 0) { byte[] data = new byte[bytesRecorded]; Marshal.Copy(header.lpData, data, 0, bytesRecorded); lock (syncRoot) { if (output.Count == bufferCount) // Is output queue full? // Drop an item { byte[] outputData = output.Dequeue(); this.nBytesLost += outputData.Length; } // Add data to output queue output.Enqueue(data); } } if (this.state == RecordingState.Stopping) { if (gchHeaderQueue.Count == 0) // All the buffers are done { break; // No more recording } } else if (this.state == RecordingState.Recording) // Recording is not stopped { lock (syncRoot) { // Make sure recording is not stopped if (this.state == RecordingState.Recording) { IntPtr pHeader = gchHeader.AddrOfPinnedObject(); mmr = MMInterop.waveInAddBuffer(this.hWaveIn, pHeader, (uint)size); if (mmr != 0) { throw new SoundException("waveInAddBuffer", mmr); } gchHeaderQueue.Enqueue(gchHeader); } } } } // Stop recording mmr = MMInterop.waveInStop(this.hWaveIn); }
private void WaveCallback(IntPtr hwi, MMInterop.WIMMessages uMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2) { if (uMsg == MMInterop.WIMMessages.MM_WIM_DATA) { // Let the recorder thread know another buffer is full this.recordingSemaphore.Release(); } }