1// 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
122