-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwaveIn.cpp
165 lines (136 loc) · 5.93 KB
/
waveIn.cpp
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
#include "waveIn.h"
#include <stdio.h>
#pragma comment(lib, "Winmm.lib")
const unsigned short MicLevel = 65535;
// TODO: also set Mic Boost
// MIXERCONTROL_CONTROLTYPE_DECIBELS ??
#define WAV_IN_BUF_MSECS 1000
#define WAV_IN_CHANNELS 1
#define BITS_PER_SAMPLE 16
#define WAV_IN_SAMPLE_HZ 192000 // requested standard nominal value
const int NUM_WAV_BUFFERS = 3;
const int BufferSamples = int(SampleHz + 0.5);
short wavInBuf[NUM_WAV_BUFFERS][BufferSamples];
void (*waveInRdyCallback)(WAVEHDR* wh);
HWAVEIN hwi;
WAVEHDR wih[NUM_WAV_BUFFERS];
void setMicLevel(int wavInDevID, unsigned short micLevel) {
MMRESULT result;
HMIXER hMixer;
result = mixerOpen(&hMixer, (UINT)wavInDevID, NULL, 0, MIXER_OBJECTF_WAVEIN);
MIXERLINE ml = {0};
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
result = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
MIXERLINECONTROLS mlineControls = {0}; // contains information about the controls of an audio line
MIXERCONTROL controlArray[8] = {0};
mlineControls.dwLineID = ml.dwLineID; // unique audio line identifier
mlineControls.cControls = ml.cControls; // number of controls associated with the line
mlineControls.pamxctrl = controlArray; // points to the first MIXERCONTROL structure to be filled
mlineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mlineControls.cbmxctrl = sizeof(MIXERCONTROL);
// Get information on ALL controls associated with the specified audio line
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlineControls, MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ALL);
// 0: Mute = AGC?? 1: Volume
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
MIXERCONTROLDETAILS mcd = {0};
MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
mcdu.dwValue = 0;
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
result = mixerSetControlDetails((HMIXEROBJ) hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
mcdu.dwValue = micLevel; // 0..65535
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
result = mixerSetControlDetails((HMIXEROBJ) hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
}
void waveInReady(WAVEHDR* wh) {
WAVEHDR whIn = *wh;
MMRESULT res = waveInAddBuffer(hwi, wh, sizeof(WAVEHDR)); // resets WAVEHDR
(*waveInRdyCallback)(&whIn);
}
void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
if (uMsg == WIM_DATA)
waveInReady((WAVEHDR*)dwParam1);
}
void setupAudioIn(const char* deviceName, void (*waveInRdy)(WAVEHDR* wh)) {
waveInRdyCallback = waveInRdy;
int wavInDevID = -1;
int numDevs = waveInGetNumDevs();
for (int devID = 0; devID < numDevs; ++devID) {
WAVEINCAPS wic;
if (waveInGetDevCaps(devID, &wic, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) {
// printf("DeviceID %d: %s\n", devID, wic.szPname);
if (strstr(wic.szPname, deviceName)) {
wavInDevID = devID;
break;
}
}
}
if (wavInDevID == -1) {
printf("Input %s not found\n", deviceName);
return;
}
WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, WAV_IN_CHANNELS,
WAV_IN_SAMPLE_HZ, WAV_IN_SAMPLE_HZ * WAV_IN_CHANNELS * BITS_PER_SAMPLE / 8,
WAV_IN_CHANNELS * BITS_PER_SAMPLE / 8, BITS_PER_SAMPLE, 0};
MMRESULT res = waveInOpen(&hwi, wavInDevID, &wfx, (DWORD_PTR)(VOID*)waveInProc, 0, CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT);
setMicLevel(wavInDevID, MicLevel);
for (int b = 0; b < NUM_WAV_BUFFERS; ++b) {
wih[b].lpData = (LPSTR)wavInBuf[b];
wih[b].dwBufferLength = BufferSamples * WAV_IN_CHANNELS * BITS_PER_SAMPLE / 8;
MMRESULT res = waveInPrepareHeader(hwi, &wih[b], sizeof(WAVEHDR)); // lock buffer
res = waveInAddBuffer(hwi, &wih[b], sizeof(WAVEHDR));
}
}
#define POWER_REQ
HANDLE hPCR;
void startWaveIn() {
MMRESULT res = waveInStart(hwi);
#ifdef POWER_REQ
REASON_CONTEXT reason = {POWER_REQUEST_CONTEXT_VERSION, POWER_REQUEST_CONTEXT_SIMPLE_STRING, };
wchar_t reason_string[] = L"Prevent audio gaps"; // for powercfg -
reason.Reason.SimpleReasonString = reason_string;
HANDLE hPCR = PowerCreateRequest(&reason);
if (!PowerSetRequest(hPCR, PowerRequestExecutionRequired)) printf("PSR error %d\n", GetLastError());
if (!PowerSetRequest(hPCR, PowerRequestDisplayRequired)) printf("PSR error %d\n", GetLastError()); // prevents audio gaps OK
if (!PowerSetRequest(hPCR, PowerRequestSystemRequired)) printf("PSR error %d\n", GetLastError()); // already done by Realtek driver
#endif
// SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED); // don't sleep, run in background
// no help - still get audio buffer discontinuities
}
void stopWaveIn() {
waveInStop(hwi);
for (int b = 0; b < NUM_WAV_BUFFERS; ++b)
waveInUnprepareHeader(hwi, &wih[b], sizeof(WAVEHDR));
#ifdef POWER_REQ
PowerClearRequest(hPCR, PowerRequestExecutionRequired);
PowerClearRequest(hPCR, PowerRequestDisplayRequired);
PowerClearRequest(hPCR, PowerRequestSystemRequired);
CloseHandle(hPCR);
#endif
// SetThreadExecutionState(ES_CONTINUOUS);
}