// Copies data from the capture buffer to the output buffer public void RecordCapturedData( ) { int ReadPos; byte[] CaptureData = null; int CapturePos; int LockSize; applicationBuffer.GetCurrentPosition(out CapturePos, out ReadPos); CalculationFunctions cf = new CalculationFunctions(); long CurrentPosition = (long)CapturePos; CurrentPositionInByte = CurrentPosition + SampleCount; dCurrentTime = cf.ConvertByteToTime(CurrentPosition, m_SampleRate, m_FrameSize); m_UpdateVMArrayLength = m_iCaptureBufferSize / 50; m_UpdateVMArrayLength = Convert.ToInt32(cf.AdaptToFrame(Convert.ToInt32(m_UpdateVMArrayLength), m_FrameSize)); arUpdateVM = new byte [m_UpdateVMArrayLength]; ReadPos = CapturePos; if (ReadPos < ((m_iCaptureBufferSize) - m_UpdateVMArrayLength)) { Array.Copy(applicationBuffer.Read(ReadPos, typeof(byte), LockFlag.None, m_UpdateVMArrayLength), arUpdateVM, m_UpdateVMArrayLength); //ob_UpdateVuMeter.NotifyUpdateVuMeter ( this, ob_UpdateVuMeter ) ; UpdateVuMeterFromRecorder(this, new events.AudioRecorderEvents.UpdateVuMeterFromRecorder()); } LockSize = ReadPos - NextCaptureOffset; if (LockSize < 0) { LockSize += m_iCaptureBufferSize; } // Block align lock size so that we are always write on a boundary LockSize -= (LockSize % m_iNotifySize); if (0 == LockSize) { return; } // Read the capture buffer. CaptureData = (byte[])applicationBuffer.Read(NextCaptureOffset, typeof(byte), LockFlag.None, LockSize); FileInfo fi = new FileInfo(m_sFileName); BinaryWriter Writer = new BinaryWriter(File.OpenWrite(m_sFileName)); // Write the data into the wav file"); Writer.BaseStream.Position = (long)(fi.Length); //Writer.Seek(0, SeekOrigin.End); Writer.Write(CaptureData, 0, CaptureData.Length); Writer.Close(); Writer = null; NotifyThread = null; // Update the number of samples, in bytes, of the file so far. //SampleCount+= datalength; SampleCount += (long)CaptureData.Length; // Move the capture offset along NextCaptureOffset += CaptureData.Length; NextCaptureOffset %= m_iCaptureBufferSize; // Circular buffer }
private void RecordWorker() { try { byte[] buf = new byte[mBufferLength]; MemoryStream memStream = new MemoryStream(buf); int readLength = mBufferLength / 4; int latestReadCursor = 0; int latestReadPosition = 0; mBuffer.Start(true); setState(AudioDeviceState.Recording); double[] maxDbs; while (true) { int captureCursor, readCursor; mBuffer.GetCurrentPosition(out captureCursor, out readCursor); if (readCursor < latestReadCursor) { mCycleCount++; } int currentReadPosition = readCursor + (mCycleCount * mBufferLength); //Do read if there is more than readLength bytes to read or if recording has stopped if (mHasRecordingStopped) { memStream.Position = 0; mBuffer.Read(latestReadPosition % mBufferLength, memStream, currentReadPosition - latestReadPosition, LockFlag.None); mPCMOutoutStream.Write(buf, 0, currentReadPosition - latestReadPosition); handleRecordedData(buf, 0, currentReadPosition - latestReadPosition, out maxDbs); FireTime(getTimeEquivalent(readCursor + (mCycleCount * mBufferLength)), maxDbs); break; } else if (latestReadPosition + readLength < currentReadPosition) { memStream.Position = 0; mBuffer.Read(latestReadPosition % mBufferLength, memStream, currentReadPosition - latestReadPosition, LockFlag.None); mPCMOutoutStream.Write(buf, 0, currentReadPosition - latestReadPosition); handleRecordedData(buf, 0, currentReadPosition - latestReadPosition, out maxDbs); latestReadPosition = currentReadPosition; FireTime(getTimeEquivalent(readCursor + (mCycleCount * mBufferLength)), maxDbs); } latestReadCursor = readCursor; Thread.Sleep(WAIT_TIME_MS); } mBuffer.Dispose(); } catch (ThreadAbortException) { if (mBuffer != null) { if (!mBuffer.Disposed) { mBuffer.Dispose(); } } } }
public static void StartCapturing() { try { captureBuffer = new CaptureBuffer(captureBufferDescription, capture); SetBufferEvents(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); while (true) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); if (!StopLoop) { OnBufferFulfill(dataToWrite, null); } } } catch (Exception e) { // } }
public void StartCapturing() { try { _captureBuffer = new CaptureBuffer(_capBufDescr, _capture); SetBufferEvents(); int halfBuffer = _bufferSize / 2; _captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); while (true) { _eventToReset.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); _captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); if (!_StopLoop) { OnBufferFulfill(dataToWrite, null); } } } catch {} }
public void StartCapturing() { try { captureBuffer = new CaptureBuffer(captureBufferDescription, capture); // Set Buffer Size,Voice Recording Format & Input Voice Device SetBufferEvents(); // Set the events Positions to Send While Recording int halfBuffer = bufferSize / 2; // Take the half buffer size captureBuffer.Start(true); // start capturing bool readFirstBufferPart = true; // to know which part has been filled (the buufer has been divided into tow parts) int offset = 0; // at point 0 MemoryStream memStream = new MemoryStream(halfBuffer); // set the half buffer size to the memory stream while (true) // Looping until Stoploop=true Set by the talker { //WaitOne() Blocks the current thread until the current WaitHandle receives a signal //WaitHandle("Encapsulates operating system–specific objects that wait for exclusive access to shared resources") autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); //Sets the position within the current stream to 0 captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); // capturing and set to MemoryStream readFirstBufferPart = !readFirstBufferPart; // reflecting the boolean value to set the new comming buffer to the other part offset = readFirstBufferPart ? 0 : halfBuffer; // if readFirstBufferPart set to true then set the offset to 0 else set the offset to the half buffer byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); // G.711 Encoding, Compress to less then 50% if (!StopLoop) { OnBufferFulfill(dataToWrite, null); } } } catch {} }
private void RecordCapturedData() { byte[] CaptureData = null; int ReadPos; int CapturePos; int LockSize; mRecBuffer.GetCurrentPosition(out CapturePos, out ReadPos); LockSize = ReadPos - mNextCaptureOffset; if (LockSize < 0) { LockSize += mBufferSize; } // 对齐缓冲区边界,实际上由于开始设定完整,这个操作是多余的. LockSize -= (LockSize % mNotifySize); if (0 == LockSize) { return; } // 读取缓冲区内的数据 CaptureData = (byte[])mRecBuffer.Read(mNextCaptureOffset, typeof(byte), LockFlag.None, LockSize); // 写入Wav文件 mWriter.Write(CaptureData, 0, CaptureData.Length); // 更新已经录制的数据长度. mSampleCount += CaptureData.Length; // 移动录制数据的起始点,通知消息只负责指示产生消息的位置,并不记录上次录制的位置 mNextCaptureOffset += CaptureData.Length; mNextCaptureOffset %= mBufferSize; // Circular buffer }
//真正转移数据的事件,其实就是把数据传送到网络上去。 private void RecordCapturedData(Socket Client, EndPoint epServer) { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小 if (locksize == 0) { return; } if (locksize < 0) {//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 locksize += iBufferSize; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize); //capturedata = g729.Encode(capturedata);//语音编码 try { Console.WriteLine(new DateTime() + "=====传送语音"); Client.SendTo(capturedata, epServer);//传送语音 Console.WriteLine(new DateTime() + "=====播放语音"); GetVoiceData(capturedata.Length, capturedata); } catch (Exception ex) { Console.WriteLine("发送语音异常:" + ex.Message); throw new Exception(); } iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。 }
public void RecordCapturedData() { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset; if (locksize < 0) { locksize += iBufferSize; } locksize -= (locksize % iNotifySize); if (0 == locksize) { return; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.None, locksize); sck.Send(capturedata); Console.WriteLine("Keep sending data..."); mWriter.Write(capturedata, 0, capturedata.Length); iSampleSize += capturedata.Length; iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize; Console.WriteLine("Keep writing data into file"); }
/// <summary> /// 将录制的数据写入wav文件 /// </summary> private void RecordCapturedData() { byte[] CaptureData = null; int ReadPos = 0, CapturePos = 0, LockSize = 0; mRecBuffer.GetCurrentPosition(out CapturePos, out ReadPos); LockSize = ReadPos - mNextCaptureOffset; if (LockSize < 0) // 因为是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 { LockSize += mBufferSize; } LockSize -= (LockSize % mNotifySize); // 对齐缓冲区边界,实际上由于开始设定完整,这个操作是多余的. if (0 == LockSize) { return; } // 读取缓冲区内的数据 CaptureData = (byte[])mRecBuffer.Read(mNextCaptureOffset, typeof(byte), LockFlag.None, LockSize); lock (currentdata) { currentdata.AddRange(CaptureData); } // 写入Wav文件 mWriter.Write(CaptureData, 0, CaptureData.Length); // 更新已经录制的数据长度. mSampleCount += CaptureData.Length; // 移动录制数据的起始点,通知消息只负责指示产生消息的位置,并不记录上次录制的位置 mNextCaptureOffset += CaptureData.Length; mNextCaptureOffset %= mBufferSize; // Circular buffer }
private void CaptureData() { int readPos = 0, capturePos = 0, lockSize = 0; captureBuffer_.GetCurrentPosition(out capturePos, out readPos); lockSize = readPos - captureOffset_; if (lockSize < 0) // 因为是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 { lockSize += captureBufferSize_; } lockSize -= (lockSize % notifySize_); // 对齐缓冲区边界,实际上由于开始设定完整,这个操作是多余的. if (0 == lockSize) { return; } // 读取缓冲区内的数据 byte[] captureData = (byte[])captureBuffer_.Read(captureOffset_, typeof(byte), LockFlag.None, lockSize); // 写入Wav文件 writer_.Write(captureData, 0, captureData.Length); // 更新已经录制的数据长度. captureDataLength_ += captureData.Length; // 移动录制数据的起始点,通知消息只负责指示产生消息的位置,并不记录上次录制的位置 captureOffset_ += captureData.Length; captureOffset_ %= captureBufferSize_; // Circular buffer }
public float GetSignFromDevice(out float response) { cap = new Capture(deviceGuid); desc = new CaptureBufferDescription(); WaveFormat wf = new WaveFormat(); wf.BitsPerSample = bitsPerSample; wf.SamplesPerSecond = sampleRate; wf.Channels = channels; wf.BlockAlign = (short)(wf.Channels * wf.BitsPerSample / 8); wf.AverageBytesPerSecond = wf.BlockAlign * wf.SamplesPerSecond; wf.FormatTag = WaveFormatTag.Pcm; desc.Format = wf; desc.BufferBytes = SAMPLES * wf.BlockAlign; buffer = new Microsoft.DirectX.DirectSound.CaptureBuffer(desc, cap); buffer.Start(true); while (start) { Array samples = buffer.Read(0, typeof(Int16), LockFlag.FromWriteCursor, SAMPLE_FORMAT_ARRAY); response = ((float)samples.GetValue(0, 0, 0)) / 100; } response = 0.0f; return(0.0f); }
//真正转移数据的事件,其实就是把数据转移到WAV文件中。 private void RecordCapturedData() { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小 if (locksize == 0) { return; } if (locksize < 0) {//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 locksize += iBufferSize; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize); //发送出去 Thread thread = new Thread(new ParameterizedThreadStart(Send)); thread.IsBackground = true; thread.Start(capturedata); iSampleSize += capturedata.Length; iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。 }
private void Send() { try { captureBuffer = new CaptureBuffer(captureBufferDescription, cap); CreateNotifyPositions(); int num = checked ((int)Math.Round(unchecked ((double)bufferSize / 2.0))); captureBuffer.Start(true); bool flag = true; int bufferStartingLocation = 0; MemoryStream memoryStream = new MemoryStream(num); while (flagSrarting) { autoResetEvent.WaitOne(); memoryStream.Seek(0L, SeekOrigin.Begin); captureBuffer.Read(bufferStartingLocation, memoryStream, num, LockFlag.None); flag = !flag; bufferStartingLocation = ((!flag) ? num : 0); byte[] buffer = memoryStream.GetBuffer(); udpSend.Send(buffer, buffer.Length, send_Com); } } catch (Exception ex) { ProjectData.SetProjectError(ex); Exception ex2 = ex; ProjectData.ClearProjectError(); } finally { captureBuffer.Stop(); captureBuffer.Dispose(); udpSend.Close(); } }
//真正转移数据的事件,其实就是把数据传送到网络上去。 private void RecordCapturedData(EndPoint Client) { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小 if (locksize == 0) { return; } if (locksize < 0) {//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 locksize += iBufferSize; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize); //capturedata = g729.Encode(capturedata);//语音编码 try { server.SendTo(capturedata, point); } catch { //throw new Exception(); } try { iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。 } catch { } }
private void ThreadLoop() { buffer.Start(true); try { int nextCapturePosition = 0; WaitHandle[] handles = new WaitHandle[] { terminated, positionEvent }; while (WaitHandle.WaitAny(handles) > 0) { int capturePosition, readPosition; buffer.GetCurrentPosition(out capturePosition, out readPosition); int lockSize = readPosition - nextCapturePosition; if (lockSize < 0) { lockSize += bufferLength; } if ((lockSize & 1) != 0) { lockSize--; } int itemsCount = lockSize >> 1; short[] data = (short[])buffer.Read(nextCapturePosition, typeof(short), LockFlag.None, itemsCount); ProcessData(data); nextCapturePosition = (nextCapturePosition + lockSize) % bufferLength; } } finally { buffer.Stop(); } }
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(); }
// Copies data from the capture buffer to the output buffer public void RecordCapturedData( ) { int ReadPos; int CapturePos; int LockSize; applicationBuffer.GetCurrentPosition(out CapturePos, out ReadPos); ReadPos = CapturePos; if (ReadPos < ((m_iCaptureBufferSize) - m_UpdateVMArrayLength)) { Array.Copy(applicationBuffer.Read(ReadPos, typeof(byte), LockFlag.None, m_UpdateVMArrayLength), arUpdateVM, m_UpdateVMArrayLength); ob_UpdateVuMeter.NotifyUpdateVuMeter(this, ob_UpdateVuMeter); } LockSize = ReadPos - NextCaptureOffset; if (LockSize < 0) { LockSize += m_iCaptureBufferSize; } // Block align lock size so that we are always write on a boundary LockSize -= (LockSize % m_iNotifySize); if (0 == LockSize) { return; } // Read the capture buffer. CaptureData = (byte[])applicationBuffer.Read(NextCaptureOffset, typeof(byte), LockFlag.None, LockSize); FileInfo fi = new FileInfo(m_sFileName); Writer = new BinaryWriter(File.OpenWrite(m_sFileName)); // Write the data into the wav file"); Writer.BaseStream.Position = (long)(fi.Length); //Writer.Seek(0, SeekOrigin.End); Writer.Write(CaptureData, 0, CaptureData.Length); Writer.Close(); // Writer = null; // Update the number of samples, in bytes, of the file so far. //SampleCount+= datalength; SampleCount += (long)CaptureData.Length; // Move the capture offset along NextCaptureOffset += CaptureData.Length; NextCaptureOffset %= m_iCaptureBufferSize; // Circular buffer }
/* * Send synchronously sends data captured from microphone across the network on port 1550. */ private void UDP_Send() { try { //The following lines get audio from microphone and then send them //across network. captureBuffer = new CaptureBuffer(captureBufferDescription, capture); UDP_CreateNotifyPositions(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); bStop = false; while (!bStop) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; //TODO: Fix this ugly way of initializing differently. //Choose the vocoder. And then send the data to other party at port 1550. byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString(), 6068); } } catch (Exception ex) { MessageBox.Show(ex.Message, "VoiceChat-Send ()", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { captureBuffer.Stop(); //Increment flag by one. nUdpClientFlag += 1; //When flag is two then it means we have got out of loops in Send and Receive. while (nUdpClientFlag != 2) { } //Clear the flag. nUdpClientFlag = 0; //Close the socket. udpClient.Close(); } }
/* * Send synchronously sends data captured from microphone across the network on port 1550. */ private void Send() { try { //The following lines get audio from microphone and then send them //across network. captureBuffer = new CaptureBuffer(captureBufferDescription, capture); CreateNotifyPositions(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); bStop = false; while (!bStop) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; byte[] dataToWrite = memStream.GetBuffer(); udpClient.Send(dataToWrite, dataToWrite.Length, "169.254.133.4", 1550); } } catch (Exception ex) { MessageBox.Show(ex.Message, "VoiceChat-Send ()", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { captureBuffer.Stop(); //Increment flag by one. nUdpClientFlag += 1; //When flag is two then it means we have got out of loops in Send and Receive. while (nUdpClientFlag != 2) { } //Clear the flag. nUdpClientFlag = 0; //Close the socket. udpClient.Close(); } }
void RecordCapturedData() { //----------------------------------------------------------------------------- // Name: RecordCapturedData() // Desc: Copies data from the capture buffer to the output buffer //----------------------------------------------------------------------------- byte[] captureData = null; int readPos; int capturePos; int lockSize; try { buffer.GetCurrentPosition(out capturePos, out readPos); lockSize = readPos - nextCaptureOffset; if (lockSize < 0) { lockSize += captureBufferSize; } // Block align lock size so that we are always write on a boundary lockSize -= (lockSize % notifySize); if (0 == lockSize) { return; } // Read the capture buffer. captureData = (byte[])buffer.Read(nextCaptureOffset, typeof(byte), LockFlag.None, lockSize); OnBufferData(this, new DirectSoundBufferDataEventArgs(captureData)); if (writer != null) { // Write the data into the wav file writer.Write(captureData, 0, captureData.Length); } // Update the number of samples, in bytes, of the file so far. sampleCount += captureData.Length; // Move the capture offset along nextCaptureOffset += captureData.Length; nextCaptureOffset %= captureBufferSize; // Circular buffer } catch (Exception) { } finally { captureData = null; } }
private void CopyRecordedData() { // This copys the recorded data out of the capture buffer // and in to the wave file verbatam. The data is stored in // the capture buffer in the correct format and the wave file // header was previously written in the CreateTheRiff method int readCursor; int captureCursor; // Loads the captureCursor and readCursor with the buffer positions _recordBuffer.GetCurrentPosition(out captureCursor, out readCursor); // boundry used to check that we have located a valid boundry to // write from int boundry; boundry = readCursor - _nextRecordingPosition; if (boundry < 0) { boundry = boundry + _recordBufferSize; } // Align the block so that we will write on a boundry boundry = boundry - (boundry % _notificationAt); if (0 == boundry) { return; } // Set a temporary byte buffer to store the _recordBuffer data byte[] captured = null; // Copy the data out of the capture buffer captured = (byte[])_recordBuffer.Read(_nextRecordingPosition, typeof(byte), LockFlag.None, boundry); // Write out the data to the file previously setup _binaryWriter.Write(captured, 0, captured.Length); // Increase the running total of sample bytes (used when // finalising the file to update the length ) _sampleBytes = _sampleBytes + captured.Length; // Increase the capture buffer offset to the next position _nextRecordingPosition = _nextRecordingPosition + captured.Length; // Take in to account our circular buffer _nextRecordingPosition = _nextRecordingPosition % _recordBufferSize; }
/// <summary> /// 常時録音処理を行う。 /// </summary> private void RecordWorker() { short[] buffer = new short[DataBuffer.PacketSize / sizeof(short)]; while (isActive) { try { // キャプチャバッファが埋まるまで待機 notificationEvent.WaitOne(Timeout.Infinite, true); // キャプチャサイズを算出 int capturePosition, readPosition; applicationBuffer.GetCurrentPosition(out capturePosition, out readPosition); int lockSize = readPosition - nextCaptureOffset; if (lockSize < 0) { lockSize += captureBufferSize; } lockSize -= lockSize % notifySize; if (lockSize == 0) { continue; } // キャプチャデータ取得 byte[] captureData = (byte[])applicationBuffer.Read( nextCaptureOffset, typeof(byte), LockFlag.None, lockSize); // パケットに切り分けて処理 for (int i = 0; i < captureData.Length / DataBuffer.PacketSize; i++) { System.Buffer.BlockCopy(captureData, DataBuffer.PacketSize * i, buffer, 0, DataBuffer.PacketSize); dataBuffer.AddData(buffer, DetectTalking(buffer), DateTime.Now.Ticks); } // 次回のオフセットを計算 nextCaptureOffset += captureData.Length; if (nextCaptureOffset >= captureBufferSize) { nextCaptureOffset -= captureBufferSize; } } catch (Exception e) { SoundControl.WriteErrorLog(e.ToString()); } } }
/* * Send synchronously sends data captured from microphone across the network on port 1550. */ private void Send() { try { udpAudioSending = new UdpClient(); //The following lines get audio from microphone and then send them //across network. captureBuffer = new CaptureBuffer(captureBufferDescription, capture); CreateNotifyPositions(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); audioSend = true; while (true) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; byte[] dataToWrite = memStream.GetBuffer(); udpAudioSending.Send(dataToWrite, dataToWrite.Length, serverIPAddress, 1550); } } catch (Exception ex) { if (captureBuffer.Capturing) { captureBuffer.Stop(); } Send(); //MessageBox.Show(ex.Message, "VoiceChat-Send ()", MessageBoxButtons.OK, MessageBoxIcon.Error); //return; } }
//The real transfer of data events, in fact, the data is transferred to the WAV file. private void RecordCapturedData() { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset;//This size is the size we can safely read if (locksize == 0) { return; } if (locksize < 0) { //Because we are using the buffer for the loop, //so there is a case of negative: //when the text to read the pointer back to the first notification point, //and Ibuffeoffset is still the last notification locksize += iBufferSize; } if (locksize % 2 == 1) { locksize -= 1; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize); for (int i = 0; i < locksize; i += 2) { int temp = ((capturedata[i + 1] << 8) | (capturedata[i])) << 48 >> 48; if (temp < minVoice && temp > (0 - minVoice)) { temp = 0; } float Ftemp = ((float)temp) / 65536; try { Monitor.Enter(queue); queue.Enqueue(Ftemp); Monitor.Exit(queue); } catch (Exception ex) { ; } } iSampleSize += capturedata.Length; iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize;//Modulo is because the buffer is looped. }
//真正转移数据的事件,其实就是把数据传送到网络上去。 private void RecordCapturedData(RadioTCPClient Client) { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小 if (locksize == 0) { return; } if (locksize < 0) {//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 locksize += iBufferSize; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize); //capturedata = g729.Encode(capturedata);//语音编码 try { if (Client.NetWork.Connected) { count++; Client.NetWork.GetStream().Write(capturedata, 0, capturedata.Length); if (count >= 4) { count = 0; //Client.NetWork.GetStream().Write(empty, 0, empty.Length/2); } } } catch { //throw new Exception(); } try { iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。 } catch { } }
//真正转移数据的事件,其实就是把数据传送到网络上去。 private void RecordCapturedData() { byte[] capturedata = null; int readpos = 0, capturepos = 0, locksize = 0; capturebuffer.GetCurrentPosition(out capturepos, out readpos); locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小 if (locksize == 0) { return; } if (locksize < 0) {//因为我们是循环的使用缓冲区,所以有一种情况下为负:当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处 locksize += iBufferSize; } capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize); mWriter.Write(capturedata, 0, capturedata.Length);//写入到文件 iSampleSize += capturedata.Length; iBufferOffset += capturedata.Length; iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。 }
private void Process() { //lock (this.thread) while (true) { // Wait for the buffer to fill up (no timeout) WaitHandle.WaitAny(this.fullEvent, -1, false); // Capture audio data var data = new short[numberOfSamples * 2]; // Stereo captureBuffer.Read(data, captureBuffer.CurrentRealPosition, LockFlags.FromWriteCursor); onProcessAudio(data); /*int num = captureBuffer.CurrentCapturePosition - captureBuffer.CurrentRealPosition; * * if (num > 0) * { * onProcessAudio(data, num); * }*/ } }
/// <summary> /// Copies data from the capture buffer to the output buffer /// </summary> private void RecordCapturedData(bool flush) { byte[] CaptureData = null; int ReadPos; int CapturePos; int LockSize; applicationBuffer.GetCurrentPosition(out CapturePos, out ReadPos); LockSize = ReadPos - nextCaptureOffset; if (LockSize < 0) { LockSize += captureBufferSize; } // Block align lock size so that we are always write on a boundary LockSize -= (LockSize % notifySize); if (0 == LockSize) { return; } // Read the capture buffer. CaptureData = (byte[])applicationBuffer.Read(nextCaptureOffset, typeof(byte), LockFlag.None, LockSize); filters.Input.Write(CaptureData, 0, CaptureData.Length); // Update the number of samples, in bytes, of the file so far. sampleByteCount += CaptureData.Length; // Move the capture offset along nextCaptureOffset += CaptureData.Length; nextCaptureOffset %= captureBufferSize; // Circular buffer if (flush) { filters.Input.Flush(); } }
void RecordCapturedData() { //----------------------------------------------------------------------------- // Name: RecordCapturedData() // Desc: Copies data from the capture buffer to the output buffer //----------------------------------------------------------------------------- byte[] CaptureData = null; int ReadPos; int CapturePos; int LockSize; applicationBuffer.GetCurrentPosition(out CapturePos, out ReadPos); LockSize = ReadPos - NextCaptureOffset; if (LockSize < 0) { LockSize += CaptureBufferSize; } // Block align lock size so that we are always write on a boundary LockSize -= (LockSize % NotifySize); if (0 == LockSize) { return; } // Read the capture buffer. CaptureData = (byte[])applicationBuffer.Read(NextCaptureOffset, typeof(byte), LockFlag.None, LockSize); // Write the data into the wav file Writer.Write(CaptureData, 0, CaptureData.Length); // Update the number of samples, in bytes, of the file so far. SampleCount += CaptureData.Length; // Move the capture offset along NextCaptureOffset += CaptureData.Length; NextCaptureOffset %= CaptureBufferSize; // Circular buffer }
private void SendAudio() { try { // Capturamos el audio y lo enviamos por la red int halfbuffer = buffersize / 2; captureBuffer = new CaptureBuffer(captureBuffDesc, capture); CreateNotifyPositions(); captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfbuffer); while (!button7.Enabled) { // Esperamos un evento autoResetEvent.WaitOne(); // Ponemos el puntero al principio del MS memStream.Seek(0, SeekOrigin.Begin); // Leemos el Buffer de Captura y lo guardamos en la primera mitad captureBuffer.Read(offset, memStream, halfbuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfbuffer; // Preparamos el stream de datos //byte[] data = memStream.GetBuffer(); // Sin compresión byte[] data = ALawEncoder.ALawEncode(memStream.GetBuffer()); // Enviamos via RTP al usuario. audio.sendALaw(data); num_audio++; } } catch (Exception ex) { MessageBox.Show("Error sending audio."); } }
/// <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(); } }
/* * Send synchronously sends data captured from microphone across the network on port 1550. */ private void Send() { try { //The following lines get audio from microphone and then send them //across network. captureBuffer = new CaptureBuffer(captureBufferDescription, capture); CreateNotifyPositions(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); bStop = false; while (!bStop) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; //TODO: Fix this ugly way of initializing differently. //Choose the vocoder. And then send the data to other party at port 1550. if (vocoder == Vocoder.ALaw) { byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString (), 1550); } else if (vocoder == Vocoder.uLaw) { byte[] dataToWrite = MuLawEncoder.MuLawEncode(memStream.GetBuffer()); udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString(), 1550); } else { byte[] dataToWrite = memStream.GetBuffer(); udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString(), 1550); } } } catch (Exception ex) { MessageBox.Show(ex.Message, "VoiceChat-Send ()", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { captureBuffer.Stop(); //Increment flag by one. nUdpClientFlag += 1; //When flag is two then it means we have got out of loops in Send and Receive. while (nUdpClientFlag != 2) { } //Clear the flag. nUdpClientFlag = 0; //Close the socket. udpClient.Close(); } }
private void StartRecordAndSend() { try { Capture capture = null; CaptureDevicesCollection captureDeviceCollection = new CaptureDevicesCollection(); try { capture = new Capture(captureDeviceCollection[ConfSingleton.Instance.CaptureDeviceIndex].DriverGuid); } catch { capture = new Capture(captureDeviceCollection[0].DriverGuid); } captureBuffer = new CaptureBuffer(captureBufferDescription, capture); SetBufferEvents(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); bStop = false; while (!bStop) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; rtpSender.Send(ConfSingleton.Instance.Compression ? ALawEncoder.ALawEncode(memStream.GetBuffer()) : memStream.GetBuffer()); } } catch (ThreadAbortException) { /* This is OK. It's raised when the record thread is stopped. */ } /* Catch DirectSound's uninformative exceptions and attempt to expand on them... */ catch (Exception ex) { if (OnCaptureError != null) { AudioCaptureException captureException = new AudioCaptureException("There was a problem in the audio capture process. This is often due to no working capture device being available.", ex); OnCaptureError(this, new AudioCaptureExceptionEventArgs() { Exception = captureException }); } } finally { try { if (captureBuffer != null) captureBuffer.Stop(); bStop = true; } catch { } } }
/* * Send synchronously sends data captured from microphone across the network on port 1550. */ private void Send() { try { //The following lines get audio from microphone and then send them //across network. captureBuffer = new CaptureBuffer(captureBufferDescription, capture); CreateNotifyPositions(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); bStop = false; while (!bStop) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; //TODO: Fix this ugly way of initializing differently. //Choose the vocoder. And then send the data to other party at port 1550. //循环聊天室里面的用户发送语音数据 List<ChatUser> chatUserlist = LoginRoler.chatUserlist; if (chatUserlist!=null && chatUserlist.Count>0) { //chatroomusers for (int a = 0; a < chatUserlist.Count; a++) { //Console.WriteLine("ip=" + chatroomusers.Items[a].Text.ToString() + "进入聊天"); string ip = (((ChatUser)chatUserlist[a]).ChatIp).ToString(); if (ip.Equals(LoginRoler.ip)) continue; //Console.WriteLine("发送音频数据到:" + ip); if (vocoder == Vocoder.ALaw) { byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); //udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString(), 1550); udpClient.Send(dataToWrite, dataToWrite.Length, ip, 1550); } else if (vocoder == Vocoder.uLaw) { byte[] dataToWrite = MuLawEncoder.MuLawEncode(memStream.GetBuffer()); //udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString(), 1550); udpClient.Send(dataToWrite, dataToWrite.Length, ip, 1550); //udpClient.Send(dataToWrite, dataToWrite.Length, "192.168.0.104", 1550); } else { byte[] dataToWrite = memStream.GetBuffer(); //udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIP.Address.ToString(), 1550); udpClient.Send(dataToWrite, dataToWrite.Length, ip, 1550); } } } } } catch (Exception ex) { MessageBox.Show(ex.Message, "VoiceChat-Send ()", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { captureBuffer.Stop(); //Increment flag by one. nUdpClientFlag += 1; //When flag is two then it means we have got out of loops in Send and Receive. while (nUdpClientFlag != 2) { } //Clear the flag. nUdpClientFlag = 0; //Close the socket. //udpClient.Close(); } }
/// <summary> /// Records sound data from the given audio input. /// </summary> /// /// <remarks> /// Note that this method will block forever. Threading will be required /// to get the data back. /// </remarks> /// /// <param name="capture">The input to record from.</param> /// <returns>The audio data recorded from the input.</returns> public void Record(Capture capture) { if (Recording) { throw new Exception("Already recording."); } WaveFormat format = (WaveFormat) GetAmibiguousType(typeof(WaveFormat)); format.SamplesPerSecond = 96000; format.BitsPerSample = 16; format.Channels = 1; format.FormatTag = WaveFormatTag.Pcm; format.BlockAlign = (Int16) (format.Channels * (format.BitsPerSample / 8)); format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign; int notifySize = Math.Max(4096, format.AverageBytesPerSecond / 16); notifySize -= notifySize % format.BlockAlign; // This is a fairly arbitrary choice. int inputSize = notifySize * 16; // Output is half of input, as every two bytes is a piece of sound data. int outputSize = inputSize / 2; CaptureBufferDescription description = (CaptureBufferDescription) GetAmibiguousType(typeof(CaptureBufferDescription)); description.Format = format; description.BufferBytes = inputSize; CaptureBuffer buffer; try { buffer = new CaptureBuffer(description, capture); } catch { throw new IOException( "An error occurred attempting to set up a read buffer."); } AutoResetEvent reset = new AutoResetEvent(false); Notify notify = new Notify(buffer); BufferPositionNotify bpn1 = (BufferPositionNotify) GetAmibiguousType(typeof(BufferPositionNotify)); bpn1.Offset = buffer.Caps.BufferBytes / 2 - 1; bpn1.EventNotifyHandle = reset.SafeWaitHandle.DangerousGetHandle(); BufferPositionNotify bpn2 = (BufferPositionNotify) GetAmibiguousType(typeof(BufferPositionNotify)); bpn2.Offset = buffer.Caps.BufferBytes - 1; bpn2.EventNotifyHandle = reset.SafeWaitHandle.DangerousGetHandle(); notify.SetNotificationPositions(new BufferPositionNotify[] { bpn1, bpn2 }); int offset = 0; Data = new List<Int16>(); Recording = true; new Thread((ThreadStart) delegate { buffer.Start(true); while (Recording) { // Let the buffer fill up from the last read. reset.WaitOne(); byte[] read; try { read = (byte[]) buffer.Read(offset, typeof(byte), LockFlag.None, outputSize); } catch { throw new IOException( "An error occurred attempting to read the input data."); } offset = (offset + outputSize) % inputSize; bool written = false; Int16 old = 0; foreach (byte b in read) { if (!written) { old = (Int16) b; } else { old = (Int16) (old | (((Int16) (b << 8)))); Data.Add(old); } written = !written; } } buffer.Stop(); }).Start(); }
/* * Send synchronously sends data captured from microphone across the network on port 1550. */ private void Send() { try { IsThreadSendEnd = false; //The following lines get audio from microphone and then send them //across network. int users_count = 0; captureBuffer = new CaptureBuffer(captureBufferDescription, capture); CreateNotifyPositions(); int halfBuffer = bufferSize / 2; captureBuffer.Start(true); bool readFirstBufferPart = true; int offset = 0; MemoryStream memStream = new MemoryStream(halfBuffer); bStop = false; LogAppend("Sending Started"); while (!bStop) { lock (otherPartyIPs) { users_count = otherPartyIPs.Count; if (users_count > 0) { autoResetEvent.WaitOne(); memStream.Seek(0, SeekOrigin.Begin); captureBuffer.Read(offset, memStream, halfBuffer, LockFlag.None); readFirstBufferPart = !readFirstBufferPart; offset = readFirstBufferPart ? 0 : halfBuffer; //TODO: Fix this ugly way of initializing differently. //Choose the vocoder. And then send the data to other party at port 1550. //if (vocoder == Vocoder.ALaw) //{ //byte[] dataToWrite = MuLawEncoder.MuLawEncode(memStream.GetBuffer()); //MULAW //byte[] dataToWrite = ALawEncoder.ALawEncode(memStream.GetBuffer()); //ALAW (RECOMENdADO) byte[] dataToWrite = memStream.GetBuffer(); //NORMAL if (bStop) return; for (int i = 0; i < users_count; i++) udpClient.Send(dataToWrite, dataToWrite.Length, otherPartyIPs[i].Address.ToString(), 1550); } } } IsThreadSendEnd = true; LogAppend("Sending Ended"); } catch (Exception ex) { // MessageBox.Show(ex.Message, "VoiceChat-Send ()", MessageBoxButtons.OK, MessageBoxIcon.Error); LogAppend("VoiceChat-Send >> " + ex.Message); } finally { captureBuffer.Stop(); //Increment flag by one. nUdpClientFlag += 1; //When flag is two then it means we have got out of loops in Send and Receive. while (nUdpClientFlag != 2) { } //Clear the flag. nUdpClientFlag = 0; //Close the socket. udpClient.Close(); } }
/// <summary> /// Records sound data from the given audio input. /// </summary> /// /// <remarks> /// Note that this method will block forever. Threading will be required /// to get the data back. /// </remarks> /// /// <param name="capture">The input to record from.</param> /// <returns>The audio data recorded from the input.</returns> public bool Record(Capture cap) { if(recording){ return false; } // string captureDescriptor – string for eg “Mic”, “Input” // Control owner – maybe Window or Form would do for this – was Native.GetDesktopWindow() // if windowless application use desktop window as message broker // Returns true for setup done and thread started, false for problem // Choose a Wave format, calculating BlockAlign and AverageBytesPerSecond ConstructorInfo nom = typeof(WaveFormat).GetConstructor(Type.EmptyTypes); format = (WaveFormat)nom.Invoke(null); format.SamplesPerSecond = 96000; format.BitsPerSample = 16; format.Channels = 1; format.FormatTag = WaveFormatTag.Pcm; SData = new List<Int16>(); // Both of these are calculate for All channels // BlockAlign = BytesPerSampleAllChannels, AverageBytesPerSecond = BytesPerSecondAllChannels format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8)); format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign; // Set the size of input and output buffers // Multiplier of both delay and minimum buffer size in units of 1/16th secs, int NUM_BUFFERS = 8; // Sets _dwNotifySize to enough bytes for 1/16th of a second, all channels // Note that this was 1/8th (ie line ended ‘/ 8);’), and output buffer size = capture size/2 // But this was changed to allow output buffer size to be a multiple of BlockAlign int _dwNotifySize = Math.Max(4096, format.AverageBytesPerSecond / (8 * 2)); // rounds _dwNotifySize to a multiple of BlockAlign (BytesPerSampleAllChannel) _dwNotifySize -= _dwNotifySize % format.BlockAlign; // Capture buffer is looped – when the end is reached, it starts from the beginning again. // Capturing one should be twice as large as output – so that when completed capture // is being read to output buffer there is still room to for the buffer to keep filling // without overwriting the output. I think. int _dwCaptureBufferSize = NUM_BUFFERS * _dwNotifySize * 2; int _dwOutputBufferSize = NUM_BUFFERS * _dwNotifySize; // Check a matching capture device was found if (cap == null) return false; // no matching sound card/capture device { // Make the description and create a CaptureBuffer accordingly ConstructorInfo capnom = typeof(CaptureBufferDescription).GetConstructor(Type.EmptyTypes); var capDesc = (CaptureBufferDescription)capnom.Invoke(null); capDesc.Format = format; capDesc.BufferBytes = _dwCaptureBufferSize; var _dwCapBuffer = new CaptureBuffer(capDesc, cap); // Create two output buffers – this seems to avoid the buffer being locked and written // to while it's still playing, helping to avoid a sound glitch on my machine. var _dwDevBuffers = new SecondaryBuffer[2]; // Set autoResetEvent to be fired when it's filled and subscribe to buffer notifications var _resetEvent = new AutoResetEvent(false); var _notify = new Notify(_dwCapBuffer); // Half&half – one notification halfway through the output buffer, one at the end ConstructorInfo buffnom = typeof(BufferPositionNotify).GetConstructor(Type.EmptyTypes); var bpn1 = (BufferPositionNotify)buffnom.Invoke(null); bpn1.Offset = _dwCapBuffer.Caps.BufferBytes / 2 - 1; bpn1.EventNotifyHandle = _resetEvent.SafeWaitHandle.DangerousGetHandle(); var bpn2 = (BufferPositionNotify)buffnom.Invoke(null); bpn2.Offset = _dwCapBuffer.Caps.BufferBytes - 1; bpn2.EventNotifyHandle = _resetEvent.SafeWaitHandle.DangerousGetHandle(); _notify.SetNotificationPositions(new BufferPositionNotify[] { bpn1, bpn2 }); recording = true; // ready to capture sound // Fire worker thread to take care of messages // Note that on a uniprocessor, the new thread may not get any processor time // until the main thread is preempted or yields, eg by ending button click event or // calling Thread.Sleep(0) // botch – not sure if these are thread safe for multiple threads int offset = 0; int devbuffer = 0; // Make a new thread – as countained in the { } Thread _dwCaptureThread = new Thread((ThreadStart)delegate { _dwCapBuffer.Start(true); // start capture // IsReady – This should be true while you wish to capture and then output the sound. while (recording) { _resetEvent.WaitOne(); // blocks thread until _dwCapBuffer is half/totally full // Read the capture buffer into an array, and output it to the next DevBuffer byte[] read = (byte[])_dwCapBuffer.Read(offset, typeof(byte), LockFlag.None, _dwOutputBufferSize); for (int i = 0; i < read.Length; i++) { SData.Add(Int16.Parse(read[i].ToString())); } // _dwDevBuffers[devbuffer].Write(0, read, LockFlag.EntireBuffer); // Update offset offset = (offset + _dwOutputBufferSize) % _dwCaptureBufferSize; devbuffer = 1 - devbuffer; // toggle between 0 and 1 } _dwCapBuffer.Stop(); // stop capture }); _dwCaptureThread.Start(); // start the new Thread return true; } }