Commit 90b9a06c authored by En-Shuo Hsu's avatar En-Shuo Hsu Committed by Commit Bot

Add BluetoothBatteryChanged event and interface

This event and corresponding interface will be used to support battery
indicator for headphone supporting Hands-Free Profile (HFP).

Design doc: go/cros-bt-bi-hfp

BUG=chromium:785758,b:140783217
TEST=build chrome and run chromeos_unittests

Change-Id: Ieda4b83f4aa86f21038e7e6a9e9e5aa2b58cba0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2041970
Auto-Submit: En-Shuo Hsu <enshuo@chromium.org>
Commit-Queue: En-Shuo Hsu <enshuo@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740851}
parent 050fce37
......@@ -90,6 +90,10 @@ void CrasAudioHandler::AudioObserver::OnHotwordTriggered(
uint64_t /* tv_sec */,
uint64_t /* tv_nsec */) {}
void CrasAudioHandler::AudioObserver::OnBluetoothBatteryChanged(
const std::string& /* address */,
uint32_t /* level */) {}
void CrasAudioHandler::AudioObserver::OnOutputStarted() {}
void CrasAudioHandler::AudioObserver::OnOutputStopped() {}
......@@ -764,6 +768,12 @@ void CrasAudioHandler::NumberOfActiveStreamsChanged() {
GetNumberOfOutputStreams();
}
void CrasAudioHandler::BluetoothBatteryChanged(const std::string& address,
uint32_t level) {
for (auto& observer : observers_)
observer.OnBluetoothBatteryChanged(address, level);
}
void CrasAudioHandler::OnAudioPolicyPrefChanged() {
ApplyAudioPolicy();
}
......
......@@ -86,6 +86,15 @@ class COMPONENT_EXPORT(CHROMEOS_AUDIO) CrasAudioHandler
// Called when hotword is detected.
virtual void OnHotwordTriggered(uint64_t tv_sec, uint64_t tv_nsec);
// Called when the battery level change is reported over the Hands-Free
// Profile for a Bluetooth headset.
// The address is a Bluetooth address as 6 bytes written in hexadecimal and
// separated by colons. Example: 00:11:22:33:44:FF
// The level ranges from 0 to 100. Erroneous value reported by the headset
// will be ignored and won't trigger this callback.
virtual void OnBluetoothBatteryChanged(const std::string& address,
uint32_t level);
// Called when an initial output stream is opened.
virtual void OnOutputStarted();
......@@ -316,6 +325,8 @@ class COMPONENT_EXPORT(CHROMEOS_AUDIO) CrasAudioHandler
void ActiveInputNodeChanged(uint64_t node_id) override;
void OutputNodeVolumeChanged(uint64_t node_id, int volume) override;
void HotwordTriggered(uint64_t tv_sec, uint64_t tv_nsec) override;
void BluetoothBatteryChanged(const std::string& address,
uint32_t level) override;
void NumberOfActiveStreamsChanged() override;
// AudioPrefObserver overrides.
......
......@@ -105,6 +105,15 @@ class CrasAudioClientImpl : public CrasAudioClient {
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&CrasAudioClientImpl::SignalConnected,
weak_ptr_factory_.GetWeakPtr()));
// Monitor the D-Bus signal for changes in Bluetooth headset battery level.
cras_proxy_->ConnectToSignal(
cras::kCrasControlInterface, cras::kBluetoothBatteryChanged,
base::BindRepeating(
&CrasAudioClientImpl::BluetoothBatteryChangedReceived,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&CrasAudioClientImpl::SignalConnected,
weak_ptr_factory_.GetWeakPtr()));
}
~CrasAudioClientImpl() override = default;
......@@ -424,6 +433,24 @@ class CrasAudioClientImpl : public CrasAudioClient {
observer.NumberOfActiveStreamsChanged();
}
void BluetoothBatteryChangedReceived(dbus::Signal* signal) {
dbus::MessageReader reader(signal);
std::string address;
uint32_t level;
if (!reader.PopString(&address)) {
LOG(ERROR) << "Error reading signal from cras:" << signal->ToString();
return;
}
if (!reader.PopUint32(&level)) {
LOG(ERROR) << "Error reading signal from cras:" << signal->ToString();
return;
}
for (auto& observer : observers_)
observer.BluetoothBatteryChanged(address, level);
}
void OnGetVolumeState(DBusMethodCallback<VolumeState> callback,
dbus::Response* response) {
if (!response) {
......@@ -667,6 +694,10 @@ void CrasAudioClient::Observer::HotwordTriggered(uint64_t tv_sec,
void CrasAudioClient::Observer::NumberOfActiveStreamsChanged() {}
void CrasAudioClient::Observer::BluetoothBatteryChanged(
const std::string& address,
uint32_t level) {}
CrasAudioClient::CrasAudioClient() {
DCHECK(!g_instance);
g_instance = this;
......
......@@ -58,6 +58,10 @@ class COMPONENT_EXPORT(DBUS_AUDIO) CrasAudioClient {
// Called when the number of active output streams has changed.
virtual void NumberOfActiveStreamsChanged();
// Called when the battery level for a Bluetooth headset changed.
virtual void BluetoothBatteryChanged(const std::string& address,
uint32_t level);
protected:
virtual ~Observer();
};
......
......@@ -94,6 +94,8 @@ class MockObserver : public CrasAudioClient::Observer {
MOCK_METHOD2(OutputNodeVolumeChanged, void(uint64_t node_id, int volume));
MOCK_METHOD2(HotwordTriggered, void(uint64_t tv_sec, uint64_t tv_nsec));
MOCK_METHOD0(NumberOfActiveStreamsChanged, void());
MOCK_METHOD2(BluetoothBatteryChanged,
void(const std::string& address, uint32_t level));
};
// Expect the reader to be empty.
......@@ -349,6 +351,15 @@ class CrasAudioClientTest : public testing::Test {
.WillRepeatedly(
Invoke(this, &CrasAudioClientTest::OnNumberOfActiveStreamsChanged));
// Set an expectation so mock_cras_proxy's monitoring
// BluetoothBatteryChanged ConnectToSignal will use
// OnBluetoothBatteryChanged() to run the callback.
EXPECT_CALL(*mock_cras_proxy_.get(),
DoConnectToSignal(interface_name_,
cras::kBluetoothBatteryChanged, _, _))
.WillRepeatedly(
Invoke(this, &CrasAudioClientTest::OnBluetoothBatteryChanged));
// Set an expectation so mock_bus's GetObjectProxy() for the given
// service name and the object path will return mock_cras_proxy_.
EXPECT_CALL(*mock_bus_.get(),
......@@ -432,6 +443,12 @@ class CrasAudioClientTest : public testing::Test {
number_of_active_streams_changed_handler_.Run(signal);
}
// Send Bluetooth battery changed signal to the tested client.
void SendBluetoothBatteryChangedSignal(dbus::Signal* signal) {
ASSERT_FALSE(bluetooth_battery_changed_handler_.is_null());
bluetooth_battery_changed_handler_.Run(signal);
}
CrasAudioClient* client() { return CrasAudioClient::Get(); }
// The interface name.
......@@ -459,6 +476,8 @@ class CrasAudioClientTest : public testing::Test {
dbus::ObjectProxy::SignalCallback hotword_triggered_handler_;
// The NumberOfActiveStreamsChanged signal handler given by the tested client.
dbus::ObjectProxy::SignalCallback number_of_active_streams_changed_handler_;
// The BluetoothBatteryChanged signal handler given by the tested client.
dbus::ObjectProxy::SignalCallback bluetooth_battery_changed_handler_;
// The name of the method which is expected to be called.
std::string expected_method_name_;
// The response which the mock cras proxy returns.
......@@ -579,6 +598,20 @@ class CrasAudioClientTest : public testing::Test {
interface_name, signal_name, success));
}
// Checks the requested interface name and signal name.
// Used to implement the mock cras proxy.
void OnBluetoothBatteryChanged(
const std::string& interface_name,
const std::string& signal_name,
const dbus::ObjectProxy::SignalCallback& signal_callback,
dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
bluetooth_battery_changed_handler_ = signal_callback;
const bool success = true;
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(std::move(*on_connected_callback),
interface_name, signal_name, success));
}
// Checks the content of the method call and returns the response.
// Used to implement the mock cras proxy.
void OnCallMethod(dbus::MethodCall* method_call,
......@@ -709,6 +742,31 @@ TEST_F(CrasAudioClientTest, NumberOfActiveStreamsChanged) {
base::RunLoop().RunUntilIdle();
}
TEST_F(CrasAudioClientTest, BluetoothBatteryChanged) {
const std::string address = "11:22:33:44:55:66";
const uint32_t level = 82;
dbus::Signal signal(cras::kCrasControlInterface,
cras::kBluetoothBatteryChanged);
dbus::MessageWriter writer(&signal);
writer.AppendString(address);
writer.AppendUint32(level);
MockObserver observer;
EXPECT_CALL(observer, BluetoothBatteryChanged(address, level)).Times(1);
client()->AddObserver(&observer);
SendBluetoothBatteryChangedSignal(&signal);
client()->RemoveObserver(&observer);
EXPECT_CALL(observer, BluetoothBatteryChanged(_, _)).Times(0);
// Run the signal callback again and make sure the observer isn't called.
SendBluetoothBatteryChangedSignal(&signal);
base::RunLoop().RunUntilIdle();
}
TEST_F(CrasAudioClientTest, NodesChanged) {
// Create a signal.
dbus::Signal signal(cras::kCrasControlInterface, cras::kNodesChanged);
......
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