Skip to content

Commit

Permalink
Host-side implementation of ARC audio bridge.
Browse files Browse the repository at this point in the history
BUG=b:26933097

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

Cr-Commit-Position: refs/heads/master@{#383926}
  • Loading branch information
chinyue authored and Commit bot committed Mar 30, 2016
1 parent b0b70b1 commit beb9aec
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 1 deletion.
3 changes: 2 additions & 1 deletion chromeos/audio/cras_audio_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer,
virtual void SetActiveHDMIOutoutRediscoveringIfNecessary(
bool force_rediscovering);

virtual const AudioDevice* GetDeviceFromId(uint64_t device_id) const;

protected:
explicit CrasAudioHandler(
scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler);
Expand Down Expand Up @@ -260,7 +262,6 @@ class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer,
// Sets up the additional active audio node's state.
void SetupAdditionalActiveAudioNodeState(uint64_t node_id);

const AudioDevice* GetDeviceFromId(uint64_t device_id) const;
const AudioDevice* GetDeviceFromStableDeviceId(
uint64_t stable_device_id) const;
const AudioDevice* GetKeyboardMic() const;
Expand Down
3 changes: 3 additions & 0 deletions components/arc.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
'arc/arc_service.h',
'arc/arc_service_manager.cc',
'arc/arc_service_manager.h',
'arc/audio/arc_audio_bridge.cc',
'arc/audio/arc_audio_bridge.h',
'arc/auth/arc_auth_fetcher.cc',
'arc/auth/arc_auth_fetcher.h',
'arc/clipboard/arc_clipboard_bridge.cc',
Expand Down Expand Up @@ -94,6 +96,7 @@
'sources': [
'arc/common/app.mojom',
'arc/common/arc_bridge.mojom',
'arc/common/audio.mojom',
'arc/common/auth.mojom',
'arc/common/clipboard.mojom',
'arc/common/crash_collector.mojom',
Expand Down
3 changes: 3 additions & 0 deletions components/arc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ static_library("arc") {
"arc_service.h",
"arc_service_manager.cc",
"arc_service_manager.h",
"audio/arc_audio_bridge.cc",
"audio/arc_audio_bridge.h",
"auth/arc_auth_fetcher.cc",
"auth/arc_auth_fetcher.h",
"clipboard/arc_clipboard_bridge.cc",
Expand Down Expand Up @@ -72,6 +74,7 @@ mojom("arc_bindings") {
sources = [
"common/app.mojom",
"common/arc_bridge.mojom",
"common/audio.mojom",
"common/auth.mojom",
"common/clipboard.mojom",
"common/crash_collector.mojom",
Expand Down
26 changes: 26 additions & 0 deletions components/arc/arc_bridge_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ void ArcBridgeService::AddObserver(Observer* observer) {
// them explicitly now to avoid a race.
if (app_instance())
observer->OnAppInstanceReady();
if (audio_instance())
observer->OnAudioInstanceReady();
if (auth_instance())
observer->OnAuthInstanceReady();
if (clipboard_instance())
Expand Down Expand Up @@ -113,6 +115,29 @@ void ArcBridgeService::CloseAppChannel() {
FOR_EACH_OBSERVER(Observer, observer_list(), OnAppInstanceClosed());
}

void ArcBridgeService::OnAudioInstanceReady(AudioInstancePtr audio_ptr) {
DCHECK(CalledOnValidThread());
temporary_audio_ptr_ = std::move(audio_ptr);
temporary_audio_ptr_.QueryVersion(base::Bind(
&ArcBridgeService::OnAudioVersionReady, weak_factory_.GetWeakPtr()));
}

void ArcBridgeService::OnAudioVersionReady(int32_t version) {
DCHECK(CalledOnValidThread());
audio_ptr_ = std::move(temporary_audio_ptr_);
audio_ptr_.set_connection_error_handler(base::Bind(
&ArcBridgeService::CloseAudioChannel, weak_factory_.GetWeakPtr()));
FOR_EACH_OBSERVER(Observer, observer_list(), OnAudioInstanceReady());
}

void ArcBridgeService::CloseAudioChannel() {
if (!audio_ptr_)
return;

audio_ptr_.reset();
FOR_EACH_OBSERVER(Observer, observer_list(), OnAudioInstanceClosed());
}

void ArcBridgeService::OnAuthInstanceReady(AuthInstancePtr auth_ptr) {
DCHECK(CalledOnValidThread());
temporary_auth_ptr_ = std::move(auth_ptr);
Expand Down Expand Up @@ -434,6 +459,7 @@ void ArcBridgeService::CloseAllChannels() {
// Call all the error handlers of all the channels to both close the channel
// and notify any observers that the channel is closed.
CloseAppChannel();
CloseAudioChannel();
CloseAuthChannel();
CloseClipboardChannel();
CloseCrashCollectorChannel();
Expand Down
11 changes: 11 additions & 0 deletions components/arc/arc_bridge_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class ArcBridgeService : public ArcBridgeHost {
virtual void OnAppInstanceReady() {}
virtual void OnAppInstanceClosed() {}

// Called whenever the ARC audio interface state changes.
virtual void OnAudioInstanceReady() {}
virtual void OnAudioInstanceClosed() {}

// Called whenever the ARC auth interface state changes.
virtual void OnAuthInstanceReady() {}
virtual void OnAuthInstanceClosed() {}
Expand Down Expand Up @@ -163,6 +167,7 @@ class ArcBridgeService : public ArcBridgeHost {
// you want to be notified when this is ready. This can only be called on the
// thread that this class was created on.
AppInstance* app_instance() { return app_ptr_.get(); }
AudioInstance* audio_instance() { return audio_ptr_.get(); }
AuthInstance* auth_instance() { return auth_ptr_.get(); }
ClipboardInstance* clipboard_instance() { return clipboard_ptr_.get(); }
CrashCollectorInstance* crash_collector_instance() {
Expand All @@ -183,6 +188,7 @@ class ArcBridgeService : public ArcBridgeHost {
VideoInstance* video_instance() { return video_ptr_.get(); }

int32_t app_version() const { return app_ptr_.version(); }
int32_t audio_version() const { return audio_ptr_.version(); }
int32_t auth_version() const { return auth_ptr_.version(); }
int32_t clipboard_version() const { return clipboard_ptr_.version(); }
int32_t crash_collector_version() const {
Expand All @@ -200,6 +206,7 @@ class ArcBridgeService : public ArcBridgeHost {

// ArcHost:
void OnAppInstanceReady(AppInstancePtr app_ptr) override;
void OnAudioInstanceReady(AudioInstancePtr audio_ptr) override;
void OnAuthInstanceReady(AuthInstancePtr auth_ptr) override;
void OnClipboardInstanceReady(ClipboardInstancePtr clipboard_ptr) override;
void OnCrashCollectorInstanceReady(
Expand Down Expand Up @@ -247,6 +254,7 @@ class ArcBridgeService : public ArcBridgeHost {

// Called when one of the individual channels is closed.
void CloseAppChannel();
void CloseAudioChannel();
void CloseAuthChannel();
void CloseClipboardChannel();
void CloseCrashCollectorChannel();
Expand All @@ -262,6 +270,7 @@ class ArcBridgeService : public ArcBridgeHost {

// Callbacks for QueryVersion.
void OnAppVersionReady(int32_t version);
void OnAudioVersionReady(int32_t version);
void OnAuthVersionReady(int32_t version);
void OnClipboardVersionReady(int32_t version);
void OnCrashCollectorVersionReady(int32_t version);
Expand All @@ -277,6 +286,7 @@ class ArcBridgeService : public ArcBridgeHost {

// Mojo interfaces.
AppInstancePtr app_ptr_;
AudioInstancePtr audio_ptr_;
AuthInstancePtr auth_ptr_;
ClipboardInstancePtr clipboard_ptr_;
CrashCollectorInstancePtr crash_collector_ptr_;
Expand All @@ -297,6 +307,7 @@ class ArcBridgeService : public ArcBridgeHost {
// To keep the xxx_instance() functions being trivial, store the instance
// pointer in a temporary variable to avoid losing its reference.
AppInstancePtr temporary_app_ptr_;
AudioInstancePtr temporary_audio_ptr_;
AuthInstancePtr temporary_auth_ptr_;
ClipboardInstancePtr temporary_clipboard_ptr_;
CrashCollectorInstancePtr temporary_crash_collector_ptr_;
Expand Down
2 changes: 2 additions & 0 deletions components/arc/arc_service_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "base/thread_task_runner_handle.h"
#include "components/arc/arc_bridge_bootstrap.h"
#include "components/arc/arc_bridge_service_impl.h"
#include "components/arc/audio/arc_audio_bridge.h"
#include "components/arc/clipboard/arc_clipboard_bridge.h"
#include "components/arc/crash_collector/arc_crash_collector_bridge.h"
#include "components/arc/ime/arc_ime_service.h"
Expand All @@ -32,6 +33,7 @@ ArcServiceManager::ArcServiceManager()
DCHECK(!g_arc_service_manager);
g_arc_service_manager = this;

AddService(make_scoped_ptr(new ArcAudioBridge(arc_bridge_service())));
AddService(make_scoped_ptr(new ArcClipboardBridge(arc_bridge_service())));
AddService(
make_scoped_ptr(new ArcCrashCollectorBridge(arc_bridge_service())));
Expand Down
3 changes: 3 additions & 0 deletions components/arc/audio/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_rules = [
"+chromeos/audio",
]
66 changes: 66 additions & 0 deletions components/arc/audio/arc_audio_bridge.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/arc/audio/arc_audio_bridge.h"

#include "base/logging.h"
#include "chromeos/audio/audio_device.h"

namespace arc {

ArcAudioBridge::ArcAudioBridge(ArcBridgeService* bridge_service)
: ArcService(bridge_service) {
arc_bridge_service()->AddObserver(this);
if (chromeos::CrasAudioHandler::IsInitialized()) {
cras_audio_handler_ = chromeos::CrasAudioHandler::Get();
cras_audio_handler_->AddAudioObserver(this);
}
}

ArcAudioBridge::~ArcAudioBridge() {
arc_bridge_service()->RemoveObserver(this);
if (cras_audio_handler_ && chromeos::CrasAudioHandler::IsInitialized()) {
cras_audio_handler_->RemoveAudioObserver(this);
}
}

void ArcAudioBridge::OnAudioNodesChanged() {
uint64_t output_id = cras_audio_handler_->GetPrimaryActiveOutputNode();
const chromeos::AudioDevice* output_device =
cras_audio_handler_->GetDeviceFromId(output_id);
bool headphone_inserted =
(output_device &&
output_device->type == chromeos::AudioDeviceType::AUDIO_TYPE_HEADPHONE);

uint64_t input_id = cras_audio_handler_->GetPrimaryActiveInputNode();
const chromeos::AudioDevice* input_device =
cras_audio_handler_->GetDeviceFromId(input_id);
bool microphone_inserted =
(input_device &&
input_device->type == chromeos::AudioDeviceType::AUDIO_TYPE_MIC);

VLOG(1) << "HEADPHONE " << headphone_inserted
<< " MICROPHONE " << microphone_inserted;
SendSwitchState(headphone_inserted, microphone_inserted);
}

void ArcAudioBridge::SendSwitchState(bool headphone_inserted,
bool microphone_inserted) {
uint32_t switch_state = 0;
if (headphone_inserted) {
switch_state |=
(1 << static_cast<uint32_t>(AudioSwitch::SW_HEADPHONE_INSERT));
}
if (microphone_inserted) {
switch_state |=
(1 << static_cast<uint32_t>(AudioSwitch::SW_MICROPHONE_INSERT));
}

VLOG(1) << "Send switch state " << switch_state;
AudioInstance* audio_instance = arc_bridge_service()->audio_instance();
if (audio_instance)
audio_instance->NotifySwitchState(switch_state);
}

} // namespace arc
38 changes: 38 additions & 0 deletions components/arc/audio/arc_audio_bridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_ARC_AUDIO_ARC_AUDIO_BRIDGE_H_
#define COMPONENTS_ARC_AUDIO_ARC_AUDIO_BRIDGE_H_

#include <string>

#include "base/macros.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service.h"
#include "mojo/public/cpp/bindings/binding.h"

namespace arc {

class ArcAudioBridge : public ArcService,
public ArcBridgeService::Observer,
public chromeos::CrasAudioHandler::AudioObserver {
public:
explicit ArcAudioBridge(ArcBridgeService* bridge_service);
~ArcAudioBridge() override;

private:
chromeos::CrasAudioHandler* cras_audio_handler_ = nullptr;

// chromeos::CrasAudioHandler::AudioObserver overrides.
void OnAudioNodesChanged() override;

void SendSwitchState(bool headphone_inserted, bool microphone_inserted);

DISALLOW_COPY_AND_ASSIGN(ArcAudioBridge);
};

} // namespace arc

#endif // COMPONENTS_ARC_AUDIO_ARC_AUDIO_BRIDGE_H_
4 changes: 4 additions & 0 deletions components/arc/common/arc_bridge.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
module arc;

import "app.mojom";
import "audio.mojom";
import "auth.mojom";
import "clipboard.mojom";
import "crash_collector.mojom";
Expand All @@ -26,6 +27,9 @@ interface ArcBridgeHost {
// Notifies Chrome that the AppInstance interface is ready.
OnAppInstanceReady@100(AppInstance instance_ptr);

// Notifies Chrome that the AudioInstance interface is ready.
[MinVersion=8] OnAudioInstanceReady@115(AudioInstance instance_ptr);

// Notifies Chrome that the AuthInstance interface is ready.
[MinVersion=1] OnAuthInstanceReady@106(AuthInstance instance_ptr);

Expand Down
19 changes: 19 additions & 0 deletions components/arc/common/audio.mojom
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module arc;

// Use same switch values as kernel switch events.
[Extensible]
enum AudioSwitch {
SW_HEADPHONE_INSERT = 0x02,
SW_MICROPHONE_INSERT = 0x04
};

interface AudioInstance {
// Notify plug states of headphone, microphone, etc. Each switch state is
// represented by the corresponding bit, if the bit is set then the switch
// is plugged/inserted.
NotifySwitchState(uint32 state);
};

0 comments on commit beb9aec

Please sign in to comment.