Skip to content

Commit 5eee277

Browse files
committed
Fixing build errors...
1 parent b9e0dd5 commit 5eee277

File tree

8 files changed

+367
-368
lines changed

8 files changed

+367
-368
lines changed

sdk/ai/Azure.AI.VoiceLive/Directory.Build.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,10 @@
22
<!--
33
Add any shared properties you want for the projects under this package directory that need to be set before the auto imported Directory.Build.props
44
-->
5+
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Samples'))">
6+
<IsTestProject>true</IsTestProject>
7+
<IsTestSupportProject>true</IsTestSupportProject>
8+
</PropertyGroup>
9+
510
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory).., Directory.Build.props))\Directory.Build.props" />
611
</Project>

sdk/ai/Azure.AI.VoiceLive/samples/BasicVoiceAssistant/AudioProcessor.cs

Lines changed: 61 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@
33

44
using System.Threading.Channels;
55
using NAudio.Wave;
6+
using Azure.Core.Pipeline;
67

78
namespace Azure.AI.VoiceLive.Samples;
89

910
/// <summary>
1011
/// Handles real-time audio capture and playback for the voice assistant.
11-
///
12+
///
1213
/// This processor demonstrates some of the new VoiceLive SDK convenience methods:
1314
/// - Uses existing SendInputAudioAsync() method for audio streaming
1415
/// - Shows how convenience methods simplify audio operations
15-
///
16+
///
1617
/// Additional convenience methods available in the SDK:
1718
/// - StartAudioTurnAsync() / AppendAudioToTurnAsync() / EndAudioTurnAsync() - Audio turn management
1819
/// - ClearStreamingAudioAsync() - Clear all streaming audio
1920
/// - ConnectAvatarAsync() - Avatar connection with SDP
20-
///
21+
///
2122
/// Threading Architecture:
2223
/// - Main thread: Event loop and UI
2324
/// - Capture thread: NAudio input stream reading
@@ -28,29 +29,29 @@ public class AudioProcessor : IDisposable
2829
{
2930
private readonly VoiceLiveSession _session;
3031
private readonly ILogger<AudioProcessor> _logger;
31-
32+
3233
// Audio configuration - PCM16, 24kHz, mono as specified
3334
private const int SampleRate = 24000;
3435
private const int Channels = 1;
3536
private const int BitsPerSample = 16;
36-
37+
3738
// NAudio components
3839
private WaveInEvent? _waveIn;
3940
private WaveOutEvent? _waveOut;
4041
private BufferedWaveProvider? _playbackBuffer;
41-
42+
4243
// Audio capture and playback state
4344
private bool _isCapturing;
4445
private bool _isPlaying;
45-
46+
4647
// Audio streaming channels
4748
private readonly Channel<byte[]> _audioSendChannel;
4849
private readonly Channel<byte[]> _audioPlaybackChannel;
4950
private readonly ChannelWriter<byte[]> _audioSendWriter;
5051
private readonly ChannelReader<byte[]> _audioSendReader;
5152
private readonly ChannelWriter<byte[]> _audioPlaybackWriter;
5253
private readonly ChannelReader<byte[]> _audioPlaybackReader;
53-
54+
5455
// Background tasks
5556
private Task? _audioSendTask;
5657
private Task? _audioPlaybackTask;
@@ -66,45 +67,45 @@ public AudioProcessor(VoiceLiveSession session, ILogger<AudioProcessor> logger)
6667
{
6768
_session = session ?? throw new ArgumentNullException(nameof(session));
6869
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
69-
70+
7071
// Create unbounded channels for audio data
7172
_audioSendChannel = Channel.CreateUnbounded<byte[]>();
7273
_audioSendWriter = _audioSendChannel.Writer;
7374
_audioSendReader = _audioSendChannel.Reader;
74-
75+
7576
_audioPlaybackChannel = Channel.CreateUnbounded<byte[]>();
7677
_audioPlaybackWriter = _audioPlaybackChannel.Writer;
7778
_audioPlaybackReader = _audioPlaybackChannel.Reader;
78-
79+
7980
_cancellationTokenSource = new CancellationTokenSource();
8081
_playbackCancellationTokenSource = new CancellationTokenSource();
8182

8283
_logger.LogInformation("AudioProcessor initialized with {SampleRate}Hz PCM16 mono audio", SampleRate);
8384
}
84-
85+
8586
/// <summary>
8687
/// Start capturing audio from microphone.
8788
/// </summary>
8889
public Task StartCaptureAsync()
8990
{
9091
if (_isCapturing)
9192
return Task.CompletedTask;
92-
93+
9394
_isCapturing = true;
94-
95+
9596
try
9697
{
9798
_waveIn = new WaveInEvent
9899
{
99100
WaveFormat = new WaveFormat(SampleRate, BitsPerSample, Channels),
100101
BufferMilliseconds = 50 // 50ms buffer for low latency
101102
};
102-
103+
103104
_waveIn.DataAvailable += OnAudioDataAvailable;
104105
_waveIn.RecordingStopped += OnRecordingStopped;
105106

106107
_logger.LogInformation($"There are {WaveIn.DeviceCount} devices available.");
107-
for(int i = 0; i < WaveIn.DeviceCount; i++)
108+
for (int i = 0; i < WaveIn.DeviceCount; i++)
108109
{
109110
var deviceInfo = WaveIn.GetCapabilities(i);
110111

@@ -113,10 +114,10 @@ public Task StartCaptureAsync()
113114
_waveIn.DeviceNumber = 1;
114115

115116
_waveIn.StartRecording();
116-
117+
117118
// Start audio send task
118119
_audioSendTask = ProcessAudioSendAsync(_cancellationTokenSource.Token);
119-
120+
120121
_logger.LogInformation("Started audio capture");
121122
return Task.CompletedTask;
122123
}
@@ -127,17 +128,17 @@ public Task StartCaptureAsync()
127128
throw;
128129
}
129130
}
130-
131+
131132
/// <summary>
132133
/// Stop capturing audio.
133134
/// </summary>
134135
public async Task StopCaptureAsync()
135136
{
136137
if (!_isCapturing)
137138
return;
138-
139+
139140
_isCapturing = false;
140-
141+
141142
if (_waveIn != null)
142143
{
143144
_waveIn.StopRecording();
@@ -146,49 +147,49 @@ public async Task StopCaptureAsync()
146147
_waveIn.Dispose();
147148
_waveIn = null;
148149
}
149-
150+
150151
// Complete the send channel and wait for the send task
151152
_audioSendWriter.TryComplete();
152153
if (_audioSendTask != null)
153154
{
154155
await _audioSendTask.ConfigureAwait(false);
155156
_audioSendTask = null;
156157
}
157-
158+
158159
_logger.LogInformation("Stopped audio capture");
159160
}
160-
161+
161162
/// <summary>
162163
/// Initialize audio playback system.
163164
/// </summary>
164165
public Task StartPlaybackAsync()
165166
{
166167
if (_isPlaying)
167168
return Task.CompletedTask;
168-
169+
169170
_isPlaying = true;
170-
171+
171172
try
172173
{
173174
_waveOut = new WaveOutEvent
174175
{
175176
DesiredLatency = 100 // 100ms latency
176177
};
177-
178+
178179
_playbackBuffer = new BufferedWaveProvider(new WaveFormat(SampleRate, BitsPerSample, Channels))
179180
{
180181
BufferDuration = TimeSpan.FromMinutes(5), // 5 second buffer
181182
DiscardOnBufferOverflow = true
182183
};
183-
184+
184185
_waveOut.Init(_playbackBuffer);
185186
_waveOut.Play();
186187

187188
_playbackCancellationTokenSource = new CancellationTokenSource();
188189

189190
// Start audio playback task
190191
_audioPlaybackTask = ProcessAudioPlaybackAsync();
191-
192+
192193
_logger.LogInformation("Audio playback system ready");
193194
return Task.CompletedTask;
194195
}
@@ -199,34 +200,35 @@ public Task StartPlaybackAsync()
199200
throw;
200201
}
201202
}
202-
203+
203204
/// <summary>
204205
/// Stop audio playback and clear buffer.
205206
/// </summary>
206207
public async Task StopPlaybackAsync()
207208
{
208209
if (!_isPlaying)
209210
return;
210-
211+
211212
_isPlaying = false;
212-
213+
213214
// Clear the playback channel
214-
while (_audioPlaybackReader.TryRead(out _)) { }
215-
215+
while (_audioPlaybackReader.TryRead(out _))
216+
{ }
217+
216218
if (_playbackBuffer != null)
217219
{
218220
_playbackBuffer.ClearBuffer();
219221
}
220-
222+
221223
if (_waveOut != null)
222224
{
223225
_waveOut.Stop();
224226
_waveOut.Dispose();
225227
_waveOut = null;
226228
}
227-
229+
228230
_playbackBuffer = null;
229-
231+
230232
// Complete the playback channel and wait for the playback task
231233
_playbackCancellationTokenSource.Cancel();
232234

@@ -235,10 +237,10 @@ public async Task StopPlaybackAsync()
235237
await _audioPlaybackTask.ConfigureAwait(false);
236238
_audioPlaybackTask = null;
237239
}
238-
240+
239241
_logger.LogInformation("Stopped audio playback");
240242
}
241-
243+
242244
/// <summary>
243245
/// Queue audio data for playback.
244246
/// </summary>
@@ -250,7 +252,7 @@ public async Task QueueAudioAsync(byte[] audioData)
250252
await _audioPlaybackWriter.WriteAsync(audioData).ConfigureAwait(false);
251253
}
252254
}
253-
255+
254256
/// <summary>
255257
/// Event handler for audio data available from microphone.
256258
/// </summary>
@@ -260,15 +262,15 @@ private void OnAudioDataAvailable(object? sender, WaveInEventArgs e)
260262
{
261263
byte[] audioData = new byte[e.BytesRecorded];
262264
Array.Copy(e.Buffer, 0, audioData, 0, e.BytesRecorded);
263-
265+
264266
// Queue audio data for sending (non-blocking)
265267
if (!_audioSendWriter.TryWrite(audioData))
266268
{
267269
_logger.LogWarning("Failed to queue audio data for sending - channel may be full");
268270
}
269271
}
270272
}
271-
273+
272274
/// <summary>
273275
/// Event handler for recording stopped.
274276
/// </summary>
@@ -279,19 +281,19 @@ private void OnRecordingStopped(object? sender, StoppedEventArgs e)
279281
_logger.LogError(e.Exception, "Audio recording stopped due to error");
280282
}
281283
}
282-
284+
283285
/// <summary>
284286
/// Background task to process audio data and send to VoiceLive service.
285287
/// </summary>
286288
private async Task ProcessAudioSendAsync(CancellationToken cancellationToken)
287289
{
288290
try
289291
{
290-
await foreach (byte[] audioData in _audioSendReader.ReadAllAsync(cancellationToken))
292+
await foreach (byte[] audioData in _audioSendReader.ReadAllAsync(cancellationToken).ConfigureAwait(false))
291293
{
292294
if (cancellationToken.IsCancellationRequested)
293295
break;
294-
296+
295297
try
296298
{
297299
// Send audio data directly to the session using the convenience method
@@ -315,7 +317,7 @@ private async Task ProcessAudioSendAsync(CancellationToken cancellationToken)
315317
_logger.LogError(ex, "Error in audio send processing");
316318
}
317319
}
318-
320+
319321
/// <summary>
320322
/// Background task to process audio playback.
321323
/// </summary>
@@ -326,11 +328,11 @@ private async Task ProcessAudioPlaybackAsync()
326328
CancellationTokenSource combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_playbackCancellationTokenSource.Token, _cancellationTokenSource.Token);
327329
var cancellationToken = combinedTokenSource.Token;
328330

329-
await foreach (byte[] audioData in _audioPlaybackReader.ReadAllAsync(cancellationToken))
331+
await foreach (byte[] audioData in _audioPlaybackReader.ReadAllAsync(cancellationToken).ConfigureAwait(false))
330332
{
331333
if (cancellationToken.IsCancellationRequested)
332334
break;
333-
335+
334336
try
335337
{
336338
if (_playbackBuffer != null && _isPlaying)
@@ -354,36 +356,38 @@ private async Task ProcessAudioPlaybackAsync()
354356
_logger.LogError(ex, "Error in audio playback processing");
355357
}
356358
}
357-
359+
358360
/// <summary>
359361
/// Clean up audio resources.
360362
/// </summary>
361363
public async Task CleanupAsync()
362364
{
363365
await StopCaptureAsync().ConfigureAwait(false);
364366
await StopPlaybackAsync().ConfigureAwait(false);
365-
367+
366368
_cancellationTokenSource.Cancel();
367-
369+
368370
// Wait for background tasks to complete
369371
var tasks = new List<Task>();
370-
if (_audioSendTask != null) tasks.Add(_audioSendTask);
371-
if (_audioPlaybackTask != null) tasks.Add(_audioPlaybackTask);
372-
372+
if (_audioSendTask != null)
373+
tasks.Add(_audioSendTask);
374+
if (_audioPlaybackTask != null)
375+
tasks.Add(_audioPlaybackTask);
376+
373377
if (tasks.Count > 0)
374378
{
375379
await Task.WhenAll(tasks).ConfigureAwait(false);
376380
}
377-
381+
378382
_logger.LogInformation("Audio processor cleaned up");
379383
}
380-
384+
381385
/// <summary>
382386
/// Dispose of resources.
383387
/// </summary>
384388
public void Dispose()
385389
{
386-
CleanupAsync().GetAwaiter().GetResult();
390+
CleanupAsync().Wait();
387391
_cancellationTokenSource.Dispose();
388392
}
389393
}

0 commit comments

Comments
 (0)