-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathAudioCaptureImpl_SDL.cpp
159 lines (129 loc) · 4.77 KB
/
AudioCaptureImpl_SDL.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
#include "AudioCaptureImpl_SDL.h"
#include <Poco/Util/Application.h>
#include <projectM-4/projectM.h>
AudioCaptureImpl::AudioCaptureImpl()
: _requestedSampleCount(projectm_pcm_get_max_samples())
{
auto targetFps = Poco::Util::Application::instance().config().getUInt("projectM.fps", 60);
if (targetFps > 0)
{
_requestedSampleCount = std::min(_requestedSampleFrequency / targetFps, _requestedSampleCount);
// Don't let the buffer get too small to prevent excessive updates calls.
// 300 samples is enough for 144 FPS.
_requestedSampleCount = std::max(_requestedSampleCount, 300U);
}
#ifdef SDL_HINT_AUDIO_INCLUDE_MONITORS
SDL_SetHint(SDL_HINT_AUDIO_INCLUDE_MONITORS, "1");
#endif
SDL_InitSubSystem(SDL_INIT_AUDIO);
}
AudioCaptureImpl::~AudioCaptureImpl()
{
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
std::map<int, std::string> AudioCaptureImpl::AudioDeviceList()
{
std::map<int, std::string> deviceList{
{-1, "Default capturing device"}};
auto recordingDeviceCount = SDL_GetNumAudioDevices(true);
for (int i = 0; i < recordingDeviceCount; i++)
{
auto deviceName = SDL_GetAudioDeviceName(i, true);
if (deviceName)
{
deviceList.insert(std::make_pair(i, deviceName));
}
else
{
poco_error_f2(_logger, "Could not get device name for device ID %d: %s", i, std::string(SDL_GetError()));
}
}
return deviceList;
}
void AudioCaptureImpl::StartRecording(projectm* projectMHandle, int audioDeviceIndex)
{
_projectMHandle = projectMHandle;
_currentAudioDeviceIndex = audioDeviceIndex;
if (OpenAudioDevice())
{
SDL_PauseAudioDevice(_currentAudioDeviceID, false);
poco_debug(_logger, "Started audio recording.");
}
}
void AudioCaptureImpl::StopRecording()
{
if (_currentAudioDeviceID)
{
SDL_PauseAudioDevice(_currentAudioDeviceID, true);
SDL_CloseAudioDevice(_currentAudioDeviceID);
_currentAudioDeviceID = 0;
poco_debug(_logger, "Stopped audio recording and closed device.");
}
}
void AudioCaptureImpl::NextAudioDevice()
{
StopRecording();
// Will wrap around to default capture device (-1).
int nextAudioDeviceId = ((_currentAudioDeviceIndex + 2) % (SDL_GetNumAudioDevices(true) + 1)) - 1;
StartRecording(_projectMHandle, nextAudioDeviceId);
}
void AudioCaptureImpl::AudioDeviceIndex(int index)
{
if (index >= -1 && index < SDL_GetNumAudioDevices(true))
{
_currentAudioDeviceIndex = index;
StartRecording(_projectMHandle, index);
}
}
int AudioCaptureImpl::AudioDeviceIndex() const
{
return _currentAudioDeviceIndex;
}
std::string AudioCaptureImpl::AudioDeviceName() const
{
if (_currentAudioDeviceIndex >= 0)
{
return SDL_GetAudioDeviceName(_currentAudioDeviceIndex, true);
}
else
{
return "Default capturing device";
}
}
bool AudioCaptureImpl::OpenAudioDevice()
{
SDL_AudioSpec requestedSpecs{};
SDL_AudioSpec actualSpecs{};
requestedSpecs.freq = _requestedSampleFrequency;
requestedSpecs.format = AUDIO_F32;
requestedSpecs.channels = 2;
requestedSpecs.samples = _requestedSampleCount;
requestedSpecs.callback = AudioCaptureImpl::AudioInputCallback;
requestedSpecs.userdata = this;
// Will be NULL on error, which happens if the requested index is -1. This automatically selects the default device.
auto deviceName = SDL_GetAudioDeviceName(_currentAudioDeviceIndex, true);
_currentAudioDeviceID = SDL_OpenAudioDevice(deviceName, true, &requestedSpecs, &actualSpecs, 0);
if (_currentAudioDeviceID == 0)
{
poco_error_f3(_logger, R"(Failed to open audio device "%s" (ID %?d): %s)",
std::string(deviceName != nullptr ? deviceName : "System default capturing device"),
_currentAudioDeviceIndex,
std::string(SDL_GetError()));
return false;
}
_channels = actualSpecs.channels;
poco_information_f4(_logger, R"(Opened audio recording device "%s" (ID %?d) with %?d channels at %?d Hz.)",
std::string(deviceName != nullptr ? deviceName : "System default capturing device"),
_currentAudioDeviceIndex,
actualSpecs.channels,
actualSpecs.freq);
return true;
}
void AudioCaptureImpl::AudioInputCallback(void* userData, unsigned char* stream, int len)
{
poco_assert_dbg(userData);
auto instance = reinterpret_cast<AudioCaptureImpl*>(userData);
unsigned int samples = len / sizeof(float) / instance->_channels;
projectm_pcm_add_float(instance->_projectMHandle, reinterpret_cast<float*>(stream), samples,
static_cast<projectm_channels>(instance->_channels));
}