Commit 9367e039 authored by tommi@chromium.org's avatar tommi@chromium.org

Hook up AudioDeviceListenerWin to monitor all default device changes.

In addition to the current functionality, this adds:
* Detection of default capture devices (communication and console).
* Detection of changes to the default communication render device.

While doing this, I decided to also make 'effects' visible in the media-internals page which was very helpful in tracking down the source of the problem I was running into.

BUG=347531

Review URL: https://codereview.chromium.org/187593004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255687 0039d316-1c4b-4281-b951-d872f2087c98
parent 83fc639b
......@@ -5,6 +5,7 @@
#include "content/browser/media/media_internals.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_ui.h"
......@@ -23,6 +24,37 @@ base::string16 SerializeUpdate(const std::string& function,
function, std::vector<const base::Value*>(1, value));
}
std::string EffectsToString(int effects) {
if (effects == media::AudioParameters::NO_EFFECTS)
return "NO_EFFECTS";
struct {
int flag;
const char* name;
} flags[] = {
{ media::AudioParameters::ECHO_CANCELLER, "ECHO_CANCELLER" },
{ media::AudioParameters::DUCKING, "DUCKING" },
};
std::string ret;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flags); ++i) {
if (effects & flags[i].flag) {
if (!ret.empty())
ret += " | ";
ret += flags[i].name;
effects &= ~flags[i].flag;
}
}
if (effects) {
if (!ret.empty())
ret += " | ";
ret += base::IntToString(effects);
}
return ret;
}
const char kAudioLogStatusKey[] = "status";
const char kAudioLogUpdateFunction[] = "media.updateAudioComponent";
......@@ -83,6 +115,7 @@ void AudioLogImpl::OnCreated(int component_id,
dict.SetInteger("channels", params.channels());
dict.SetString("channel_layout",
ChannelLayoutToString(params.channel_layout()));
dict.SetString("effects", EffectsToString(params.effects()));
media_internals_->SendUpdateAndCache(
FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
......
......@@ -30,9 +30,12 @@ class MediaInternalsTest
base::Unretained(this))),
test_params_(media::AudioParameters::AUDIO_PCM_LINEAR,
media::CHANNEL_LAYOUT_MONO,
0,
48000,
16,
128),
128,
media::AudioParameters::ECHO_CANCELLER |
media::AudioParameters::DUCKING),
test_component_(GetParam()),
audio_log_(media_internals_->CreateAudioLog(test_component_)) {
media_internals_->AddUpdateCallback(update_cb_);
......@@ -95,6 +98,7 @@ TEST_P(MediaInternalsTest, AudioLogCreateStartStopErrorClose) {
ExpectInt("frames_per_buffer", test_params_.frames_per_buffer());
ExpectInt("channels", test_params_.channels());
ExpectInt("input_channels", test_params_.input_channels());
ExpectString("effects", "ECHO_CANCELLER | DUCKING");
ExpectString("device_id", kTestDeviceID);
ExpectInt("component_id", kTestComponentID);
ExpectInt("component_type", test_component_);
......
......@@ -30,6 +30,27 @@ static std::string RoleToString(ERole role) {
}
}
static std::string GetDeviceId(EDataFlow flow,
ERole role) {
ScopedComPtr<IMMDevice> device =
CoreAudioUtil::CreateDefaultDevice(flow, role);
if (!device) {
// Most probable reason for ending up here is that all audio devices are
// disabled or unplugged.
DVLOG(1) << "CoreAudioUtil::CreateDefaultDevice failed. No device?";
return std::string();
}
AudioDeviceName device_name;
HRESULT hr = CoreAudioUtil::GetDeviceName(device, &device_name);
if (FAILED(hr)) {
DVLOG(1) << "Failed to retrieve the device id: " << std::hex << hr;
return std::string();
}
return device_name.unique_id;
}
AudioDeviceListenerWin::AudioDeviceListenerWin(const base::Closure& listener_cb)
: listener_cb_(listener_cb) {
CHECK(CoreAudioUtil::IsSupported());
......@@ -48,22 +69,12 @@ AudioDeviceListenerWin::AudioDeviceListenerWin(const base::Closure& listener_cb)
device_enumerator_ = device_enumerator;
ScopedComPtr<IMMDevice> device =
CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
if (!device) {
// Most probable reason for ending up here is that all audio devices are
// disabled or unplugged.
VLOG(1) << "CoreAudioUtil::CreateDefaultDevice failed. No device?";
return;
}
AudioDeviceName device_name;
hr = CoreAudioUtil::GetDeviceName(device, &device_name);
if (FAILED(hr)) {
VLOG(1) << "Failed to retrieve the device id: " << std::hex << hr;
return;
}
default_render_device_id_ = device_name.unique_id;
default_render_device_id_ = GetDeviceId(eRender, eConsole);
default_capture_device_id_ = GetDeviceId(eCapture, eConsole);
default_communications_render_device_id_ =
GetDeviceId(eRender, eCommunications);
default_communications_capture_device_id_ =
GetDeviceId(eCapture, eCommunications);
}
AudioDeviceListenerWin::~AudioDeviceListenerWin() {
......@@ -126,9 +137,24 @@ STDMETHODIMP AudioDeviceListenerWin::OnDeviceStateChanged(LPCWSTR device_id,
STDMETHODIMP AudioDeviceListenerWin::OnDefaultDeviceChanged(
EDataFlow flow, ERole role, LPCWSTR new_default_device_id) {
// Only listen for output device changes right now...
if (flow != eConsole && role != eRender)
// Only listen for console and communication device changes.
if ((role != eConsole && role != eCommunications) ||
(flow != eRender && flow != eCapture)) {
return S_OK;
}
// Grab a pointer to the appropriate ID member.
// Note that there are three "?:"'s here to select the right ID.
std::string* current_device_id =
role == eRender ? (
flow == eConsole ?
&default_render_device_id_ :
&default_communications_render_device_id_
) : (
flow == eConsole ?
&default_capture_device_id_ :
&default_communications_capture_device_id_
);
// If no device is now available, |new_default_device_id| will be NULL.
std::string new_device_id;
......@@ -146,10 +172,11 @@ STDMETHODIMP AudioDeviceListenerWin::OnDefaultDeviceChanged(
// TODO(dalecurtis): This still seems to fire an extra event on my machine for
// an unplug event (probably others too); e.g., we get two transitions to a
// new default device id.
if (new_device_id.compare(default_render_device_id_) == 0)
if (new_device_id.compare(*current_device_id) == 0)
return S_OK;
default_render_device_id_ = new_device_id;
// Store the new id in the member variable (that current_device_id points to).
*current_device_id = new_device_id;
listener_cb_.Run();
return S_OK;
......
......@@ -49,6 +49,9 @@ class MEDIA_EXPORT AudioDeviceListenerWin : public IMMNotificationClient {
base::Closure listener_cb_;
ScopedComPtr<IMMDeviceEnumerator> device_enumerator_;
std::string default_render_device_id_;
std::string default_capture_device_id_;
std::string default_communications_render_device_id_;
std::string default_communications_capture_device_id_;
// AudioDeviceListenerWin must be constructed and destructed on one thread.
base::ThreadChecker thread_checker_;
......
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