Silverlight实用窍门系列:41.Silverlight中调用麦克风模拟录音机设备,存储为WAV音频


在Silverlight 4中支持了麦克风设置的调用,在本节中我们将调用麦克风设备,然后进行录音,并且将录制的声音存取为Wav音频文件。 第一步、首先我们从AudioSink类派生一个音频接收器类:WavAudioSink。其代码如下所示: public class WavAudioSink:AudioSink { //设置需


  在Silverlight 4中支持了麦克风设置的调用,在本节中我们将调用麦克风设备,然后进行录音,并且将录制的声音存取为Wav音频文件。

  第一步、首先我们从AudioSink类派生一个音频接收器类:WavAudioSink。其代码如下所示:


public  
  class WavAudioSink:AudioSink 
  
 { 
  
      
  // 设置需要记录的内存流 
  
      
  private MemoryStream _stream; 
  
      
  // 设置当前的音频格式 
  
      
  private AudioFormat _format; 
  

      
  public Stream BackingStream 
  
     { 
  
          
  get {  
  return _stream; } 
  
     } 
  

      
  public AudioFormat CurrentFormat 
  
     { 
  
          
  get {  
  return _format; } 
  
     } 
  

      
  protected  
  override  
  void OnCaptureStarted() 
  
     { 
  
         _stream =  
  new MemoryStream(1024); 
  
     } 
  

      
  protected  
  override  
  void OnCaptureStopped() 
  
     { 
  
     } 
  

      
  protected  
  override  
  void OnFormatChange(AudioFormat audioFormat) 
  
     { 
  
          
  if (audioFormat.WaveFormat != WaveFormatType.Pcm) 
  
              
  throw  
  new InvalidOperationException( 
  "WavAudioSink只支持PCM音频格式"); 
  

         _format = audioFormat; 
  
     } 
  

      
  protected  
  override  
  void OnSamples( 
  long sampleTime,  
  long sampleDuration, 
  
          
  byte[] sampleData) 
  
     { 
  
          
  // 新的音频数据到达,将它们写入流 
  
         _stream.Write(sampleData, 0, sampleData.Length); 
  
     } 
  
 }



 

  第二步、然后我们将编写一个保存音频的函数类,以保存读取到的音频数据:

public  
  class SaveWAVHelper 
  
   { 
  
      
  public  
  static  
  void SavePcmToWav(Stream rawData, Stream output, AudioFormat audioFormat) 
  
     { 
  
          
  if (audioFormat.WaveFormat != WaveFormatType.Pcm) 
  
              
  throw  
  new ArgumentException( 
  "Only PCM coding is supported."); 
  

         BinaryWriter bwOutput =  
  new BinaryWriter(output); 
  

          
  // -- RIFF 块 
  
         bwOutput.Write( 
  "RIFF".ToCharArray()); 
  
          
  // 包的总长度 
  
          
  // 计算的数据长度加上数据头的长度没有数据 
  
          
  // 写数据(44 - 4 ("RIFF") - 4 (当前数据)) 
  
         bwOutput.Write(( 
  uint)(rawData.Length + 36)); 
  
         bwOutput.Write( 
  "WAVE".ToCharArray()); 
  

          
  // -- FORMAT 块 
  
         bwOutput.Write( 
  "fmt ".ToCharArray()); 
  
          
  // FORMAT 块的长度 (Binary, 总是 0x10) 
  
         bwOutput.Write(( 
  uint)0x10); 
  
          
  // 总是 0x01 
  
         bwOutput.Write(( 
  ushort)0x01); 
  
          
  // 通道数( 0x01=单声道, 0x02=立体声) 
  
         bwOutput.Write(( 
  ushort)audioFormat.Channels); 
  
          
  // 采样率 (Binary,  Hz为单位) 
  
         bwOutput.Write(( 
  uint)audioFormat.SamplesPerSecond); 
  
          
  // 字节每秒 
  
         bwOutput.Write(( 
  uint)(audioFormat.BitsPerSample * audioFormat.SamplesPerSecond *  
  
             audioFormat.Channels / 8)); 
  
          
  // 每个样品字节: 1=8 bit 单声道, 2=8 bit 立体声 or 16 bit 单声道, 4=16 bit 立体声 
  
         bwOutput.Write(( 
  ushort)(audioFormat.BitsPerSample * audioFormat.Channels / 8)); 
  
          
  // 每个样品字节 
  
         bwOutput.Write(( 
  ushort)audioFormat.BitsPerSample); 
  

          
  // -- DATA 块 
  
         bwOutput.Write( 
  "data".ToCharArray()); 
  
          
  // DATA数据块的长度 
  
         bwOutput.Write(( 
  uint)rawData.Length); 
  
          
  // 原始PCM数据如下 
  
          
  // 复位rawData地位,记住它的原点位置 
  
          
  // 恢复底。 
  
          
  long originalRawDataStreamPosition = rawData.Position; 
  
         rawData.Seek(0, SeekOrigin.Begin); 
  
          
  //追加到输出流中的所有数据从rawData流 
  
          
  byte[] buffer =  
  new  
  byte[4096]; 
  
          
  int read;        
  
          
  // 循环读取字节数据 
  
          
  while ((read = rawData.Read(buffer, 0, 4096)) > 0) 
  
         { 
  
             bwOutput.Write(buffer, 0, read); 
  
         } 
  
          
  //开始写入数据 
  
         rawData.Seek(originalRawDataStreamPosition, SeekOrigin.Begin); 
  
   } 
  
 }



 

  第三步、然后再MainPage.xaml中我们添加三个按钮,分别是开始记录音频、停止录制音频、保存音频文件三个按钮。


Grid x:Name= 
  "LayoutRoot" 
   Background= 
  "White"> 
  
         < 
  Button 
  "开始录制" 
   Height= 
  "28" 
   HorizontalAlignment= 
  "Left" 
  
                 Margin= 
  "30,15,0,0" 
   Name= 
  "btnRecord" 
   VerticalAlignment= 
  "Top" 
  
                 Width= 
  "71" 
   Click= 
  "btnRecord_Click" 
   /> 
  
         < 
  Button 
  "停止录制" 
   Height= 
  "28" 
   HorizontalAlignment= 
  "Left" 
  
                 Margin= 
  "150,15,0,0" 
   Name= 
  "btnStopRecord" 
   VerticalAlignment= 
  "Top" 
  
                 Width= 
  "71" 
   Click= 
  "btnStopRecord_Click" 
   /> 
  
         < 
  Button 
  "保存音频" 
   Height= 
  "28" 
   HorizontalAlignment= 
  "Left" 
  
                 Margin= 
  "268,15,0,0" 
   Name= 
  "btnSaveWav" 
   VerticalAlignment= 
  "Top" 
  
                 Width= 
  "71" 
   Click= 
  "btnSaveWav_Click" 
   /> 
  
     < 
  /Grid>


 

  第四步、最后在MainPage.xaml.cs代码中我们进行录制、停止、保存音频的操作如下所示:

public partial  
  class MainPage : UserControl 
  
     { 
  
      
  public MainPage() 
  
     { 
  
         InitializeComponent(); 
  

         btnRecord.IsEnabled =  
  true; 
  
         btnStopRecord.IsEnabled =  
  false; 
  
         btnSaveWav.IsEnabled =  
  false; 
  
     } 
  

      
  //声明私有变量 
  
      
  private WavAudioSink _wavSink; 
  
      
  private CaptureSource _captureSource; 
  
      
  private SaveFileDialog _saveFileDialog =  
  new SaveFileDialog()  
  
         { Filter =  
  "Audio files (*.wav)|*.wav" }; 
  

      
  private  
  void btnRecord_Click( 
  object sender, RoutedEventArgs e) 
  
     { 
  

          
  //初始化_captureSource 
  
         var audioDevice = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice(); 
  
         _captureSource =  
  new CaptureSource() { AudioCaptureDevice = audioDevice }; 
  

          
  //有默认设置的设备且可以用来录制音频 
  
          
  if (CaptureDeviceConfiguration.AllowedDeviceAccess || 
  
             CaptureDeviceConfiguration.RequestDeviceAccess()) 
  
         { 
  
              
  //判断当前没有开始录制音频 
  
              
  if (_captureSource.State == CaptureState.Stopped) 
  
             { 
  
                  
  //初始化WavAudioSink 
  
                 _wavSink =  
  new WavAudioSink(); 
  
                 _wavSink.CaptureSource = _captureSource; 
  
                  
  //开始录制音频 
  
                 _captureSource.Start();      
  

             } 
  
         } 
  


         btnRecord.IsEnabled =  
  false; 
  
         btnStopRecord.IsEnabled =  
  true; 
  
         btnSaveWav.IsEnabled =  
  false; 
  
     } 
  

      
  private  
  void btnStopRecord_Click( 
  object sender, RoutedEventArgs e) 
  
     { 
  
          
  //如果当前状态为开始录制,则停止录制 
  
          
  if (_captureSource.State == CaptureState.Started) 
  
         { 
  
             _captureSource.Stop(); 
  
         } 
  


         btnRecord.IsEnabled =  
  false; 
  
         btnStopRecord.IsEnabled =  
  false; 
  
         btnSaveWav.IsEnabled =  
  true; 
  
     } 
  

      
  private  
  void btnSaveWav_Click( 
  object sender, RoutedEventArgs e) 
  
     { 
  
          
  if (_saveFileDialog.ShowDialog() ==  
  false) 
  
         { 
  
              
  return; 
  
         } 
  
          
  //保存Wav文件 
  
         Stream stream = _saveFileDialog.OpenFile(); 
  
         SaveWAVHelper.SavePcmToWav(_wavSink.BackingStream, stream, _wavSink.CurrentFormat); 
  

         stream.Close(); 
  

         MessageBox.Show( 
  "你的音频已经保存"); 
  


         btnRecord.IsEnabled =  
  true; 
  
         btnStopRecord.IsEnabled =  
  false; 
  
         btnSaveWav.IsEnabled =  
  false; 
  
     } 
  
 }



 

  通过以上步骤我们就可以开始调用麦克风录制音频文件了,本实例采用Silverlight 4.0+VS2010编写,如需源码请点击 SL4Audio.zip 下载。其效果图如下所示:

  

android 录音机监听麦克风被抢占停止录音 录音设备麦克风_数据