一、录制音频
Windows Phone 提供的访问麦克风的类为 Microsoft.Xna.Framework.Audio.Microphone ,该类属于 XNA Framework , 若要在 Silverlight 中访问 Windows Phone 麦克风,同样需要使用此类。所以需要添加引用 Microsoft.Xna.Framework。
1.声明局部变量,获取麦克风单例。
2.由于在XNA中每33fp就会更新画面一次,但在Silverlight Application并没有这样的机制,为了确保录音的功能持续的更新状态与进行撷取动作,因此,需要透过指定一个定期执行 FrameworkDispatcher.Update() 的事件。
//设置定时器
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(33);
timer.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
timer.Start();
3.设置录音相关信息,启动录音。
//设置1秒的缓存区,没获取1秒音频就会调用一次BufferReady事件
microphone.BufferDuration = TimeSpan.FromMilliseconds(1000);
//分配1秒音频所需要的缓存区
buf = new byte[microphone.GetSampleSizeInBytes(microphone.BufferDuration)];
audioStream = new MemoryStream();
//BufferReady事件
microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
//启动录音
microphone.Start();
4.实现 BufferReady 事件处理程序。该处理程序将麦克风的数据复制到缓冲区中并将该缓冲区写入一个流。
void microphone_BufferReady(object sender, EventArgs e)
{
//将麦克风的数据复制到缓冲区中
microphone.GetData(buf);
//将该缓冲区写入一个流
audioStream.Write(buf, 0, buf.Length);
}
5.停止录音
//停止录音
microphone.Stop();
microphone.BufferReady -= new EventHandler<EventArgs>(microphone_BufferReady);
audioStream.Flush();
//将数据流转换为byte,recording中即为音频数据
byte[] recording = audioStream.ToArray();
audioStream.Dispose();
6.播放录音
//播放录音
SoundEffect sound = new SoundEffect(audioStream.ToArray(), microphone.SampleRate, AudioChannels.Mono);
sound.Play();
通过录制的byte字节流数据,可以通过SoundEffect类播放,相当容易。但是如果想通过其他方式播放或在要到处音频数据,则需要将音频数据以文件的方式保存到独立存储中。
保存音频
录制好的音频要保存为文件,需要做相关格式转换。一般录音的格式为.WAV,下面就介绍如何将录音保存为WAV文件。
1.在录制音频开始之前,首先要向音频流存储区audioStream中写入WAV文件头信息。即在调用microphone.Start()之前调用WriteWavHeader(audioStream, microphone.SampleRate),其中WriteWavHeader函数实现如下。
WriteWavHeader
1 /// <summary>
2 /// 写wav文件头信息
3 /// </summary>
4 /// <param name="stream"></param>
5 /// <param name="sampleRate"></param>
6 public void WriteWavHeader(Stream stream, int sampleRate)
7 {
8 const int bitsPerSample = 16;
9 const int bytesPerSample = bitsPerSample / 8;
10 var encoding = System.Text.Encoding.UTF8;
11
12 // ChunkID Contains the letters "RIFF" in ASCII form (0x52494646 big-endian form).
13 stream.Write(encoding.GetBytes("RIFF"), 0, 4);
14
15 // NOTE this will be filled in later
16 stream.Write(BitConverter.GetBytes(0), 0, 4);
17
18 // Format Contains the letters "WAVE"(0x57415645 big-endian form).
19 stream.Write(encoding.GetBytes("WAVE"), 0, 4);
20
21 // Subchunk1ID Contains the letters "fmt " (0x666d7420 big-endian form).
22 stream.Write(encoding.GetBytes("fmt "), 0, 4);
23
24 // Subchunk1Size 16 for PCM. This is the size of therest of the Subchunk which follows this number.
25 stream.Write(BitConverter.GetBytes(16), 0, 4);
26
27 // AudioFormat PCM = 1 (i.e. Linear quantization) Values other than 1 indicate some form of compression.
28 stream.Write(BitConverter.GetBytes((short)1), 0, 2);
29
30 // NumChannels Mono = 1, Stereo = 2, etc.
31 stream.Write(BitConverter.GetBytes((short)1), 0, 2);
32
33 // SampleRate 8000, 44100, etc.
34 stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
35
36 // ByteRate = SampleRate * NumChannels * BitsPerSample/8
37 stream.Write(BitConverter.GetBytes(sampleRate * bytesPerSample), 0, 4);
38
39 // BlockAlign NumChannels * BitsPerSample/8 The number of bytes for one sample including all channels.
40 stream.Write(BitConverter.GetBytes((short)(bytesPerSample)), 0, 2);
41
42 // BitsPerSample 8 bits = 8, 16 bits = 16, etc.
43 stream.Write(BitConverter.GetBytes((short)(bitsPerSample)), 0, 2);
44
45 // Subchunk2ID Contains the letters "data" (0x64617461 big-endian form).
46 stream.Write(encoding.GetBytes("data"), 0, 4);
47
48 // NOTE to be filled in later
49 stream.Write(BitConverter.GetBytes(0), 0, 4);
50 }
2.在录制音频结束的时候,才能确认录音文件大小的长度,此时需要修改WAV文件头部分信息。即在调用microphone.Stop()之后调用UpdateWavHeader(audioStream),其中
UpdateWavHeader函数实现如下。
UpdateWavHeader
1 /// <summary>
2 /// 更新wav文件头信息
3 /// </summary>
4 /// <param name="stream"></param>
5 public void UpdateWavHeader(Stream stream)
6 {
7 if (!stream.CanSeek) throw new Exception("Can't seek stream to update wav header");
8
9 var oldPos = stream.Position;
10
11 // ChunkSize 36 + SubChunk2Size
12 stream.Seek(4, SeekOrigin.Begin);
13 stream.Write(BitConverter.GetBytes((int)stream.Length - 8), 0, 4);
14
15 // Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data.
16 stream.Seek(40, SeekOrigin.Begin);
17 stream.Write(BitConverter.GetBytes((int)stream.Length - 44), 0, 4);
18
19 stream.Seek(oldPos, SeekOrigin.Begin);
20 }
3.通过以上处理后的audioStream流已经是格式化后的WAV流。接下来只需要将audioStream流写入独立存储中(yu.wav)。
//将数据流转换为byte,recording中即为音频数据
byte[] recording = audioStream.ToArray();
//独立存储文件处理
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
try
{
//打开文件
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("yu.wav", FileMode.Create, myIsolatedStorage))
{
fileStream.Write(recording, 0, recording.Length);
}
}
catch (Exception ex)
{
//读取失败
}
}