Skip to content

Commit afc18ac

Browse files
danbohuschitsaw
authored andcommitted
Release 0.16.92.1
1 parent 0411fc2 commit afc18ac

File tree

527 files changed

+25216
-5526
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

527 files changed

+25216
-5526
lines changed

Directory.Build.props

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Company>Microsoft Corporation</Company>
77
<Owners>microsoft,psi</Owners>
88
<Authors>Microsoft</Authors>
9-
<AssemblyVersion>0.15.49.1</AssemblyVersion>
9+
<AssemblyVersion>0.16.92.1</AssemblyVersion>
1010
<FileVersion>$(AssemblyVersion)</FileVersion>
1111
<Version>$(AssemblyVersion)-beta</Version>
1212
<SignAssembly>false</SignAssembly>

Psi.sln

+48
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filters", "Filters", "{E0E7
198198
EndProject
199199
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Psi.Filters", "Sources\Filters\Microsoft.Psi.Filters\Microsoft.Psi.Filters.csproj", "{E0621435-AF35-4CFA-BE9E-3781AF6E161F}"
200200
EndProject
201+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Spatial", "Spatial", "{F36DEF23-4FFF-4237-9104-03CF19036C70}"
202+
EndProject
203+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Psi.Spatial.Euclidean", "Sources\Spatial\Microsoft.Psi.Spatial.Euclidean\Microsoft.Psi.Spatial.Euclidean.csproj", "{C3114338-AD22-4EBC-85C3-EE06045CDD78}"
204+
EndProject
205+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Psi.Spatial.Euclidean.Visualization.Windows", "Sources\Spatial\Microsoft.Psi.Spatial.Euclidean.Visualization.Windows\Microsoft.Psi.Spatial.Euclidean.Visualization.Windows.csproj", "{A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}"
206+
EndProject
207+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MixedReality", "MixedReality", "{32023088-0392-4B48-B2CF-3754B55C6DE9}"
208+
EndProject
209+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HoloLens2ResearchMode", "Sources\MixedReality\HoloLens2ResearchMode\HoloLens2ResearchMode.vcxproj", "{F50194C0-9561-40C7-B9CB-B977E3B3D76D}"
210+
EndProject
211+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Psi.MixedReality", "Sources\MixedReality\Microsoft.Psi.MixedReality\Microsoft.Psi.MixedReality.csproj", "{3434D5B2-B06F-4356-9E9B-90171CEF482B}"
212+
EndProject
213+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Psi.MixedReality.UniversalWindows", "Sources\MixedReality\Microsoft.Psi.MixedReality.UniversalWindows\Microsoft.Psi.MixedReality.UniversalWindows.csproj", "{ECD9E150-8104-4DA3-B807-A6A4392A67C6}"
214+
EndProject
215+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Psi.MixedReality.Visualization.Windows", "Sources\MixedReality\Microsoft.Psi.MixedReality.Visualization.Windows\Microsoft.Psi.MixedReality.Visualization.Windows.csproj", "{BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}"
216+
EndProject
201217
Global
202218
GlobalSection(SolutionConfigurationPlatforms) = preSolution
203219
Debug|Any CPU = Debug|Any CPU
@@ -436,6 +452,30 @@ Global
436452
{E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Debug|Any CPU.Build.0 = Debug|Any CPU
437453
{E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Release|Any CPU.ActiveCfg = Release|Any CPU
438454
{E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Release|Any CPU.Build.0 = Release|Any CPU
455+
{C3114338-AD22-4EBC-85C3-EE06045CDD78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
456+
{C3114338-AD22-4EBC-85C3-EE06045CDD78}.Debug|Any CPU.Build.0 = Debug|Any CPU
457+
{C3114338-AD22-4EBC-85C3-EE06045CDD78}.Release|Any CPU.ActiveCfg = Release|Any CPU
458+
{C3114338-AD22-4EBC-85C3-EE06045CDD78}.Release|Any CPU.Build.0 = Release|Any CPU
459+
{A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
460+
{A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Debug|Any CPU.Build.0 = Debug|Any CPU
461+
{A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Release|Any CPU.ActiveCfg = Release|Any CPU
462+
{A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Release|Any CPU.Build.0 = Release|Any CPU
463+
{F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Debug|Any CPU.ActiveCfg = Debug|ARM
464+
{F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Debug|Any CPU.Build.0 = Debug|ARM
465+
{F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Release|Any CPU.ActiveCfg = Release|ARM
466+
{F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Release|Any CPU.Build.0 = Release|ARM
467+
{3434D5B2-B06F-4356-9E9B-90171CEF482B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
468+
{3434D5B2-B06F-4356-9E9B-90171CEF482B}.Debug|Any CPU.Build.0 = Debug|Any CPU
469+
{3434D5B2-B06F-4356-9E9B-90171CEF482B}.Release|Any CPU.ActiveCfg = Release|Any CPU
470+
{3434D5B2-B06F-4356-9E9B-90171CEF482B}.Release|Any CPU.Build.0 = Release|Any CPU
471+
{ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Debug|Any CPU.ActiveCfg = Debug|ARM
472+
{ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Debug|Any CPU.Build.0 = Debug|ARM
473+
{ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Release|Any CPU.ActiveCfg = Release|ARM
474+
{ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Release|Any CPU.Build.0 = Release|ARM
475+
{BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
476+
{BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Debug|Any CPU.Build.0 = Debug|Any CPU
477+
{BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Release|Any CPU.ActiveCfg = Release|Any CPU
478+
{BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Release|Any CPU.Build.0 = Release|Any CPU
439479
EndGlobalSection
440480
GlobalSection(SolutionProperties) = preSolution
441481
HideSolutionNode = FALSE
@@ -522,6 +562,14 @@ Global
522562
{A0677BEA-ADB1-4950-89E6-89483D621A52} = {EE4035A8-CEFE-4E3A-9CD9-4AE7E88DA2C4}
523563
{E0E7957E-731F-4FDD-83FE-634FFE24862F} = {A0856299-D28A-4513-B964-3FA5290FF160}
524564
{E0621435-AF35-4CFA-BE9E-3781AF6E161F} = {E0E7957E-731F-4FDD-83FE-634FFE24862F}
565+
{F36DEF23-4FFF-4237-9104-03CF19036C70} = {A0856299-D28A-4513-B964-3FA5290FF160}
566+
{C3114338-AD22-4EBC-85C3-EE06045CDD78} = {F36DEF23-4FFF-4237-9104-03CF19036C70}
567+
{A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F} = {F36DEF23-4FFF-4237-9104-03CF19036C70}
568+
{32023088-0392-4B48-B2CF-3754B55C6DE9} = {A0856299-D28A-4513-B964-3FA5290FF160}
569+
{F50194C0-9561-40C7-B9CB-B977E3B3D76D} = {32023088-0392-4B48-B2CF-3754B55C6DE9}
570+
{3434D5B2-B06F-4356-9E9B-90171CEF482B} = {32023088-0392-4B48-B2CF-3754B55C6DE9}
571+
{ECD9E150-8104-4DA3-B807-A6A4392A67C6} = {32023088-0392-4B48-B2CF-3754B55C6DE9}
572+
{BE95524A-F9C2-4D0D-8F7E-1C7019B5A114} = {32023088-0392-4B48-B2CF-3754B55C6DE9}
525573
EndGlobalSection
526574
GlobalSection(ExtensibilityGlobals) = postSolution
527575
SolutionGuid = {EAF15EE9-DCC5-411B-A9E5-7C2F3D132331}

Sources/Audio/Microsoft.Psi.Audio.Linux/AudioCapture.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public void Start(Action<DateTime> notifyCompletionTime)
158158
Array.Copy(buf, this.buffer.Data, length);
159159

160160
// use the end of the last sample in the packet as the originating time
161-
DateTime originatingTime = this.pipeline.GetCurrentTime().AddSeconds(length / format.AvgBytesPerSec);
161+
DateTime originatingTime = this.pipeline.GetCurrentTime().AddSeconds((double)length / format.AvgBytesPerSec);
162162

163163
// post the data to the output stream
164164
this.audioBuffers.Post(this.buffer, originatingTime);

Sources/Audio/Microsoft.Psi.Audio.Windows/MFResampler.cs

+20-4
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,32 @@ public void Initialize(int targetLatencyInMs, WaveFormat inFormat, WaveFormat ou
9191
this.inputBufferSize = (int)(this.bufferLengthInMs * inFormat.AvgBytesPerSec / 1000);
9292
this.outputBufferSize = (int)(this.bufferLengthInMs * outFormat.AvgBytesPerSec / 1000);
9393

94+
Exception taskException = null;
95+
9496
// Activate native Media Foundation COM objects on a thread-pool thread to ensure that they are in an MTA
9597
Task.Run(() =>
9698
{
97-
DeviceUtil.CreateResamplerBuffer(this.inputBufferSize, out this.inputSample, out this.inputBuffer);
98-
DeviceUtil.CreateResamplerBuffer(this.outputBufferSize, out this.outputSample, out this.outputBuffer);
99+
try
100+
{
101+
DeviceUtil.CreateResamplerBuffer(this.inputBufferSize, out this.inputSample, out this.inputBuffer);
102+
DeviceUtil.CreateResamplerBuffer(this.outputBufferSize, out this.outputSample, out this.outputBuffer);
99103

100-
// Create resampler object
101-
this.resampler = DeviceUtil.CreateResampler(inFormat, outFormat);
104+
// Create resampler object
105+
this.resampler = DeviceUtil.CreateResampler(inFormat, outFormat);
106+
}
107+
catch (Exception e)
108+
{
109+
taskException = e;
110+
}
102111
}).Wait();
103112

113+
// do error checking on the main thread
114+
if (taskException != null)
115+
{
116+
// rethrow exception
117+
throw taskException;
118+
}
119+
104120
// Set the callback function
105121
this.dataAvailableCallback = callback;
106122
}

Sources/Audio/Microsoft.Psi.Audio.Windows/Operators.cs

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
namespace Microsoft.Psi.Audio
55
{
6-
using Microsoft.Psi.Audio;
7-
86
/// <summary>
97
/// Stream operators and extension methods for Microsoft.Psi.Audio.Windows.
108
/// </summary>

Sources/Audio/Microsoft.Psi.Audio.Windows/WasapiCapture.cs

+31-17
Original file line numberDiff line numberDiff line change
@@ -143,33 +143,47 @@ public void Dispose()
143143
/// </param>
144144
public void Initialize(string deviceDescription)
145145
{
146+
Exception taskException = null;
147+
146148
// Activate native audio COM objects on a thread-pool thread to ensure that they are in an MTA
147149
Task.Run(() =>
148150
{
149-
if (string.IsNullOrEmpty(deviceDescription))
151+
try
150152
{
151-
// use the default console device
152-
this.audioDevice = DeviceUtil.GetDefaultDevice(EDataFlow.Capture, ERole.Console);
153+
if (string.IsNullOrEmpty(deviceDescription))
154+
{
155+
// use the default console device
156+
this.audioDevice = DeviceUtil.GetDefaultDevice(EDataFlow.Capture, ERole.Console);
157+
}
158+
else
159+
{
160+
this.audioDevice = DeviceUtil.GetDeviceByName(EDataFlow.Capture, deviceDescription);
161+
}
162+
163+
if (this.audioDevice != null)
164+
{
165+
// Try to get the volume control
166+
object obj = this.audioDevice.Activate(new Guid(Guids.IAudioEndpointVolumeIIDString), ClsCtx.ALL, IntPtr.Zero);
167+
this.volume = (IAudioEndpointVolume)obj;
168+
169+
// Now create an IAudioEndpointVolumeCallback object that wraps the callback and register it with the endpoint.
170+
this.volumeCallback = new AudioEndpointVolumeCallback(this.AudioVolumeCallback);
171+
this.volume.RegisterControlChangeNotify(this.volumeCallback);
172+
}
153173
}
154-
else
174+
catch (Exception e)
155175
{
156-
this.audioDevice = DeviceUtil.GetDeviceByName(EDataFlow.Capture, deviceDescription);
157-
}
158-
159-
if (this.audioDevice != null)
160-
{
161-
// Try to get the volume control
162-
object obj = this.audioDevice.Activate(new Guid(Guids.IAudioEndpointVolumeIIDString), ClsCtx.ALL, IntPtr.Zero);
163-
this.volume = (IAudioEndpointVolume)obj;
164-
165-
// Now create an IAudioEndpointVolumeCallback object that wraps the callback and register it with the endpoint.
166-
this.volumeCallback = new AudioEndpointVolumeCallback(this.AudioVolumeCallback);
167-
this.volume.RegisterControlChangeNotify(this.volumeCallback);
176+
taskException = e;
168177
}
169178
}).Wait();
170179

171180
// do error checking on the main thread
172-
if (this.audioDevice == null)
181+
if (taskException != null)
182+
{
183+
// rethrow exception
184+
throw taskException;
185+
}
186+
else if (this.audioDevice == null)
173187
{
174188
throw new IOException(string.IsNullOrEmpty(deviceDescription) ?
175189
"No default audio capture device found." :

Sources/Audio/Microsoft.Psi.Audio.Windows/WasapiRender.cs

+39-16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace Microsoft.Psi.Audio
55
{
66
using System;
7+
using System.IO;
78
using System.Runtime.InteropServices;
89
using System.Threading.Tasks;
910
using Microsoft.Psi.Audio.ComInterop;
@@ -138,30 +139,52 @@ public void Dispose()
138139
/// </param>
139140
public void Initialize(string deviceDescription)
140141
{
142+
Exception taskException = null;
143+
141144
// Activate native audio COM objects on a thread-pool thread to ensure that they are in an MTA
142145
Task.Run(() =>
143146
{
144-
if (string.IsNullOrEmpty(deviceDescription))
147+
try
145148
{
146-
// use the default console device
147-
this.audioDevice = DeviceUtil.GetDefaultDevice(EDataFlow.Render, ERole.Console);
149+
if (string.IsNullOrEmpty(deviceDescription))
150+
{
151+
// use the default console device
152+
this.audioDevice = DeviceUtil.GetDefaultDevice(EDataFlow.Render, ERole.Console);
153+
}
154+
else
155+
{
156+
this.audioDevice = DeviceUtil.GetDeviceByName(EDataFlow.Render, deviceDescription);
157+
}
158+
159+
if (this.audioDevice != null)
160+
{
161+
// Try to get the volume control
162+
object obj = this.audioDevice.Activate(new Guid(Guids.IAudioEndpointVolumeIIDString), ClsCtx.ALL, IntPtr.Zero);
163+
this.volume = (IAudioEndpointVolume)obj;
164+
165+
// Now create an IAudioEndpointVolumeCallback object that wraps the callback and register it with the endpoint.
166+
this.volumeCallback = new AudioEndpointVolumeCallback(this.AudioVolumeCallback);
167+
this.volume.RegisterControlChangeNotify(this.volumeCallback);
168+
}
148169
}
149-
else
170+
catch (Exception e)
150171
{
151-
this.audioDevice = DeviceUtil.GetDeviceByName(EDataFlow.Render, deviceDescription);
152-
}
153-
154-
if (this.audioDevice != null)
155-
{
156-
// Try to get the volume control
157-
object obj = this.audioDevice.Activate(new Guid(Guids.IAudioEndpointVolumeIIDString), ClsCtx.ALL, IntPtr.Zero);
158-
this.volume = (IAudioEndpointVolume)obj;
159-
160-
// Now create an IAudioEndpointVolumeCallback object that wraps the callback and register it with the endpoint.
161-
this.volumeCallback = new AudioEndpointVolumeCallback(this.AudioVolumeCallback);
162-
this.volume.RegisterControlChangeNotify(this.volumeCallback);
172+
taskException = e;
163173
}
164174
}).Wait();
175+
176+
// do error checking on the main thread
177+
if (taskException != null)
178+
{
179+
// rethrow exception
180+
throw taskException;
181+
}
182+
else if (this.audioDevice == null)
183+
{
184+
throw new IOException(string.IsNullOrEmpty(deviceDescription) ?
185+
"No default audio playback device found." :
186+
$"Audio playback device {deviceDescription} not found.");
187+
}
165188
}
166189

167190
/// <summary>

Sources/Audio/Microsoft.Psi.Audio/WaveFileHelper.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,18 @@ public static WaveFormat ReadWaveFileHeader(string filename)
6363
/// <returns>The number of byte of wave data that follow.</returns>
6464
public static long ReadWaveDataLength(BinaryReader br)
6565
{
66-
if (Encoding.UTF8.GetString(BitConverter.GetBytes(br.ReadInt32())) != "data")
66+
var name = Encoding.UTF8.GetString(BitConverter.GetBytes(br.ReadInt32()));
67+
if (name != "data")
6768
{
69+
if (name == "fact" || name == "LIST")
70+
{
71+
// Some formats (e.g. IEEE float) contain fact and LIST chunks (which we skip).
72+
// see fhe "fact Chunk" section of the spec: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
73+
// "IEEE float data (introduced after the Rev. 3 documention) need a fact"
74+
br.ReadBytes((int)br.ReadUInt32()); // skip
75+
return ReadWaveDataLength(br);
76+
}
77+
6878
throw new FormatException("Data header missing");
6979
}
7080

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
namespace Microsoft.Psi.Audio
5+
{
6+
using System;
7+
using System.IO;
8+
using Microsoft.Psi.Components;
9+
10+
/// <summary>
11+
/// Component that produces on-demand an audio sample specified by a <see cref="System.IO.Stream"/>.
12+
/// </summary>
13+
/// <remarks>
14+
/// This is meant for relatively short sound effects cached in memory.
15+
/// We consume the stream given at construction time; breaking it into
16+
/// audio buffers which are "played" upon receiving a true input signal.
17+
/// </remarks>
18+
public class WaveStreamSampleSource : IConsumerProducer<bool, AudioBuffer>
19+
{
20+
private readonly Pipeline pipeline;
21+
private readonly AudioBuffer[] audioData;
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="WaveStreamSampleSource"/> class.
25+
/// </summary>
26+
/// <param name="pipeline">The pipeline to add the component to.</param>
27+
/// <param name="stream">Audio stream in WAVE format (48KHz, 1-channel, IEEE Float).</param>
28+
public WaveStreamSampleSource(Pipeline pipeline, Stream stream)
29+
{
30+
this.pipeline = pipeline;
31+
this.In = pipeline.CreateReceiver<bool>(this, this.Play, nameof(this.In));
32+
this.Out = pipeline.CreateEmitter<AudioBuffer>(this, nameof(this.Out));
33+
34+
var reader = new BinaryReader(stream);
35+
var inputFormat = WaveFileHelper.ReadWaveFileHeader(reader);
36+
37+
// we don't do resampling or conversion (must be 1-channel, 48kHz, float32).
38+
// convert offline if needed: ffmpeg -i foo.wav -f wav -acodec pcm_f32le -ar 48000 -ac 1 bar.wav
39+
if (inputFormat.Channels != 1 ||
40+
inputFormat.SamplesPerSec != 48000 ||
41+
(inputFormat.FormatTag != WaveFormatTag.WAVE_FORMAT_IEEE_FLOAT &&
42+
inputFormat.FormatTag != WaveFormatTag.WAVE_FORMAT_EXTENSIBLE) ||
43+
inputFormat.BitsPerSample != 32)
44+
{
45+
throw new ArgumentException("Expected 1-channel, 48kHz, float32 audio format.");
46+
}
47+
48+
// break into 1 second audio buffers
49+
var outputFormat = WaveFormat.CreateIeeeFloat(48000, 1);
50+
var dataLength = WaveFileHelper.ReadWaveDataLength(reader);
51+
52+
// stepping over this line computing frames (e.g. F10) in the debugger will throw - still trying to understand why
53+
var frames = (int)Math.Ceiling((double)dataLength / (double)outputFormat.AvgBytesPerSec);
54+
this.audioData = new AudioBuffer[frames];
55+
for (var i = 0; dataLength > 0; i++)
56+
{
57+
var count = (int)Math.Min(dataLength, outputFormat.AvgBytesPerSec);
58+
var bytes = reader.ReadBytes(count);
59+
this.audioData[i] = new AudioBuffer(bytes, outputFormat);
60+
dataLength -= count;
61+
}
62+
}
63+
64+
/// <summary>
65+
/// Gets the receiver of a signal indicating whether to play a sound.
66+
/// </summary>
67+
public Receiver<bool> In { get; private set; }
68+
69+
/// <summary>
70+
/// Gets the stream of sound output.
71+
/// </summary>
72+
public Emitter<AudioBuffer> Out { get; private set; }
73+
74+
private void Play(bool play)
75+
{
76+
if (play)
77+
{
78+
var now = this.pipeline.GetCurrentTime();
79+
if (now < this.Out.LastEnvelope.OriginatingTime)
80+
{
81+
// overlapping with last time played (play after)
82+
now = this.Out.LastEnvelope.OriginatingTime.AddTicks(1);
83+
}
84+
85+
for (var i = 0; i < this.audioData.Length; i++)
86+
{
87+
this.Out.Post(this.audioData[i], now + TimeSpan.FromSeconds(i));
88+
}
89+
}
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)