1 // Copyright (C) 2020 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 #include "AudioProxyDevice.h"
16 
17 #include <android-base/logging.h>
18 
19 #include "AudioProxyStreamOut.h"
20 
21 using aidl::device::google::atv::audio_proxy::AudioConfig;
22 
23 #define CHECK_API(st, func)                    \
24   do {                                         \
25     if (!st->func) {                           \
26       LOG(ERROR) << "Undefined API " << #func; \
27       return false;                            \
28     }                                          \
29   } while (0)
30 
31 namespace audio_proxy {
32 namespace {
isValidStreamOut(const audio_proxy_stream_out_t * stream)33 bool isValidStreamOut(const audio_proxy_stream_out_t* stream) {
34   CHECK_API(stream, standby);
35   CHECK_API(stream, pause);
36   CHECK_API(stream, resume);
37   CHECK_API(stream, flush);
38   CHECK_API(stream, drain);
39   CHECK_API(stream, write);
40   CHECK_API(stream, get_presentation_position);
41   CHECK_API(stream, set_volume);
42   CHECK_API(stream, get_buffer_size);
43   CHECK_API(stream, get_latency);
44 
45   if (stream->v2) {
46     CHECK_API(stream->v2, start);
47     CHECK_API(stream->v2, stop);
48     CHECK_API(stream->v2, create_mmap_buffer);
49     CHECK_API(stream->v2, get_mmap_position);
50   }
51 
52   return true;
53 }
54 }  // namespace
55 
AudioProxyDevice(audio_proxy_device_t * device)56 AudioProxyDevice::AudioProxyDevice(audio_proxy_device_t* device)
57     : mDevice(device) {}
58 
59 AudioProxyDevice::~AudioProxyDevice() = default;
60 
getServiceName()61 const char* AudioProxyDevice::getServiceName() {
62   return mDevice->v2->get_service_name(mDevice->v2);
63 }
64 
openOutputStream(const std::string & address,const AudioConfig & aidlConfig,int32_t flags)65 std::unique_ptr<AudioProxyStreamOut> AudioProxyDevice::openOutputStream(
66     const std::string& address, const AudioConfig& aidlConfig, int32_t flags) {
67   audio_proxy_config_v2_t config_v2 = {
68       .buffer_size_bytes = aidlConfig.bufferSizeBytes,
69       .latency_ms = aidlConfig.latencyMs,
70       .extension = nullptr};
71 
72   audio_proxy_config_t config = {
73       .format = static_cast<audio_proxy_format_t>(aidlConfig.format),
74       .sample_rate = static_cast<uint32_t>(aidlConfig.sampleRateHz),
75       .channel_mask =
76           static_cast<audio_proxy_channel_mask_t>(aidlConfig.channelMask),
77       .frame_count = 0,
78       .v2 = &config_v2};
79 
80   // TODO(yucliu): Pass address to the app. For now, the only client app
81   // (MediaShell) can use flags to distinguish different streams.
82   audio_proxy_stream_out_t* stream = nullptr;
83   int ret = mDevice->v2->open_output_stream(
84       mDevice->v2, address.c_str(),
85       static_cast<audio_proxy_output_flags_t>(flags), &config, &stream);
86 
87   if (ret || !stream) {
88     return nullptr;
89   }
90 
91   if (!isValidStreamOut(stream)) {
92     mDevice->close_output_stream(mDevice, stream);
93     return nullptr;
94   }
95 
96   return std::make_unique<AudioProxyStreamOut>(stream, mDevice);
97 }
98 
99 }  // namespace audio_proxy
100