1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <pthread.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <memory>
20
21 #include <cutils/sockets.h>
22 extern "C"{
23 #include <cutils/str_parms.h>
24 }
25
26 #include "common/libs/auto_resources/auto_resources.h"
27 #include "common/libs/threads/thunkers.h"
28 #include "common/libs/time/monotonic_time.h"
29 #include "guest/hals/audio/legacy/audio_hal.h"
30 #include "guest/hals/audio/legacy/vsoc_audio.h"
31 #include "guest/hals/audio/legacy/vsoc_audio_output_stream.h"
32 #include "guest/libs/platform_support/api_level_fixes.h"
33 #include "guest/libs/remoter/remoter_framework_pkt.h"
34
35 #if defined(AUDIO_DEVICE_API_VERSION_3_0)
GceAudioFrameSize(const audio_stream_out * s)36 static inline size_t GceAudioFrameSize(const audio_stream_out* s) {
37 return audio_stream_out_frame_size(s);
38 }
39 #elif defined(AUDIO_DEVICE_API_VERSION_2_0)
GceAudioFrameSize(const audio_stream_out * s)40 static inline size_t GceAudioFrameSize(const audio_stream_out* s) {
41
42 return audio_stream_frame_size(&s->common);
43 }
44 #else
GceAudioFrameSize(audio_stream_out * s)45 static inline size_t GceAudioFrameSize(audio_stream_out* s) {
46
47 return audio_stream_frame_size(&s->common);
48 }
49 #endif
50
51 namespace cvd {
52
53 const size_t GceAudioOutputStream::kOutBufferSize;
54 const size_t GceAudioOutputStream::kOutLatency;
55
GceAudioOutputStream(GceAudio * dev)56 GceAudioOutputStream::GceAudioOutputStream(GceAudio* dev) :
57 audio_stream_out(),
58 dev_(dev),
59 device_(AUDIO_DEVICE_OUT_DEFAULT),
60 frame_count_(0),
61 left_volume_(0.0),
62 right_volume_(0.0) { }
63
Dump(int fd) const64 int GceAudioOutputStream::Dump(int fd) const {
65 D("GceAudioOutputStream::%s", __FUNCTION__);
66 VSOC_FDPRINTF(
67 fd,
68 "\tout_dump:\n"
69 "\t\tsample rate: %u\n"
70 "\t\tbuffer size: %zu\n"
71 "\t\tchannel mask: %08x\n"
72 "\t\tformat: %d\n"
73 "\t\tdevice: %08x\n"
74 "\t\taudio dev: %p\n\n",
75 GetSampleRate(),
76 GetBufferSize(),
77 GetChannels(),
78 GetFormat(),
79 device_,
80 dev_);
81 return 0;
82 }
83
GetNextWriteTimestamp(int64_t * nstime) const84 int GceAudioOutputStream::GetNextWriteTimestamp(int64_t* nstime) const {
85 *nstime = cvd::time::Nanoseconds(
86 buffer_->GetNextOutputBufferItemTime().SinceEpoch()).count();
87 return 0;
88 }
89
90 namespace {
91 struct StrParmsDestroyer {
operator ()cvd::__anon50f83ab00111::StrParmsDestroyer92 void operator()(str_parms* parms) const {
93 if (parms) {
94 str_parms_destroy(parms);
95 }
96 }
97 };
98
99 typedef std::unique_ptr<str_parms, StrParmsDestroyer> StrParmsPtr;
100 }
101
SetParameters(const char * kv_pairs)102 int GceAudioOutputStream::SetParameters(const char* kv_pairs) {
103 int err = 0;
104 StrParmsPtr parms(str_parms_create_str(kv_pairs));
105 {
106 int fmt = 0;
107 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_FORMAT, &fmt)
108 == 0) {
109 SetFormat(static_cast<audio_format_t>(fmt));
110 }
111 }
112 {
113 int sample_rate = 0;
114 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_SAMPLING_RATE,
115 &sample_rate) == 0) {
116 SetSampleRate(static_cast<uint32_t>(sample_rate));
117 }
118 }
119 {
120 int routing = 0;
121 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_ROUTING,
122 &routing) == 0) {
123 device_ = static_cast<uint32_t>(routing);
124 }
125 }
126 {
127 int channels = 0;
128 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_CHANNELS,
129 &channels) == 0) {
130 message_header_.channel_mask = static_cast<audio_channel_mask_t>(channels);
131 }
132 }
133 {
134 int frame_count = 0;
135 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_FRAME_COUNT,
136 &frame_count) == 0) {
137 frame_count_ = static_cast<size_t>(frame_count);
138 }
139 }
140 {
141 int input_source = 0;
142 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_INPUT_SOURCE,
143 &input_source) == 0){
144 ALOGE("GceAudioOutputStream::%s AUDIO_PARAMETER_STREAM_INPUT_SOURCE"
145 " passed to an output stream", __FUNCTION__);
146 err = -EINVAL;
147 }
148 }
149 return err;
150 }
151
AddIntIfKeyPresent(str_parms * query,str_parms * reply,const char * key,int value)152 void GceAudioOutputStream::AddIntIfKeyPresent(
153 /*const */ str_parms* query, str_parms* reply, const char* key, int value) {
154 if (str_parms_get_str(query, key, NULL, 0) >= 0) {
155 str_parms_add_int(reply, key, value);
156 }
157 }
158
159
GetParameters(const char * keys) const160 char* GceAudioOutputStream::GetParameters(const char* keys) const {
161 D("GceAudioOutputStream::%s", __FUNCTION__);
162 if (keys) D("%s keys %s", __FUNCTION__, keys);
163
164 StrParmsPtr query(str_parms_create_str(keys));
165 StrParmsPtr reply(str_parms_create());
166
167 AddIntIfKeyPresent(query.get(), reply.get(),
168 AUDIO_PARAMETER_STREAM_FORMAT,
169 static_cast<int>(GetFormat()));
170 AddIntIfKeyPresent(query.get(), reply.get(),
171 AUDIO_PARAMETER_STREAM_SAMPLING_RATE,
172 static_cast<int>(GetSampleRate()));
173 AddIntIfKeyPresent(query.get(), reply.get(),
174 AUDIO_PARAMETER_STREAM_ROUTING,
175 static_cast<int>(device_));
176 AddIntIfKeyPresent(query.get(), reply.get(),
177 AUDIO_PARAMETER_STREAM_CHANNELS,
178 static_cast<int>(message_header_.channel_mask));
179 AddIntIfKeyPresent(query.get(), reply.get(),
180 AUDIO_PARAMETER_STREAM_FRAME_COUNT,
181 static_cast<int>(frame_count_));
182
183 char *str = str_parms_to_str(reply.get());
184 return str;
185 }
186
GetRenderPosition(uint32_t * dsp_frames) const187 int GceAudioOutputStream::GetRenderPosition(uint32_t* dsp_frames) const {
188 *dsp_frames = buffer_->GetCurrentItemNum();
189 return 0;
190 }
191
Write(const void * buffer,size_t length)192 ssize_t GceAudioOutputStream::Write(const void* buffer, size_t length) {
193 // We're always the blocking case for now.
194 static const bool blocking = true;
195 message_header_.frame_size = frame_size_;
196 frame_count_ += message_header_.num_frames_presented = length / frame_size_;
197 message_header_.message_type = gce_audio_message::DATA_SAMPLES;
198 // First do a nonblocking add
199 int64_t frames_accepted_without_blocking = buffer_->AddToOutputBuffer(
200 message_header_.num_frames_presented, false);
201 // This seems backward, but adding the items to the buffer first
202 // allows us to calculate the right frame number in the case of underflow.
203 message_header_.frame_num =
204 buffer_->GetNextOutputBufferItemNum() - frames_accepted_without_blocking;
205 message_header_.time_presented =
206 buffer_->GetLastUpdatedTime().SinceEpoch().GetTS();
207 // We want to send the message before blocking. If we're in blocking mode
208 // we will accept all of the frames.
209 if (blocking) {
210 message_header_.num_frames_accepted =
211 message_header_.num_frames_presented;
212 } else {
213 message_header_.num_frames_accepted = frames_accepted_without_blocking;
214 }
215 // Never exceed the maximum packet size, as defined by the interface.
216 // Clip off any frames that we can't transmit and increment the clipped
217 // count.
218 size_t transmitted_frame_size = length;
219 if (length > gce_audio_message::kMaxAudioFrameLen) {
220 transmitted_frame_size = gce_audio_message::kMaxAudioFrameLen;
221 message_header_.num_packets_shortened++;
222 }
223 message_header_.total_size =
224 sizeof(message_header_) + transmitted_frame_size;
225 // Now send the message. Do not block if the receiver isn't ready
226 // If this is a blocking write we will block after we have attempted to
227 // send the data to the receiver.
228 msghdr msg;
229 iovec msg_iov[2];
230 // We need a cast here because iov_base is defined non-const to support
231 // recvmsg et.al.
232 // There is no danger here:sendmsg does not write to the buffer.
233 msg_iov[0].iov_base = &message_header_;
234 msg_iov[0].iov_len = sizeof(message_header_);
235 msg_iov[1].iov_base = const_cast<void*>(buffer);
236 msg_iov[1].iov_len = transmitted_frame_size;
237 msg.msg_name = NULL;
238 msg.msg_namelen = 0;
239 msg.msg_iov = msg_iov;
240 msg.msg_iovlen = arraysize(msg_iov);
241 msg.msg_control = NULL;
242 msg.msg_controllen = 0;
243 msg.msg_flags = 0;
244 if (dev_->SendMsg(msg, MSG_DONTWAIT) < 0) {
245 message_header_.num_packets_dropped++;
246 }
247 if (!blocking) {
248 return frames_accepted_without_blocking * frame_size_;
249 }
250 if ((message_header_.num_frames_presented) >
251 static_cast<size_t>(frames_accepted_without_blocking)) {
252 buffer_->AddToOutputBuffer(
253 message_header_.num_frames_presented -
254 frames_accepted_without_blocking, true);
255 }
256 return message_header_.num_frames_presented * frame_size_;
257 }
258
Open(GceAudio * dev,audio_io_handle_t,audio_devices_t devices,audio_output_flags_t,audio_config * config,uint32_t stream_number,GceAudioOutputStream ** stream_out)259 int GceAudioOutputStream::Open(
260 GceAudio* dev, audio_io_handle_t /*handle*/,
261 audio_devices_t devices, audio_output_flags_t /*flags*/,
262 audio_config* config, uint32_t stream_number,
263 GceAudioOutputStream** stream_out) {
264 D("GceAudioOutputStream::%s", __FUNCTION__);
265 *stream_out = NULL;
266 // Deleted by Close(); UniquePtr holds until end of Open().
267 std::unique_ptr<GceAudioOutputStream> out(
268 new GceAudioOutputStream(dev));
269 out->message_header_.stream_number = stream_number;
270 out->message_header_.format = config->format;
271 out->message_header_.channel_mask = config->channel_mask;
272 out->message_header_.frame_rate = config->sample_rate;
273 out->frame_count_ =
274 #if VSOC_PLATFORM_SDK_AFTER(K)
275 config->frame_count;
276 #else
277 0;
278 #endif
279 out->common.get_sample_rate =
280 cvd::thunk<audio_stream, &GceAudioOutputStream::GetSampleRate>;
281 out->common.set_sample_rate =
282 cvd::thunk<audio_stream, &GceAudioOutputStream::SetSampleRate>;
283 out->common.get_buffer_size =
284 cvd::thunk<audio_stream, &GceAudioOutputStream::GetBufferSize>;
285 out->common.get_channels =
286 cvd::thunk<audio_stream, &GceAudioOutputStream::GetChannels>;
287 out->common.get_format = cvd::thunk<audio_stream, &GceAudioOutputStream::GetFormat>;
288 out->common.set_format = cvd::thunk<audio_stream, &GceAudioOutputStream::SetFormat>;
289 out->common.standby = cvd::thunk<audio_stream, &GceAudioOutputStream::Standby>;
290 out->common.dump = cvd::thunk<audio_stream, &GceAudioOutputStream::Dump>;
291 out->common.get_device = cvd::thunk<audio_stream, &GceAudioOutputStream::GetDevice>;
292 out->common.set_device = cvd::thunk<audio_stream, &GceAudioOutputStream::SetDevice>;
293 out->common.set_parameters =
294 cvd::thunk<audio_stream, &GceAudioOutputStream::SetParameters>;
295 out->common.get_parameters =
296 cvd::thunk<audio_stream, &GceAudioOutputStream::GetParameters>;
297 out->common.add_audio_effect =
298 cvd::thunk<audio_stream, &GceAudioOutputStream::AddAudioEffect>;
299 out->common.remove_audio_effect =
300 cvd::thunk<audio_stream, &GceAudioOutputStream::RemoveAudioEffect>;
301
302 out->get_latency =
303 cvd::thunk<audio_stream_out, &GceAudioOutputStream::GetLatency>;
304 out->set_volume =
305 cvd::thunk<audio_stream_out, &GceAudioOutputStream::SetVolume>;
306 out->write =
307 cvd::thunk<audio_stream_out, &GceAudioOutputStream::Write>;
308 out->get_render_position =
309 cvd::thunk<audio_stream_out, &GceAudioOutputStream::GetRenderPosition>;
310 out->get_next_write_timestamp =
311 cvd::thunk<audio_stream_out, &GceAudioOutputStream::GetNextWriteTimestamp>;
312 out->device_ = devices;
313 out->frame_size_ = GceAudioFrameSize(out.get());
314
315 int64_t item_capacity =
316 out->frame_size_ == 0 ? 0 : out->GetBufferSize() / out->frame_size_;
317 if (item_capacity == 0) {
318 ALOGE("Attempt to create GceAudioOutputStream with frame_size_ of 0.");
319 return -EINVAL;
320 }
321 out->buffer_.reset(
322 new SimulatedOutputBuffer(
323 config->sample_rate, item_capacity));
324 *stream_out = out.release();
325 return 0;
326 }
327
328 } // namespace cvd
329