blob: f764f1a8a5a94c36b5435bde60209d12e156c8eb [file] [log] [blame]
Ralph Nathan5e788b52016-01-07 15:10:32 -08001// Copyright 2016 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16// Implementation of audio_daemon.h.
17
18#include "audio_daemon.h"
19
20#include <sysexits.h>
21
22#include <base/bind.h>
23#include <base/files/file_enumerator.h>
24#include <base/files/file_path.h>
25#include <base/time/time.h>
26#include <binderwrapper/binder_wrapper.h>
27#include <linux/input.h>
28
29namespace brillo {
30
31static const char kAPSServiceName[] = "media.audio_policy";
32static const char kInputDeviceDir[] = "/dev/input";
33
34void AudioDaemon::InitializeHandler() {
35 // Start and initialize the audio device handler.
36 audio_device_handler_ =
37 std::unique_ptr<AudioDeviceHandler>(new AudioDeviceHandler());
38 audio_device_handler_->Init(aps_);
39
40 // Poll on all files in kInputDeviceDir.
41 base::FileEnumerator fenum(base::FilePath(kInputDeviceDir),
42 false /*recursive*/, base::FileEnumerator::FILES);
43 for (base::FilePath name = fenum.Next(); !name.empty(); name = fenum.Next()) {
44 base::File file(name, base::File::FLAG_OPEN | base::File::FLAG_READ);
45 if (file.IsValid()) {
46 MessageLoop* message_loop = MessageLoop::current();
47 int fd = file.GetPlatformFile();
48 // Move file to files_ and ensure that when binding we get a pointer from
49 // the object in files_.
50 files_.emplace(std::move(file));
51 base::Closure callback =
52 base::Bind(&AudioDaemon::Callback, weak_ptr_factory_.GetWeakPtr(),
53 &files_.top());
54 message_loop->WatchFileDescriptor(fd, MessageLoop::kWatchRead,
55 true /*persistent*/, callback);
56 } else {
57 LOG(WARNING) << "Could not open " << name.value() << " for reading. ("
58 << base::File::ErrorToString(file.error_details()) << ")";
59 }
60 }
61 handler_initialized_ = true;
62}
63
64void AudioDaemon::ConnectToAPS() {
65 android::BinderWrapper* binder_wrapper = android::BinderWrapper::Get();
66 auto binder = binder_wrapper->GetService(kAPSServiceName);
67 // If we didn't get the audio policy service, try again in 500 ms.
68 if (!binder.get()) {
69 LOG(INFO) << "Could not connect to audio policy service. Trying again...";
70 brillo::MessageLoop::current()->PostDelayedTask(
71 base::Bind(&AudioDaemon::ConnectToAPS, weak_ptr_factory_.GetWeakPtr()),
72 base::TimeDelta::FromMilliseconds(500));
73 return;
74 }
75 LOG(INFO) << "Connected to audio policy service.";
76 binder_wrapper->RegisterForDeathNotifications(
77 binder,
78 base::Bind(&AudioDaemon::OnAPSDisconnected,
79 weak_ptr_factory_.GetWeakPtr()));
80 VLOG(1) << "Registered death notification.";
81 aps_ = android::interface_cast<android::IAudioPolicyService>(binder);
82 if (!handler_initialized_)
83 InitializeHandler();
84 else
85 audio_device_handler_->APSConnect(aps_);
86}
87
88void AudioDaemon::OnAPSDisconnected() {
89 LOG(INFO) << "Audio policy service died. Will try to reconnect.";
90 audio_device_handler_->APSDisconnect();
91 aps_ = nullptr;
92 ConnectToAPS();
93}
94
95// OnInit, we want to do the following:
96// - Get a binder to the audio policy service.
97// - Initialize the audio device handler.
98// - Set up polling on files in /dev/input.
99int AudioDaemon::OnInit() {
100 int exit_code = Daemon::OnInit();
101 if (exit_code != EX_OK) return exit_code;
102 // Initialize a binder wrapper.
103 android::BinderWrapper::Create();
104 // Initialize a binder watcher.
105 binder_watcher_.Init();
106 ConnectToAPS();
107 return EX_OK;
108}
109
110void AudioDaemon::Callback(base::File* file) {
111 input_event event;
112 int bytes_read =
113 file->ReadAtCurrentPos(reinterpret_cast<char*>(&event), sizeof(event));
114 if (bytes_read != sizeof(event)) {
115 LOG(WARNING) << "Couldn't read an input event.";
116 return;
117 }
118 audio_device_handler_->ProcessEvent(event);
119}
120
121} // namespace brillo