summaryrefslogtreecommitdiff
path: root/system/audio_bluetooth_hw/device_port_proxy.h
blob: dab4970ca6c9e56fa3aa85ddf25c1130e790f99b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
#include <hardware/audio.h>

#include <condition_variable>
#include <mutex>
#include <unordered_map>

enum class BluetoothStreamState : uint8_t;

namespace android {
namespace bluetooth {
namespace audio {

/***
 * Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio
 * Session Control. All methods are not thread safe, so users must acquire a
 * lock. Note: currently, in stream_apis.cc, if GetState() is only used for
 * verbose logging, it is not locked, so the state may not be synchronized.
 ***/
class BluetoothAudioPort {
 public:
  BluetoothAudioPort(){};
  virtual ~BluetoothAudioPort() = default;

  /***
   * Fetch output control / data path of BluetoothAudioPort and setup
   * callbacks into BluetoothAudioProvider. If SetUp() returns false, the audio
   * HAL must delete this BluetoothAudioPort and return EINVAL to caller
   ***/
  virtual bool SetUp(audio_devices_t) { return false; }

  /***
   * Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
   * Audio HAL must delete this BluetoothAudioPort after calling this.
   ***/
  virtual void TearDown() {}

  /***
   * When the Audio framework / HAL tries to query audio config about format,
   * channel mask and sample rate, it uses this function to fetch from the
   * Bluetooth stack
   ***/
  virtual bool LoadAudioConfig(audio_config_t*) const { return false; };

  /***
   * WAR to support Mono mode / 16 bits per sample
   ***/
  virtual void ForcePcmStereoToMono(bool) {}

  /***
   * When the Audio framework / HAL wants to change the stream state, it invokes
   * these 3 functions to control the Bluetooth stack (Audio Control Path).
   * Note: Both Start() and Suspend() will return true when there are no errors.
   * Called by Audio framework / HAL to start the stream
   ***/
  virtual bool Start() { return false; }

  /***
   * Called by Audio framework / HAL to suspend the stream
   ***/
  virtual bool Suspend() { return false; };

  /***
    virtual bool Suspend() { return false; }
    * Called by Audio framework / HAL to stop the stream
  ***/
  virtual void Stop() {}

  /***
   * Called by the Audio framework / HAL to fetch information about audio frames
   * presented to an external sink, or frames presented fror an internal sink
   ***/
  virtual bool GetPresentationPosition(uint64_t*, uint64_t*, timespec*) const {
    return false;
  }

  /***
   * Called by the Audio framework / HAL when the metadata of the stream's
   * source has been changed.
   ***/
  virtual void UpdateSourceMetadata(const source_metadata*) const {};

  /***
   * Return the current BluetoothStreamState
   ***/
  virtual BluetoothStreamState GetState() const {
    return static_cast<BluetoothStreamState>(0);
  }

  /***
   * Set the current BluetoothStreamState
   ***/
  virtual void SetState(BluetoothStreamState state) {}

  virtual bool IsA2dp() const { return false; }

  virtual bool GetPreferredDataIntervalUs(size_t* interval_us) const {
    return false;
  };

  virtual size_t WriteData(const void* buffer, size_t bytes) const {
    return 0;
  };
  virtual size_t ReadData(void* buffer, size_t bytes) const { return 0; };
};

namespace aidl {

using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
using ::aidl::android::hardware::bluetooth::audio::SessionType;

class BluetoothAudioPortAidl : public BluetoothAudioPort {
 public:
  BluetoothAudioPortAidl();
  virtual ~BluetoothAudioPortAidl() = default;

  bool SetUp(audio_devices_t devices) override;

  void TearDown() override;

  void ForcePcmStereoToMono(bool force) override { is_stereo_to_mono_ = force; }

  bool Start() override;
  bool Suspend() override;
  void Stop() override;

  bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* byte,
                               timespec* timestamp) const override;

  void UpdateSourceMetadata(
      const source_metadata* source_metadata) const override;

  /***
   * Called by the Audio framework / HAL when the metadata of the stream's
   * sink has been changed.
   ***/
  virtual void UpdateSinkMetadata(const sink_metadata* sink_metadata) const;

  BluetoothStreamState GetState() const override;

  void SetState(BluetoothStreamState state) override;

  bool IsA2dp() const override {
    return session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
           session_type_ ==
               SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
  }

  bool GetPreferredDataIntervalUs(size_t* interval_us) const override;

 protected:
  uint16_t cookie_;
  BluetoothStreamState state_;
  SessionType session_type_;
  // WR to support Mono: True if fetching Stereo and mixing into Mono
  bool is_stereo_to_mono_ = false;
  virtual bool in_use() const;

 private:
  mutable std::mutex cv_mutex_;
  std::condition_variable internal_cv_;

  // Check and initialize session type for |devices| If failed, this
  // BluetoothAudioPortAidl is not initialized and must be deleted.
  bool init_session_type(audio_devices_t device);

  bool CondwaitState(BluetoothStreamState state);

  void ControlResultHandler(const BluetoothAudioStatus& status);
  void SessionChangedHandler();
};

class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
 public:
  ~BluetoothAudioPortAidlOut();

  // The audio data path to the Bluetooth stack (Software encoding)
  size_t WriteData(const void* buffer, size_t bytes) const override;
  bool LoadAudioConfig(audio_config_t* audio_cfg) const override;
};

class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
 public:
  ~BluetoothAudioPortAidlIn();

  // The audio data path from the Bluetooth stack (Software decoded)
  size_t ReadData(void* buffer, size_t bytes) const override;
  bool LoadAudioConfig(audio_config_t* audio_cfg) const override;
};

}  // namespace aidl
}  // namespace audio
}  // namespace bluetooth
}  // namespace android