示例#1
0
 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;
 }
示例#2
0
        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());
        }
示例#3
0
        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.");
        }
示例#4
0
 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;
 }
示例#5
0
 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();
 }
示例#6
0
 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();
      }
 }
示例#7
0
        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();
                }
            }
        }
示例#8
0
        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();
            }
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        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);
        }
示例#12
0
 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();
      }
 }