/
MainPage.xaml.cs
327 lines (281 loc) · 13.9 KB
/
MainPage.xaml.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*
Copyright (c) 2011 Microsoft Corporation. All rights reserved.
Use of this sample source code is subject to the terms of the Microsoft license
agreement under which you licensed this sample source code and is provided AS-IS.
If you did not accept the terms of the license agreement, you are not authorized
to use this sample source code. For the terms of the license, please see the
license agreement between you and Microsoft.
To see all Code Samples for Windows Phone, visit http://go.microsoft.com/fwlink/?LinkID=219604
*/
using System;
using System.IO;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using System.Windows;
using System.Globalization;
using Microsoft.WindowsAzure.Samples.Phone.Storage;
using sdkMicrophoneCS.Tables;
namespace sdkMicrophoneCS
{
public partial class MainPage : PhoneApplicationPage
{
private Microphone microphone = Microphone.Default; // Object representing the physical microphone on the device
private byte[] buffer; // Dynamic buffer to retrieve audio data from the microphone
private MemoryStream stream = new MemoryStream(); // Stores the audio data for later playback
private SoundEffectInstance soundInstance; // Used to play back audio
private bool soundIsPlaying = false; // Flag to monitor the state of sound playback
private bool soundIsUploading = false; // Flag to monitor the state of sound upload
private string applicationId = "sdkMicrophoneCS_UploadToBlob";
private string containerName = "notes";
private readonly ICloudBlobClient blobClient;
//private readonly ICloudNoteClient cloudNoteClient;
// Status images
private BitmapImage blankImage;
private BitmapImage microphoneImage;
private BitmapImage speakerImage;
/// <summary>
/// Constructor
/// </summary>
public MainPage()
{
InitializeComponent();
// Timer to simulate the XNA Framework game loop (Microphone is
// from the XNA Framework). We also use this timer to monitor the
// state of audio playback so we can update the UI appropriately.
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(33);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
// Event handler for getting audio data when the buffer is full
microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
blankImage = new BitmapImage(new Uri("Images/blank.png", UriKind.RelativeOrAbsolute));
microphoneImage = new BitmapImage(new Uri("Images/microphone.png", UriKind.RelativeOrAbsolute));
speakerImage = new BitmapImage(new Uri("Images/speaker.png", UriKind.RelativeOrAbsolute));
// Initialize storage
this.blobClient = CloudStorageContext.Current.Resolver.CreateCloudBlobClient();
}
/// <summary>
/// Updates the XNA FrameworkDispatcher and checks to see if a sound is playing.
/// If sound has stopped playing, it updates the UI.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void dt_Tick(object sender, EventArgs e)
{
try { FrameworkDispatcher.Update(); }
catch { }
if (true == soundIsPlaying)
{
if (soundInstance.State != SoundState.Playing)
{
// Audio has finished playing
soundIsPlaying = false;
// Update the UI to reflect that the
// sound has stopped playing
SetButtonStates(true, true, false, true);
UserHelp.Text = "press play\nor record";
StatusImage.Source = blankImage;
}
}
}
/// <summary>
/// The Microphone.BufferReady event handler.
/// Gets the audio data from the microphone and stores it in a buffer,
/// then writes that buffer to a stream for later playback.
/// Any action in this event handler should be quick!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void microphone_BufferReady(object sender, EventArgs e)
{
// Retrieve audio data
microphone.GetData(buffer);
// Store the audio data in a stream
stream.Write(buffer, 0, buffer.Length);
}
/// <summary>
/// Handles the Click event for the record button.
/// Sets up the microphone and data buffers to collect audio data,
/// then starts the microphone. Also, updates the UI.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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 information
Helper.WriteWavHeader(stream, microphone.SampleRate);
// Start recording
microphone.Start();
SetButtonStates(false, false, true, false);
UserHelp.Text = "record";
StatusImage.Source = microphoneImage;
}
/// <summary>
/// Handles the Click event for the stop button.
/// Stops the microphone from collecting audio and updates the UI.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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();
// Updated stream with WAV header information
Helper.UpdateWavHeader(stream);
}
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;
}
/// <summary>
/// Handles the Click event for the play button.
/// Plays the audio collected from the microphone and updates the UI.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void playButton_Click(object sender, EventArgs e)
{
if (stream.Length > 0)
{
// Update the UI to reflect that
// sound is playing
SetButtonStates(false, false, true, false);
UserHelp.Text = "play";
StatusImage.Source = speakerImage;
// Play the audio in a new thread so the UI can update.
Thread soundThread = new Thread(new ThreadStart(playSound));
soundThread.Start();
}
}
/// <summary>
/// Plays the audio using SoundEffectInstance
/// so we can monitor the playback status.
/// </summary>
private void playSound()
{
// Play audio using SoundEffectInstance so we can monitor it's State
// and update the UI in the dt_Tick handler when it is done playing.
SoundEffect sound = new SoundEffect(stream.ToArray(), microphone.SampleRate, AudioChannels.Mono);
soundInstance = sound.CreateInstance();
soundIsPlaying = true;
soundInstance.Play();
}
/// <summary>
/// Helper method to change the IsEnabled property for the ApplicationBarIconButtons.
/// </summary>
/// <param name="recordEnabled">New state for the record button.</param>
/// <param name="playEnabled">New state for the play button.</param>
/// <param name="stopEnabled">New state for the stop button.</param>
private void SetButtonStates(bool recordEnabled, bool playEnabled, bool stopEnabled, bool uploadEnabled)
{
(ApplicationBar.Buttons[0] as ApplicationBarIconButton).IsEnabled = recordEnabled;
(ApplicationBar.Buttons[1] as ApplicationBarIconButton).IsEnabled = playEnabled;
(ApplicationBar.Buttons[2] as ApplicationBarIconButton).IsEnabled = stopEnabled;
(ApplicationBar.Buttons[3] as ApplicationBarIconButton).IsEnabled = uploadEnabled;
}
/// <summary>
/// Handles the Click event for the stop button.
/// Stops the microphone from collecting audio and updates the UI.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void uploadButton_Click(object sender, EventArgs e)
{
UploadAudio(
successMessage =>
{
MessageBox.Show("Upload successful", "upload result message", MessageBoxButton.OK);
//this.NavigationService.GoBack();
},
errorMessage =>
{
MessageBox.Show(errorMessage, "upload result message", MessageBoxButton.OK);
//this.NavigationService.GoBack();
});
}
public void UploadAudio(Action<string> successCallback, Action<string> failureCallback)
{
successCallback = successCallback ?? (r => { });
failureCallback = failureCallback ?? (r => { });
soundIsUploading = true;
var container = this.blobClient.GetContainerReference(this.containerName);
container.CreateIfNotExist(
BlobContainerPublicAccessType.Container,
r =>
{
// Successfull container creation.
if (r.Success)
{
string blobName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}.wav", DateTime.Now.ToString("yyyyMMddTHHmmss", CultureInfo.InvariantCulture), Guid.NewGuid());
var blob = container.GetBlobReference(blobName);
blob.Properties.ContentType = "audio/wav";
//blob.Metadata["alias"] = userAlias;
//blob.Metadata["date"] = DateTime.Now.ToString(CultureInfo.InvariantCulture);
this.stream.Position = 0;
blob.UploadFromStream(
this.stream,
response =>
{
if (response.Success)
{
CloudNote cloudNote = new CloudNote();
cloudNote.ApplicationId = this.applicationId;
cloudNote.DeviceId = Helper.DeviceId;
cloudNote.PartitionKey = "a";
cloudNote.Time = DateTime.Now;
cloudNote.Uri = blob.Uri.AbsoluteUri;
var tableClient = CloudStorageContext.Current.Resolver.CreateCloudTableClient();
var tableName = "CloudNotes";
tableClient.CreateTableIfNotExist(
tableName,
p =>
{
var context = CloudStorageContext.Current.Resolver.CreateTableServiceContext();
context.AddObject(tableName, cloudNote);
context.BeginSaveChanges(
asyncResult =>
{
var response2 = context.EndSaveChanges(asyncResult);
// Some logic here.
},
null);
});
}
else
{
soundIsUploading = false;
failureCallback(string.Concat("Error: ", response.ErrorMessage));
}
stream.Close();
});
}
else
{
soundIsUploading = false;
// The container was not created successfully, some error has ocurred.
failureCallback(string.Concat("Error: ", r.ErrorMessage));
}
});
}
}
}