Added automated channel detection for speaker devices

This commit is contained in:
WolverinDEV 2021-03-27 21:25:16 +01:00
parent da07595337
commit 768e9b7bbb
5 changed files with 30 additions and 10 deletions

View File

@ -217,7 +217,10 @@ namespace tc::audio {
bool AudioDeviceRecord::start(std::string &error) { bool AudioDeviceRecord::start(std::string &error) {
std::lock_guard lock{this->state_lock}; std::lock_guard lock{this->state_lock};
if(this->running && !this->stream_invalid) return true; if(this->running && !this->stream_invalid) {
return true;
}
if(this->stream_invalid) { if(this->stream_invalid) {
this->impl_stop(); this->impl_stop();
this->running = false; this->running = false;

View File

@ -92,8 +92,9 @@ namespace tc::audio::pa {
} }
std::lock_guard lock{this->io_lock}; std::lock_guard lock{this->io_lock};
if(!this->_playback) if(!this->_playback) {
this->_playback = std::make_shared<PortAudioPlayback>(this->_index, this->_info); this->_playback = std::make_shared<PortAudioPlayback>(this->_index, this->_info);
}
return this->_playback; return this->_playback;
} }

View File

@ -28,6 +28,8 @@ namespace tc::audio::pa {
PaDeviceIndex index; PaDeviceIndex index;
const PaDeviceInfo* info; const PaDeviceInfo* info;
PaStream* stream{nullptr}; PaStream* stream{nullptr};
size_t source_channel_count{0};
}; };
class PortAudioRecord : public AudioDeviceRecord { class PortAudioRecord : public AudioDeviceRecord {

View File

@ -32,7 +32,8 @@ bool PortAudioPlayback::impl_start(std::string &error) {
unsigned long frameCount, unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo, const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags, PaStreamCallbackFlags statusFlags,
void *userData) { void *userData
) {
assert(output); assert(output);
auto player = reinterpret_cast<PortAudioPlayback*>(userData); auto player = reinterpret_cast<PortAudioPlayback*>(userData);
@ -44,10 +45,19 @@ bool PortAudioPlayback::impl_start(std::string &error) {
PaStreamParameters parameters{}; PaStreamParameters parameters{};
memset(&parameters, 0, sizeof(parameters)); memset(&parameters, 0, sizeof(parameters));
parameters.channelCount = (int) kChannelCount;
parameters.device = this->index; parameters.device = this->index;
parameters.sampleFormat = paFloat32; parameters.sampleFormat = paFloat32;
parameters.suggestedLatency = this->info->defaultLowInputLatency; parameters.suggestedLatency = this->info->defaultLowInputLatency;
if(this->info->maxOutputChannels < kChannelCount) {
parameters.channelCount = (int) 1;
this->source_channel_count = 1;
} else {
parameters.channelCount = (int) kChannelCount;
this->source_channel_count = kChannelCount;
}
log_debug(category::audio, "Opening playback device {} (MaxChannels: {}, Channels: {})", this->info->name, this->info->maxOutputChannels, this->source_channel_count);
auto err = Pa_OpenStream( auto err = Pa_OpenStream(
&this->stream, &this->stream,
nullptr, nullptr,
@ -56,7 +66,8 @@ bool PortAudioPlayback::impl_start(std::string &error) {
(unsigned long) (kSampleRate * kTimeSpan), (unsigned long) (kSampleRate * kTimeSpan),
paClipOff, paClipOff,
proxied_write_callback, proxied_write_callback,
this); this
);
if(err != paNoError) { if(err != paNoError) {
this->stream = nullptr; this->stream = nullptr;
@ -68,20 +79,23 @@ bool PortAudioPlayback::impl_start(std::string &error) {
if(err != paNoError) { if(err != paNoError) {
error = std::string{Pa_GetErrorText(err)} + "(start stream: " + std::to_string(err) + ")"; error = std::string{Pa_GetErrorText(err)} + "(start stream: " + std::to_string(err) + ")";
err = Pa_CloseStream(this->stream); err = Pa_CloseStream(this->stream);
if(err != paNoError) if(err != paNoError) {
log_critical(category::audio, tr("Failed to close opened pa stream. This will cause memory leaks. Error: {}/{}"), err, Pa_GetErrorText(err)); log_critical(category::audio, tr("Failed to close opened pa stream. This will cause memory leaks. Error: {}/{}"), err, Pa_GetErrorText(err));
}
return false; return false;
} }
return true; return true;
} }
void PortAudioPlayback::impl_stop() { void PortAudioPlayback::impl_stop() {
if(Pa_IsStreamActive(this->stream)) if(Pa_IsStreamActive(this->stream)) {
Pa_AbortStream(this->stream); Pa_AbortStream(this->stream);
}
auto error = Pa_CloseStream(this->stream); auto error = Pa_CloseStream(this->stream);
if(error != paNoError) if(error != paNoError) {
log_error(category::audio, tr("Failed to close PA stream: {}"), error); log_error(category::audio, tr("Failed to close PA stream: {}"), error);
}
this->stream = nullptr; this->stream = nullptr;
} }
@ -91,5 +105,5 @@ size_t PortAudioPlayback::sample_rate() const {
void PortAudioPlayback::write_callback(void *output, unsigned long frameCount, void PortAudioPlayback::write_callback(void *output, unsigned long frameCount,
const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) { const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) {
this->fill_buffer(output, frameCount, kChannelCount); this->fill_buffer(output, frameCount, this->source_channel_count);
} }

View File

@ -49,7 +49,7 @@ bool PortAudioRecord::impl_start(std::string &error) {
parameters.channelCount = (int) kChannelCount; parameters.channelCount = (int) kChannelCount;
this->source_channel_count = kChannelCount; this->source_channel_count = kChannelCount;
} }
log_debug(category::audio, "Opening device {} (MaxChannels: {}, MinChannels: {}, Channels: {})", this->info->name, this->info->maxInputChannels, this->info->maxInputChannels, this->source_channel_count); log_debug(category::audio, "Opening record device {} (MaxChannels: {}, Channels: {})", this->info->name, this->info->maxInputChannels, this->source_channel_count);
parameters.device = this->index; parameters.device = this->index;
parameters.sampleFormat = paFloat32; parameters.sampleFormat = paFloat32;