forked from microsoft/MixedRealityToolkit-Unity
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathMicStream.cs
More file actions
195 lines (172 loc) · 11 KB
/
Copy pathMicStream.cs
File metadata and controls
195 lines (172 loc) · 11 KB
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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using System.Runtime.InteropServices;
using UnityEngine;
using System.Text;
namespace HoloToolkit.Unity.InputModule
{
public class MicStream
{
// This class replaces Unity's Microphone object
// This class is made for HoloLens mic stream selection, but should work well on all windows 10 devices
// chooses from one of three possible microphone modes on HoloLens
// There is an example of how to use this script in HoloToolkit\Input\Tests\Scripts\MicStreamDemo.cs
// Streams: LOW_QUALITY_VOICE is optimized for speech analysis, COMMUNICATIONS is higher quality voice and is probably preferred
// ROOM_CAPTURE tries to get the sounds of the room more than the voice of the suer
// can only be set on initialization
public enum StreamCategory { LOW_QUALITY_VOICE, HIGH_QUALITY_VOICE, ROOM_CAPTURE }
public enum ErrorCodes { ALREADY_RUNNING = -10, NO_AUDIO_DEVICE, NO_INPUT_DEVICE, ALREADY_RECORDING, GRAPH_NOT_EXIST, CHANNEL_COUNT_MISMATCH, FILE_CREATION_PERMISSION_ERROR, NOT_ENOUGH_DATA, NEED_ENABLED_MIC_CAPABILITY };
const int MAX_PATH = 260; // 260 is maximum path length in windows, to be returned when we MicStopRecording
[UnmanagedFunctionPointer(CallingConvention.StdCall)] // If included in MicStartStream, this callback will be triggered when audio data is ready. This is not the preferred method for Game Engines and can probably be ignored.
public delegate void LiveMicCallback();
/// <summary>
/// Called before calling MicStartStream or MicstartRecording to initialize microphone
/// </summary>
/// <param name="category">One of the entries in the StreamCategory enumeratio</param>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicInitializeDefault(int category);
/// <summary>
/// Called before calling MicStartStream or MicstartRecording to initialize microphone
/// </summary>
/// <param name="category">One of the entries in the StreamCategory enumeration</param>
/// <param name="samplerate">Desired number of samples per second</param>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicInitializeCustomRate(int category, int samplerate);
/// <summary>
/// Call this to start receiving data from a microphone. Then, each frame, call MicGetFrame.
/// </summary>
/// <param name="keepData">If true, all data will stay in the queue, if the client code is running behind. This can lead to significant audio lag, so is not appropriate for low-latency situations like reall-time voice chat.</param>
/// <param name="previewOnDevice">If true, the audio from the microphone will be played through your speakers.</param>
/// <param name="micsignal">Optional (can be null): This callback will be called when data is ready for MicGetFrame</param>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicStartStream(bool keepData, bool previewOnDevice, LiveMicCallback micsignal);
/// <summary>
/// Call this to start receiving data from a microphone. Then, each frame, call MicGetFrame.
/// </summary>
/// <param name="keepData">If true, all data will stay in the queue, if the client code is running behind. This can lead to significant audio lag, so is not appropriate for low-latency situations like reall-time voice chat.</param>
/// <param name="previewOnDevice">If true, the audio from the microphone will be played through your speakers.</param>
/// <returns>error code or 0</returns>
public static int MicStartStream(bool keepData, bool previewOnDevice)
{
return MicStartStream(keepData, previewOnDevice, null);
}
/// <summary>
/// Shuts down the connection to the microphone. Data will not longer be received from the microphone.
/// </summary>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicStopStream();
/// <summary>
/// Begins recording microphone data to the specified file.
/// </summary>
/// <param name="filename">The file will be saved to this name. Specify only the wav file's name with extensions, aka "myfile.wav", not full path</param>
/// <param name="previewOnDevice">If true, will play micstream in speakers</param>
/// <returns></returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicStartRecording(string filename, bool previewOnDevice);
/// <summary>
/// Finishes writing the file recording started with MicStartRecording.
/// </summary>
/// <param name="sb">returns the full path to the recorded audio file</param>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern void MicStopRecording(StringBuilder sb);
/// <summary>
/// Finishes writing the file recording started with MicStartRecording.
/// </summary>
/// <returns>the full path to the recorded audio file</returns>
public static string MicStopRecording()
{
StringBuilder builder = new StringBuilder(MAX_PATH);
MicStopRecording(builder);
return builder.ToString();
}
/// <summary>
/// Cleans up data associated with microphone recording. Counterpart to MicInitialize*
/// </summary>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicDestroy();
/// <summary>
/// Pauses streaming of microphone data to MicGetFrame (and/or file specified with MicStartRecording)
/// </summary>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicPause();
/// <summary>
/// Unpauses streaming of microphone data to MicGetFrame (and/or file specified with MicStartRecording)
/// </summary>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicResume();
/// <summary>
/// Sets apmlification factor for microphone samples returned by MicGetFrame (and/or file specified with MicStartRecording)
/// </summary>
/// <param name="g">gain factor</param>
/// <returns>error code or 0</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicSetGain(float g);
/// <summary>
/// Queries the default microphone audio frame sample size. Useful if doing default initializations with callbacks to know how much data it wants to hand you.
/// </summary>
/// <returns>the number of samles in the default audio buffer</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
private static extern int MicGetDefaultBufferSize();
/// <summary>
/// Queries the number of channels supported by the microphone. Useful if doing default initializations with callbacks to know how much data it wants to hand you.
/// </summary>
/// <returns>the number of channels</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
private static extern int MicGetDefaultNumChannels();
/// <summary>
/// Read from the microphone buffer. Usually called once per frame.
/// </summary>
/// <param name="buffer">the buffer into which to store the microphone audio samples</param>
/// <param name="length">the length of the buffer</param>
/// <param name="numchannels">the number of audio channels to store in the buffer</param>
/// <returns>error code (or 0 if no error)</returns>
[DllImport("MicStreamSelector", ExactSpelling = true)]
public static extern int MicGetFrame(float[] buffer, int length, int numchannels);
/// <summary>
/// Prints useful error/warning messages based on error codes returned from the functions in this class
/// </summary>
/// <param name="returnCode">An error code returned by another function in this class</param>
/// <returns>True if no error or warning message was printed, false if a message was printed</returns>
public static bool CheckForErrorOnCall(int returnCode)
{
switch (returnCode)
{
case (int)ErrorCodes.ALREADY_RECORDING:
Debug.LogError("WARNING: Tried to start recording when you were already doing so. You need to stop your previous recording before you can start again.");
return false;
case (int)ErrorCodes.ALREADY_RUNNING:
Debug.LogError("WARNING: Tried to initialize microphone more than once");
return false;
case (int)ErrorCodes.GRAPH_NOT_EXIST:
Debug.LogError("ERROR: Tried to do microphone things without a properly initialized microphone. \n Do you have a mic plugged into a functional audio system and did you call MicInitialize() before anything else ??");
return false;
case (int)ErrorCodes.NO_AUDIO_DEVICE:
Debug.LogError("ERROR: Tried to start microphone, but you don't appear to have a functional audio device. check your OS audio settings.");
return false;
case (int)ErrorCodes.NO_INPUT_DEVICE:
Debug.LogError("ERROR: Tried to start microphone, but you don't have one plugged in, do you?");
return false;
case (int)ErrorCodes.CHANNEL_COUNT_MISMATCH:
Debug.LogError("ERROR: Microphone had a channel count mismatch internally on device. Try setting different mono/stereo options in OS mic settings.");
return false;
case (int)ErrorCodes.FILE_CREATION_PERMISSION_ERROR:
Debug.LogError("ERROR: Didn't have access to create file in Music library. Make sure permissions to write to Music library are set granted.");
return false;
case (int)ErrorCodes.NOT_ENOUGH_DATA:
// usually not an error, means the device hasn't produced enough data yet because it just started running
return false;
case (int)ErrorCodes.NEED_ENABLED_MIC_CAPABILITY:
Debug.LogError("ERROR: Seems like you forgot to enable the microphone capabilities in your Unity permissions");
return false;
}
return true;
}
}
}