Commit 4519c32f authored by Oskar Sundbom's avatar Oskar Sundbom Committed by Commit Bot

PulseAudio: Filter out unavailable inputs and refuse to open monitor inputs

If there are no available inputs, PulseAudio will, for some reason,
select the monitor of the current default sink as the default source.
Chrome will only add a Default input to the device enumeration if
there is at least one valid input found. Currently, we also include
unavailable inputs in the device enumeration, which means Chrome will
show a Default device, which in that case would likely be a monitor
device, rather than a proper input.

This CL stops this happening by not enumerating inputs that don't have
an available, active port. In case PulseAudio would _still_ pick a
monitor device as the default device, this CL also explicitly returns
invalid AudioParameters for monitor devices, and explicitly fails to
open them as inputs - to be on the safe side.

Bug: b/79580580
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I25bd96e98a48bcdf6e993759e97bf713855d4ad0
Reviewed-on: https://chromium-review.googlesource.com/1064373
Commit-Queue: Oskar Sundbom <ossu@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#562383}
parent a0bcd85d
......@@ -43,7 +43,8 @@ AudioManagerPulse::AudioManagerPulse(std::unique_ptr<AudioThread> audio_thread,
input_context_(pa_context),
devices_(NULL),
native_input_sample_rate_(0),
native_channel_count_(0) {
native_channel_count_(0),
default_source_is_monitor_(false) {
DCHECK(input_mainloop_);
DCHECK(input_context_);
SetMaxOutputStreamsAllowed(kMaxOutputStreams);
......@@ -110,6 +111,12 @@ AudioParameters AudioManagerPulse::GetInputStreamParameters(
// TODO(xians): add support for querying native channel layout for pulse.
UpdateNativeAudioHardwareInfo();
// We don't want to accidentally open a monitor device, so return invalid
// parameters for those.
if (device_id == AudioDeviceDescription::kDefaultDeviceId &&
default_source_is_monitor_) {
return AudioParameters();
}
return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_STEREO, native_input_sample_rate_,
buffer_size);
......@@ -246,6 +253,10 @@ void AudioManagerPulse::UpdateNativeAudioHardwareInfo() {
pa_operation* operation = pa_context_get_server_info(
input_context_, AudioHardwareInfoCallback, this);
WaitForOperationCompletion(input_mainloop_, operation);
operation = pa_context_get_source_info_by_name(
input_context_, default_source_name_.c_str(), DefaultSourceInfoCallback,
this);
WaitForOperationCompletion(input_mainloop_, operation);
}
void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
......@@ -259,11 +270,19 @@ void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
return;
}
// Exclude the output devices.
if (info->monitor_of_sink == PA_INVALID_INDEX) {
manager->devices_->push_back(AudioDeviceName(info->description,
info->name));
}
// Exclude output monitor (i.e. loopback) devices.
if (info->monitor_of_sink != PA_INVALID_INDEX)
return;
// Exclude devices that don't have an available active port (i.e it's
// unplugged). Such devices won't be picked (by pulseaudio) as default device,
// and if we have no available devices we don't want to add a default device
// to enumerations either.
if (!info->active_port ||
info->active_port->available == PA_PORT_AVAILABLE_NO)
return;
manager->devices_->push_back(AudioDeviceName(info->description, info->name));
}
void AudioManagerPulse::OutputDevicesInfoCallback(pa_context* context,
......@@ -288,7 +307,24 @@ void AudioManagerPulse::AudioHardwareInfoCallback(pa_context* context,
manager->native_input_sample_rate_ = info->sample_spec.rate;
manager->native_channel_count_ = info->sample_spec.channels;
manager->default_source_name_ = info->default_source_name;
pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
}
void AudioManagerPulse::DefaultSourceInfoCallback(pa_context* context,
const pa_source_info* info,
int eol,
void* user_data) {
AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
if (eol) {
// Signal the pulse object that it is done.
pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
return;
}
DCHECK(info);
manager->default_source_is_monitor_ =
info->monitor_of_sink != PA_INVALID_INDEX;
}
} // namespace media
......@@ -55,6 +55,8 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
std::string GetAssociatedOutputDeviceID(
const std::string& input_device_id) override;
bool DefaultSourceIsMonitor() const { return default_source_is_monitor_; }
protected:
void ShutdownOnAudioThread() override;
AudioParameters GetPreferredOutputStreamParameters(
......@@ -78,6 +80,11 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
const pa_server_info* info,
void* user_data);
static void DefaultSourceInfoCallback(pa_context* context,
const pa_source_info* info,
int eol,
void* user_data);
// Called by MakeLinearOutputStream and MakeLowLatencyOutputStream.
AudioOutputStream* MakeOutputStream(const AudioParameters& params,
const std::string& device_id);
......@@ -94,6 +101,8 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
AudioDeviceNames* devices_;
int native_input_sample_rate_;
int native_channel_count_;
std::string default_source_name_;
bool default_source_is_monitor_;
DISALLOW_COPY_AND_ASSIGN(AudioManagerPulse);
};
......
......@@ -21,6 +21,7 @@ int pa_context_connect(pa_context* c, const char* server, pa_context_flags_t fla
void pa_context_disconnect(pa_context* c);
pa_operation* pa_context_get_server_info(pa_context* c, pa_server_info_cb_t cb, void* userdata);
pa_operation* pa_context_get_source_info_by_index(pa_context* c, uint32_t idx, pa_source_info_cb_t cb, void* userdata);
pa_operation* pa_context_get_source_info_by_name(pa_context* c, const char* name, pa_source_info_cb_t cb, void *userdata);
pa_operation* pa_context_get_source_info_list(pa_context* c, pa_source_info_cb_t cb, void* userdata);
pa_operation* pa_context_get_sink_info_list(pa_context* c, pa_sink_info_cb_t cb, void* userdata);
pa_context_state_t pa_context_get_state(pa_context* c);
......
......@@ -52,6 +52,10 @@ PulseAudioInputStream::~PulseAudioInputStream() {
bool PulseAudioInputStream::Open() {
DCHECK(thread_checker_.CalledOnValidThread());
if (device_name_ == AudioDeviceDescription::kDefaultDeviceId &&
audio_manager_->DefaultSourceIsMonitor())
return false;
AutoPulseLock auto_lock(pa_mainloop_);
if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_,
device_name_, &StreamNotifyCallback, this)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment