private void StreamSource(ISource aSource) { SendResponse("200 OK"); iSocket.Send(iWavFileHeader); const int kAudioChunkBytes = 144 * 1024; const int kAudioChunks = 4; CaptureBuffer capture = CreateCaptureBuffer(aSource, kAudioChunks * kAudioChunkBytes); int offset = 0; NotificationPosition[] notifications = new NotificationPosition[kAudioChunks]; WaitHandle[] handles = new WaitHandle[kAudioChunks]; for (uint i = 0; i < kAudioChunks; i++) { NotificationPosition notification = new NotificationPosition(); notification.Offset = offset; notification.Event = new ManualResetEvent(false); handles[i] = notification.Event; notifications[i] = notification; offset += kAudioChunkBytes; } capture.SetNotificationPositions(notifications); // Rotate notifications for (uint i = 0; i < kAudioChunks - 1; i++) { WaitHandle a = handles[i]; handles[i] = handles[i + 1]; handles[i + 1] = a; } byte[] audio = new byte[kAudioChunkBytes]; capture.Start(true); try { while (true) { int x = WaitHandle.WaitAny(handles); ManualResetEvent manual = handles[x] as ManualResetEvent; manual.Reset(); capture.Read <byte>(audio, 0, kAudioChunkBytes, notifications[x].Offset, false); iSocket.Send(audio); } } catch (SocketException) { } capture.Stop(); }
public void Start() { if (_Running) { throw new InvalidOperationException(); } if (_CaptureDevice == null) { _CaptureDevice = new DirectSoundCapture(new Guid(_Guid)); } _WaveFormat.FormatTag = WaveFormatTag.Pcm; // Change to WaveFormatTag.IeeeFloat for float _WaveFormat.BitsPerSample = 16; // Set this to 32 for float _WaveFormat.BlockAlignment = (short)(_Channels * (_WaveFormat.BitsPerSample / 8)); _WaveFormat.Channels = _Channels; _WaveFormat.SamplesPerSecond = (int)(SampleRateKhz * 1000D); _WaveFormat.AverageBytesPerSecond = _WaveFormat.SamplesPerSecond * _WaveFormat.BlockAlignment; _BufferPortionCount = 2; _BufferDescription.BufferBytes = _BufferSize * sizeof(short) * _BufferPortionCount * _Channels; _BufferDescription.Format = _WaveFormat; _BufferDescription.WaveMapped = false; _CaptureBuffer = new CaptureBuffer(_CaptureDevice, _BufferDescription); _BufferPortionSize = _CaptureBuffer.SizeInBytes / _BufferPortionCount; _Notifications = new List <NotificationPosition>(); for (int i = 0; i < _BufferPortionCount; i++) { var notification = new NotificationPosition { Offset = _BufferPortionCount - 1 + (_BufferPortionSize * i), Event = new AutoResetEvent(false) }; _Notifications.Add(notification); } _CaptureBuffer.SetNotificationPositions(_Notifications.ToArray()); _WaitHandles = new WaitHandle[_Notifications.Count]; for (int i = 0; i < _Notifications.Count; i++) { _WaitHandles[i] = _Notifications[i].Event; } _CaptureThread = new Thread(_DoCapture) { Name = "DirectSoundCapture", IsBackground = true }; _Running = true; _CaptureThread.Start(); }
public AudioCapture() { try { directSoundCapture = new DirectSoundCapture(); } catch { throw new AudioCaptureException("Could not open recording device"); } //var directSoundCaps = directSoundCapture.Capabilities; // Default 44.1kHz 16-bit stereo PCM waveFormat = new WaveFormat(); // Set the buffer size. // Note that the buffer position will roll over to 0 when the buffer fills up, // so set the notification position's offset to one less than the buffer size. bufferSize = waveFormat.ConvertLatencyToByteSize(latency); numberOfSamples = bufferSize / waveFormat.BlockAlign; // Create audio capture buffer captureBufferDesc = new CaptureBufferDescription(); captureBufferDesc.Format = waveFormat; captureBufferDesc.BufferBytes = bufferSize; captureBuffer = new CaptureBuffer(directSoundCapture, captureBufferDesc); // Wait events allow the thread to wait asynchronously for the buffer to fill var evt = new AutoResetEvent(false); fullEvent = new WaitHandle[] { evt }; // Notify the thread when the buffer is full var nf = new NotificationPosition(); nf.Offset = bufferSize - 1; nf.WaitHandle = fullEvent[0]; var nfs = new NotificationPosition[] { nf }; captureBuffer.SetNotificationPositions(nfs); // Start the processing thread thread = new Thread(new ThreadStart(Process)); thread.IsBackground = true; // Allow application to exit thread.Start(); }
/// <summary> /// Worker thread. /// </summary> /// private void WorkerThread() { // Get the selected capture device DirectSoundCapture captureDevice = new DirectSoundCapture(device); // Set the capture format WaveFormat format = new WaveFormat(); format.Channels = 1; format.SamplesPerSecond = sampleRate; format.FormatTag = sampleFormat.ToWaveFormat(); format.BitsPerSample = (short)Signal.GetSampleSize(sampleFormat); format.BlockAlignment = (short)(format.BitsPerSample / 8); format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlignment; // Setup the capture buffer CaptureBufferDescription captureBufferDescription = new CaptureBufferDescription(); captureBufferDescription.Format = format; captureBufferDescription.BufferBytes = 2 * desiredCaptureSize * format.BlockAlignment; captureBufferDescription.WaveMapped = true; captureBufferDescription.ControlEffects = false; CaptureBuffer captureBuffer = null; NotificationPosition[] notifications = new NotificationPosition[2]; try { captureBuffer = new CaptureBuffer(captureDevice, captureBufferDescription); // Setup the notification positions int bufferPortionSize = captureBuffer.SizeInBytes / 2; notifications[0] = new NotificationPosition(); notifications[0].Offset = bufferPortionSize - 1; notifications[0].Event = new AutoResetEvent(false); notifications[1] = new NotificationPosition(); notifications[1].Offset = bufferPortionSize - 1 + bufferPortionSize; notifications[1].Event = new AutoResetEvent(false); captureBuffer.SetNotificationPositions(notifications); // Make a copy of the wait handles WaitHandle[] waitHandles = new WaitHandle[notifications.Length]; for (int i = 0; i < notifications.Length; i++) { waitHandles[i] = notifications[i].Event; } // Start capturing captureBuffer.Start(true); if (sampleFormat == SampleFormat.Format32BitIeeeFloat) { float[] currentSample = new float[desiredCaptureSize]; while (!stopEvent.WaitOne(0, true)) { int bufferPortionIndex = WaitHandle.WaitAny(waitHandles); captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex); OnNewFrame(currentSample); } } else if (sampleFormat == SampleFormat.Format16Bit) { short[] currentSample = new short[desiredCaptureSize]; while (!stopEvent.WaitOne(0, true)) { int bufferPortionIndex = WaitHandle.WaitAny(waitHandles); captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex); OnNewFrame(currentSample); } } } catch (Exception ex) { if (AudioSourceError != null) { AudioSourceError(this, new AudioSourceErrorEventArgs(ex.Message)); } else { throw; } } finally { if (captureBuffer != null) { captureBuffer.Stop(); captureBuffer.Dispose(); } if (captureDevice != null) { captureDevice.Dispose(); } for (int i = 0; i < notifications.Length; i++) { if (notifications[i].Event != null) { notifications[i].Event.Close(); } } } }
/// <summary> /// Worker thread. /// </summary> /// private void WorkerThread() { // Get the selected capture device DirectSoundCapture captureDevice = new DirectSoundCapture(device); // Set the capture format WaveFormat format = new WaveFormat(); format.Channels = 1; format.SamplesPerSecond = sampleRate; format.FormatTag = sampleFormat.ToWaveFormat(); format.BitsPerSample = (short)Signal.GetSampleSize(sampleFormat); format.BlockAlignment = (short)(format.BitsPerSample / 8); format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlignment; // Setup the capture buffer CaptureBufferDescription captureBufferDescription = new CaptureBufferDescription(); captureBufferDescription.Format = format; captureBufferDescription.BufferBytes = 2 * desiredCaptureSize * format.BlockAlignment; captureBufferDescription.WaveMapped = true; captureBufferDescription.ControlEffects = false; CaptureBuffer captureBuffer = null; NotificationPosition[] notifications = new NotificationPosition[2]; try { captureBuffer = new CaptureBuffer(captureDevice, captureBufferDescription); // Setup the notification positions int bufferPortionSize = captureBuffer.SizeInBytes / 2; notifications[0] = new NotificationPosition(); notifications[0].Offset = bufferPortionSize - 1; notifications[0].Event = new AutoResetEvent(false); notifications[1] = new NotificationPosition(); notifications[1].Offset = bufferPortionSize - 1 + bufferPortionSize; notifications[1].Event = new AutoResetEvent(false); captureBuffer.SetNotificationPositions(notifications); // Make a copy of the wait handles WaitHandle[] waitHandles = new WaitHandle[notifications.Length]; for (int i = 0; i < notifications.Length; i++) waitHandles[i] = notifications[i].Event; // Start capturing captureBuffer.Start(true); if (sampleFormat == SampleFormat.Format32BitIeeeFloat) { float[] currentSample = new float[desiredCaptureSize]; while (!stopEvent.WaitOne(0, true)) { int bufferPortionIndex = WaitHandle.WaitAny(waitHandles); captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex); OnNewFrame(currentSample); } } else if (sampleFormat == SampleFormat.Format16Bit) { short[] currentSample = new short[desiredCaptureSize]; while (!stopEvent.WaitOne(0, true)) { int bufferPortionIndex = WaitHandle.WaitAny(waitHandles); captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex); OnNewFrame(currentSample); } } } catch (Exception ex) { if (AudioSourceError != null) AudioSourceError(this, new AudioSourceErrorEventArgs(ex.Message)); else throw; } finally { if (captureBuffer != null) { captureBuffer.Stop(); captureBuffer.Dispose(); } if (captureDevice != null) captureDevice.Dispose(); for (int i = 0; i < notifications.Length; i++) if (notifications[i].Event != null) notifications[i].Event.Close(); } }
private void startRecordingOrMonitoring(AudioLibPCMFormat pcmFormat, bool recordingToFile) { RecordingPCMFormat = pcmFormat; #if USE_SHARPDX WaveFormat waveFormat = new WaveFormat((int)RecordingPCMFormat.SampleRate, 16, (int)RecordingPCMFormat.NumberOfChannels); #else WaveFormat waveFormat = new WaveFormat(); waveFormat.FormatTag = WaveFormatTag.Pcm; waveFormat.Channels = (short)RecordingPCMFormat.NumberOfChannels; waveFormat.SamplesPerSecond = (int)RecordingPCMFormat.SampleRate; waveFormat.BitsPerSample = (short)RecordingPCMFormat.BitDepth; waveFormat.AverageBytesPerSecond = (int)RecordingPCMFormat.SampleRate * RecordingPCMFormat.BlockAlign; waveFormat.BlockAlign = (short)RecordingPCMFormat.BlockAlign; #endif uint byteRate = RecordingPCMFormat.SampleRate * RecordingPCMFormat.BlockAlign; int pcmDataBufferSize = (int)(byteRate * REFRESH_INTERVAL_MS / 1000.0); pcmDataBufferSize -= pcmDataBufferSize % RecordingPCMFormat.BlockAlign; // here we are probably wasting some heap memory, // because the event arg payload buffer (for "data available" event) // contains the delta between capture and read circular buffer positions. // however, this makes the memory re-alloc (i.e. buffer resize) routine simpler, // that is to say here only when start record/monitor, // instead of inside the DirectAudio capture thread (based on the actual circular buffer delta). m_PcmDataBufferLength = pcmDataBufferSize * NOTIFICATIONS; if (m_PcmDataBuffer == null) { Console.WriteLine("ALLOCATING m_PcmDataBuffer"); m_PcmDataBuffer = new byte[m_PcmDataBufferLength]; } else if (m_PcmDataBuffer.Length < m_PcmDataBufferLength) { Console.WriteLine("m_PcmDataBuffer.resize"); Array.Resize(ref m_PcmDataBuffer, m_PcmDataBufferLength); } int circularBufferSize = pcmDataBufferSize * NOTIFICATIONS; CaptureBufferDescription bufferDescription = new CaptureBufferDescription(); bufferDescription.BufferBytes = circularBufferSize; bufferDescription.Format = waveFormat; #if USE_SHARPDX bufferDescription.Flags = CaptureBufferCapabilitiesFlags.WaveMapped; //CaptureBufferCapabilitiesFlags.ControlEffects if (InputDevice == null) { Console.WriteLine("/// InputDevice NULL, attempting reset..."); List <InputDevice> inputDevices = InputDevices; Console.WriteLine("/// InputDevices: " + inputDevices.Count); SetInputDevice("dummy"); } m_CircularBuffer = new CaptureBuffer(InputDevice.Capture, bufferDescription); #else m_CircularBuffer = new CaptureBuffer(bufferDescription, InputDevice.Capture); #endif #if FORCE_SINGLE_NOTIFICATION_EVENT m_CircularBufferNotificationEvent = new AutoResetEvent(false); #else m_CircularBufferNotificationEvents = new AutoResetEvent[NOTIFICATIONS]; #endif #if USE_SHARPDX NotificationPosition[] m_BufferPositionNotify = new NotificationPosition[NOTIFICATIONS]; #else BufferPositionNotify[] m_BufferPositionNotify = new BufferPositionNotify[NOTIFICATIONS]; #endif for (int i = 0; i < NOTIFICATIONS; i++) { #if USE_SHARPDX m_BufferPositionNotify[i] = new NotificationPosition(); #endif m_BufferPositionNotify[i].Offset = (pcmDataBufferSize * i) + pcmDataBufferSize - 1; #if FORCE_SINGLE_NOTIFICATION_EVENT #if USE_SHARPDX m_BufferPositionNotify[i].WaitHandle = m_CircularBufferNotificationEvent; //m_BufferPositionNotify[i].EventNotifyHandlePointer = m_CircularBufferNotificationEvent.SafeWaitHandle.DangerousGetHandle(); #else m_BufferPositionNotify[i].EventNotifyHandle = m_CircularBufferNotificationEvent.SafeWaitHandle.DangerousGetHandle(); #endif #else m_CircularBufferNotificationEvents[i] = new AutoResetEvent(false); #if USE_SHARPDX m_BufferPositionNotify[i].WaitHandle = m_CircularBufferNotificationEvents[i]; //m_BufferPositionNotify[i].EventNotifyHandlePointer = m_CircularBufferNotificationEvents[i].SafeWaitHandle.DangerousGetHandle(); #else m_BufferPositionNotify[i].EventNotifyHandle = m_CircularBufferNotificationEvents[i].SafeWaitHandle.DangerousGetHandle(); #endif #endif } #if USE_SHARPDX m_CircularBuffer.SetNotificationPositions(m_BufferPositionNotify); #else m_Notify = new Notify(m_CircularBuffer); m_Notify.SetNotificationPositions(m_BufferPositionNotify, NOTIFICATIONS); #endif m_CircularBufferReadPositon = 0; m_RecordingFileWriter = null; m_TotalRecordedBytes = 0; #if FORCE_SINGLE_NOTIFICATION_EVENT m_PreviousTotalRecordedBytes = 0; #endif if (recordingToFile) { int i = -1; do { i++; m_RecordedFilePath = RecordingDirectory + Path.DirectorySeparatorChar + i.ToString() + WavFormatConverter.AUDIO_WAV_EXTENSION; } while (File.Exists(m_RecordedFilePath)); Stream stream = File.Create(m_RecordedFilePath); try { m_RecordedFileRiffHeaderSize = RecordingPCMFormat.RiffHeaderWrite(stream, 0); } finally { stream.Close(); } } ThreadStart threadDelegate = delegate() { try { circularBufferRefreshThreadMethod(); } catch (ThreadAbortException ex) { // } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } finally { lock (LOCK_THREAD_INSTANCE) { m_CircularBufferRefreshThread = null; } } //lock (LOCK_THREAD_INSTANCE) //{ // m_CircularBufferRefreshThread = null; //} }; lock (LOCK_THREAD_INSTANCE) { m_CircularBufferRefreshThread = new Thread(threadDelegate); m_CircularBufferRefreshThread.Name = "Recorder Notify Thread"; m_CircularBufferRefreshThread.Priority = ThreadPriority.AboveNormal; m_CircularBufferRefreshThread.IsBackground = true; CurrentState = (recordingToFile ? State.Recording : State.Monitoring); m_CircularBuffer.Start(true); m_CircularBufferRefreshThread.Start(); #if FORCE_SINGLE_NOTIFICATION_EVENT m_CircularBufferTimer.Start(); #endif } //Console.WriteLine("Recorder notify thread start."); }
/// <summary> /// Worker thread. /// </summary> /// private void WorkerThread() { needToStop = false; // Get the selected capture device DirectSoundCapture captureDevice = new DirectSoundCapture(device); // Set the capture format var bitsPerSample = Signal.GetSampleSize(sampleFormat); WaveFormat format = WaveFormat.CreateCustomFormat(sampleFormat.ToWaveFormat(), sampleRate, 1, sampleRate * bitsPerSample / 8, bitsPerSample / 8, bitsPerSample); // Setup the capture buffer CaptureBufferDescription captureBufferDescription = new CaptureBufferDescription(); captureBufferDescription.Format = format; captureBufferDescription.BufferBytes = 2 * desiredCaptureSize * format.BlockAlign; captureBufferDescription.Flags |= CaptureBufferCapabilitiesFlags.WaveMapped; captureBufferDescription.Flags &= ~CaptureBufferCapabilitiesFlags.ControlEffects; CaptureBuffer captureBuffer = null; NotificationPosition[] notifications = new NotificationPosition[2]; try { captureBuffer = new CaptureBuffer(captureDevice, captureBufferDescription); // Setup the notification positions int bufferPortionSize = captureBuffer.Capabilities.BufferBytes / 2; notifications[0] = new NotificationPosition(); notifications[0].Offset = bufferPortionSize - 1; notifications[0].WaitHandle = new AutoResetEvent(false); notifications[1] = new NotificationPosition(); notifications[1].Offset = bufferPortionSize - 1 + bufferPortionSize; notifications[1].WaitHandle = new AutoResetEvent(false); captureBuffer.SetNotificationPositions(notifications); // Make a copy of the wait handles WaitHandle[] waitHandles = new WaitHandle[notifications.Length]; for (int i = 0; i < notifications.Length; i++) { waitHandles[i] = notifications[i].WaitHandle; } // Start capturing captureBuffer.Start(true); if (sampleFormat == SampleFormat.Format32BitIeeeFloat) { float[] currentSample = new float[desiredCaptureSize]; Signal signal = Signal.FromArray(currentSample, sampleRate, sampleFormat); while (!needToStop) { int bufferPortionIndex = WaitHandle.WaitAny(waitHandles); captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex, LockFlags.None); OnNewFrame(signal); } } else if (sampleFormat == SampleFormat.Format16Bit) { short[] currentSample = new short[desiredCaptureSize]; Signal signal = Signal.FromArray(currentSample, sampleRate, sampleFormat); while (!needToStop) { int bufferPortionIndex = WaitHandle.WaitAny(waitHandles); captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex, LockFlags.None); OnNewFrame(signal); } } } catch (Exception ex) { if (AudioSourceError == null) { throw; } AudioSourceError(this, new AudioSourceErrorEventArgs(ex)); } finally { if (captureBuffer != null) { captureBuffer.Stop(); captureBuffer.Dispose(); } if (captureDevice != null) { captureDevice.Dispose(); } #if !NETSTANDARD1_4 for (int i = 0; i < notifications.Length; i++) { if (notifications[i].WaitHandle != null) { notifications[i].WaitHandle.Close(); } } #endif } }