Reputation: 1065
A part of the application I am developing allows user to record anything using a microphone. To record from the microphone, I used the code given in Microphone Code sample by Microsoft. I just made a few changes to the code to write a wav header to the stream so that I could store the recording as a wave file in isolated storage.
private void recordButton_Click(object sender, EventArgs e)
{
// Get audio data in 1/2 second chunks
microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
// Allocate memory to hold the audio data
buffer = new byte[microphone.GetSampleSizeInBytes(microphone.BufferDuration)];
// Set the stream back to zero in case there is already something in it
stream.SetLength(0);
//Write wav header
WriteWavHeader(microphone.SampleRate);
// Start recording
microphone.Start();
SetButtonStates(false, false, true,false);
UserHelp.Text = "record";
StatusImage.Source = microphoneImage;
StatusImage.Visibility = System.Windows.Visibility.Visible;
}
public void WriteWavHeader(int sampleRate)
{
const int bitsPerSample = 16;
const int bytesPerSample = bitsPerSample / 8;
var encoding = System.Text.Encoding.UTF8;
// ChunkID Contains the letters "RIFF" in ASCII form (0x52494646 big-endian form).
stream.Write(encoding.GetBytes("RIFF"), 0, 4);
// NOTE this will be filled in later
stream.Write(BitConverter.GetBytes(0), 0, 4);
// Format Contains the letters "WAVE"(0x57415645 big-endian form).
stream.Write(encoding.GetBytes("WAVE"), 0, 4);
// Subchunk1ID Contains the letters "fmt " (0x666d7420 big-endian form).
stream.Write(encoding.GetBytes("fmt "), 0, 4);
// Subchunk1Size 16 for PCM. This is the size of therest of the Subchunk which follows this number.
stream.Write(BitConverter.GetBytes(16), 0, 4);
// AudioFormat PCM = 1 (i.e. Linear quantization) Values other than 1 indicate some form of compression.
stream.Write(BitConverter.GetBytes((short)1), 0, 2);
// NumChannels Mono = 1, Stereo = 2, etc.
stream.Write(BitConverter.GetBytes((short)1), 0, 2);
// SampleRate 8000, 44100, etc.
stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
// ByteRate = SampleRate * NumChannels * BitsPerSample/8
stream.Write(BitConverter.GetBytes(sampleRate * bytesPerSample), 0, 4);
// BlockAlign NumChannels * BitsPerSample/8 The number of bytes for one sample including all channels.
stream.Write(BitConverter.GetBytes((short)(bytesPerSample)), 0, 2);
// BitsPerSample 8 bits = 8, 16 bits = 16, etc.
stream.Write(BitConverter.GetBytes((short)(bitsPerSample)), 0, 2);
// Subchunk2ID Contains the letters "data" (0x64617461 big-endian form).
stream.Write(encoding.GetBytes("data"), 0, 4);
// NOTE to be filled in later
stream.Write(BitConverter.GetBytes(0), 0, 4);
}
public void UpdateWavHeader()
{
//if (!stream.CanSeek) throw new Exception("Can't seek stream to update wav header");
var oldPos = stream.Position;
// ChunkSize 36 + SubChunk2Size
stream.Seek(4, SeekOrigin.Begin);
stream.Write(BitConverter.GetBytes((int)stream.Length - 8), 0, 4);
// Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data.
stream.Seek(40, SeekOrigin.Begin);
stream.Write(BitConverter.GetBytes((int)stream.Length - 44), 0, 4);
stream.Seek(oldPos, SeekOrigin.Begin);
}
private void stopButton_Click(object sender, EventArgs e)
{
if (microphone.State == MicrophoneState.Started)
{
// In RECORD mode, user clicked the
// stop button to end recording
microphone.Stop();
UpdateWavHeader();
}
else if (soundInstance.State == SoundState.Playing)
{
// In PLAY mode, user clicked the
// stop button to end playing back
soundInstance.Stop();
}
SetButtonStates(true, true, false,true);
UserHelp.Text = "ready";
StatusImage.Source = blankImage;
}
After this if the user choses to save the recording I save it in the isolated storage.
There are various pages in the application and the page using the microphone is one of them. The navigation to this page is done is done from another page:
NavigationService.Navigate(new Uri("/Mic.xaml", UriKind.Relative));
Now when on the Mic.xaml page, with or without recording anything if the user clicks the hardware back button he returns to the old page. From this page if he again navigates to the Mic.xaml page and then tries to record something, the recorded file doesn't seem to get recorded properly. There seems to be problems in the recording.
Hence, when we navigate to the page for the first time the recording is successful but when we navigate for the second time or forth it doesn't.
I am performing the testing on the emulator
Upvotes: 1
Views: 2455
Reputation: 39007
Microsoft's sample isn't adapted for multiple-pages scenario, as they doesn't clean up resources when leaving the page.
First, put the DispatcherTimer in a field:
private DispatcherTimer dt;
Then, change the constructor to use this field instead of initializing a new dt:
this.dt = new DispatcherTimer();
Finally, override the OnNavigateFrom method to detect when the user leaves the page, and clean-up the resources:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
dt.Stop();
microphone.BufferReady -= this.microphone_BufferReady;
}
Upvotes: 4