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/audio_hal.h" 30 #include "guest/hals/audio/vsoc_audio.h" 31 #include "guest/hals/audio/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) 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) 40 static inline size_t GceAudioFrameSize(const audio_stream_out* s) { 41 42 return audio_stream_frame_size(&s->common); 43 } 44 #else 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 56 namespace { 57 template <typename F> struct Thunker : 58 ThunkerBase<audio_stream, GceAudioOutputStream, F>{}; 59 60 template <typename F> struct OutThunker : 61 ThunkerBase<audio_stream_out, GceAudioOutputStream, F>{}; 62 } 63 64 GceAudioOutputStream::GceAudioOutputStream(GceAudio* dev) : 65 audio_stream_out(), 66 dev_(dev), 67 device_(AUDIO_DEVICE_OUT_DEFAULT), 68 frame_count_(0), 69 left_volume_(0.0), 70 right_volume_(0.0) { } 71 72 int GceAudioOutputStream::Dump(int fd) const { 73 D("GceAudioOutputStream::%s", __FUNCTION__); 74 VSOC_FDPRINTF( 75 fd, 76 "\tout_dump:\n" 77 "\t\tsample rate: %u\n" 78 "\t\tbuffer size: %zu\n" 79 "\t\tchannel mask: %08x\n" 80 "\t\tformat: %d\n" 81 "\t\tdevice: %08x\n" 82 "\t\taudio dev: %p\n\n", 83 GetSampleRate(), 84 GetBufferSize(), 85 GetChannels(), 86 GetFormat(), 87 device_, 88 dev_); 89 return 0; 90 } 91 92 int GceAudioOutputStream::GetNextWriteTimestamp(int64_t* nstime) const { 93 *nstime = cvd::time::Nanoseconds( 94 buffer_->GetNextOutputBufferItemTime().SinceEpoch()).count(); 95 return 0; 96 } 97 98 namespace { 99 struct StrParmsDestroyer { 100 void operator()(str_parms* parms) const { 101 if (parms) { 102 str_parms_destroy(parms); 103 } 104 } 105 }; 106 107 typedef std::unique_ptr<str_parms, StrParmsDestroyer> StrParmsPtr; 108 } 109 110 int GceAudioOutputStream::SetParameters(const char* kv_pairs) { 111 int err = 0; 112 StrParmsPtr parms(str_parms_create_str(kv_pairs)); 113 { 114 int fmt = 0; 115 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_FORMAT, &fmt) 116 == 0) { 117 SetFormat(static_cast<audio_format_t>(fmt)); 118 } 119 } 120 { 121 int sample_rate = 0; 122 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_SAMPLING_RATE, 123 &sample_rate) == 0) { 124 SetSampleRate(static_cast<uint32_t>(sample_rate)); 125 } 126 } 127 { 128 int routing = 0; 129 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_ROUTING, 130 &routing) == 0) { 131 device_ = static_cast<uint32_t>(routing); 132 } 133 } 134 { 135 int channels = 0; 136 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_CHANNELS, 137 &channels) == 0) { 138 message_header_.channel_mask = static_cast<audio_channel_mask_t>(channels); 139 } 140 } 141 { 142 int frame_count = 0; 143 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_FRAME_COUNT, 144 &frame_count) == 0) { 145 frame_count_ = static_cast<size_t>(frame_count); 146 } 147 } 148 { 149 int input_source = 0; 150 if (str_parms_get_int(parms.get(), AUDIO_PARAMETER_STREAM_INPUT_SOURCE, 151 &input_source) == 0){ 152 ALOGE("GceAudioOutputStream::%s AUDIO_PARAMETER_STREAM_INPUT_SOURCE" 153 " passed to an output stream", __FUNCTION__); 154 err = -EINVAL; 155 } 156 } 157 return err; 158 } 159 160 void GceAudioOutputStream::AddIntIfKeyPresent( 161 /*const */ str_parms* query, str_parms* reply, const char* key, int value) { 162 if (str_parms_get_str(query, key, NULL, 0) >= 0) { 163 str_parms_add_int(reply, key, value); 164 } 165 } 166 167 168 char* GceAudioOutputStream::GetParameters(const char* keys) const { 169 D("GceAudioOutputStream::%s", __FUNCTION__); 170 if (keys) D("%s keys %s", __FUNCTION__, keys); 171 172 StrParmsPtr query(str_parms_create_str(keys)); 173 StrParmsPtr reply(str_parms_create()); 174 175 AddIntIfKeyPresent(query.get(), reply.get(), 176 AUDIO_PARAMETER_STREAM_FORMAT, 177 static_cast<int>(GetFormat())); 178 AddIntIfKeyPresent(query.get(), reply.get(), 179 AUDIO_PARAMETER_STREAM_SAMPLING_RATE, 180 static_cast<int>(GetSampleRate())); 181 AddIntIfKeyPresent(query.get(), reply.get(), 182 AUDIO_PARAMETER_STREAM_ROUTING, 183 static_cast<int>(device_)); 184 AddIntIfKeyPresent(query.get(), reply.get(), 185 AUDIO_PARAMETER_STREAM_CHANNELS, 186 static_cast<int>(message_header_.channel_mask)); 187 AddIntIfKeyPresent(query.get(), reply.get(), 188 AUDIO_PARAMETER_STREAM_FRAME_COUNT, 189 static_cast<int>(frame_count_)); 190 191 char *str = str_parms_to_str(reply.get()); 192 return str; 193 } 194 195 int GceAudioOutputStream::GetRenderPosition(uint32_t* dsp_frames) const { 196 *dsp_frames = buffer_->GetCurrentItemNum(); 197 return 0; 198 } 199 200 ssize_t GceAudioOutputStream::Write(const void* buffer, size_t length) { 201 // We're always the blocking case for now. 202 static const bool blocking = true; 203 message_header_.frame_size = frame_size_; 204 frame_count_ += message_header_.num_frames_presented = length / frame_size_; 205 message_header_.message_type = gce_audio_message::DATA_SAMPLES; 206 // First do a nonblocking add 207 int64_t frames_accepted_without_blocking = buffer_->AddToOutputBuffer( 208 message_header_.num_frames_presented, false); 209 // This seems backward, but adding the items to the buffer first 210 // allows us to calculate the right frame number in the case of underflow. 211 message_header_.frame_num = 212 buffer_->GetNextOutputBufferItemNum() - frames_accepted_without_blocking; 213 message_header_.time_presented = 214 buffer_->GetLastUpdatedTime().SinceEpoch().GetTS(); 215 // We want to send the message before blocking. If we're in blocking mode 216 // we will accept all of the frames. 217 if (blocking) { 218 message_header_.num_frames_accepted = 219 message_header_.num_frames_presented; 220 } else { 221 message_header_.num_frames_accepted = frames_accepted_without_blocking; 222 } 223 // Never exceed the maximum packet size, as defined by the interface. 224 // Clip off any frames that we can't transmit and increment the clipped 225 // count. 226 size_t transmitted_frame_size = length; 227 if (length > gce_audio_message::kMaxAudioFrameLen) { 228 transmitted_frame_size = gce_audio_message::kMaxAudioFrameLen; 229 message_header_.num_packets_shortened++; 230 } 231 message_header_.total_size = 232 sizeof(message_header_) + transmitted_frame_size; 233 // Now send the message. Do not block if the receiver isn't ready 234 // If this is a blocking write we will block after we have attempted to 235 // send the data to the receiver. 236 msghdr msg; 237 iovec msg_iov[2]; 238 // We need a cast here because iov_base is defined non-const to support 239 // recvmsg et.al. 240 // There is no danger here:sendmsg does not write to the buffer. 241 msg_iov[0].iov_base = &message_header_; 242 msg_iov[0].iov_len = sizeof(message_header_); 243 msg_iov[1].iov_base = const_cast<void*>(buffer); 244 msg_iov[1].iov_len = transmitted_frame_size; 245 msg.msg_name = NULL; 246 msg.msg_namelen = 0; 247 msg.msg_iov = msg_iov; 248 msg.msg_iovlen = arraysize(msg_iov); 249 msg.msg_control = NULL; 250 msg.msg_controllen = 0; 251 msg.msg_flags = 0; 252 if (dev_->SendMsg(msg, MSG_DONTWAIT) < 0) { 253 message_header_.num_packets_dropped++; 254 } 255 if (!blocking) { 256 return frames_accepted_without_blocking * frame_size_; 257 } 258 if ((message_header_.num_frames_presented) > 259 static_cast<size_t>(frames_accepted_without_blocking)) { 260 buffer_->AddToOutputBuffer( 261 message_header_.num_frames_presented - 262 frames_accepted_without_blocking, true); 263 } 264 return message_header_.num_frames_presented * frame_size_; 265 } 266 267 int GceAudioOutputStream::Open( 268 GceAudio* dev, audio_io_handle_t /*handle*/, 269 audio_devices_t devices, audio_output_flags_t /*flags*/, 270 audio_config* config, uint32_t stream_number, 271 GceAudioOutputStream** stream_out) { 272 D("GceAudioOutputStream::%s", __FUNCTION__); 273 *stream_out = NULL; 274 // Deleted by Close(); UniquePtr holds until end of Open(). 275 std::unique_ptr<GceAudioOutputStream> out( 276 new GceAudioOutputStream(dev)); 277 out->message_header_.stream_number = stream_number; 278 out->message_header_.format = config->format; 279 out->message_header_.channel_mask = config->channel_mask; 280 out->message_header_.frame_rate = config->sample_rate; 281 out->frame_count_ = 282 #if VSOC_PLATFORM_SDK_AFTER(K) 283 config->frame_count; 284 #else 285 0; 286 #endif 287 out->common.get_sample_rate = 288 Thunker<uint32_t()>::call<&GceAudioOutputStream::GetSampleRate>; 289 out->common.set_sample_rate = 290 Thunker<int(uint32_t)>::call<&GceAudioOutputStream::SetSampleRate>; 291 out->common.get_buffer_size = 292 Thunker<size_t()>::call<&GceAudioOutputStream::GetBufferSize>; 293 out->common.get_channels = 294 Thunker<audio_channel_mask_t()>::call< 295 &GceAudioOutputStream::GetChannels>; 296 out->common.get_format = Thunker<audio_format_t()>::call< 297 &GceAudioOutputStream::GetFormat>; 298 out->common.set_format = Thunker<int(audio_format_t)>::call< 299 &GceAudioOutputStream::SetFormat>; 300 out->common.standby = Thunker<int()>::call<&GceAudioOutputStream::Standby>; 301 out->common.dump = Thunker<int(int)>::call<&GceAudioOutputStream::Dump>; 302 out->common.get_device = Thunker<audio_devices_t()>::call< 303 &GceAudioOutputStream::GetDevice>; 304 out->common.set_device = Thunker<int(audio_devices_t)>::call< 305 &GceAudioOutputStream::SetDevice>; 306 out->common.set_parameters = 307 Thunker<int(const char*)>::call< 308 &GceAudioOutputStream::SetParameters>; 309 out->common.get_parameters = 310 Thunker<char*(const char *)>::call< 311 &GceAudioOutputStream::GetParameters>; 312 out->common.add_audio_effect = 313 Thunker<int(effect_handle_t)>::call< 314 &GceAudioOutputStream::AddAudioEffect>; 315 out->common.remove_audio_effect = 316 Thunker<int(effect_handle_t)>::call< 317 &GceAudioOutputStream::RemoveAudioEffect>; 318 out->get_latency = 319 OutThunker<uint32_t()>::call< 320 &GceAudioOutputStream::GetLatency>; 321 out->set_volume = 322 OutThunker<int(float, float)>::call<&GceAudioOutputStream::SetVolume>; 323 out->write = 324 OutThunker<ssize_t(const void*, size_t)>::call< 325 &GceAudioOutputStream::Write>; 326 out->get_render_position = 327 OutThunker<int(uint32_t*)>::call< 328 &GceAudioOutputStream::GetRenderPosition>; 329 out->get_next_write_timestamp = 330 OutThunker<int(int64_t*)>::call< 331 &GceAudioOutputStream::GetNextWriteTimestamp>; 332 out->device_ = devices; 333 out->frame_size_ = GceAudioFrameSize(out.get()); 334 335 int64_t item_capacity = 336 out->frame_size_ == 0 ? 0 : out->GetBufferSize() / out->frame_size_; 337 if (item_capacity == 0) { 338 ALOGE("Attempt to create GceAudioOutputStream with frame_size_ of 0."); 339 return -EINVAL; 340 } 341 out->buffer_.reset( 342 new SimulatedOutputBuffer( 343 config->sample_rate, item_capacity)); 344 *stream_out = out.release(); 345 return 0; 346 } 347 348 } // namespace cvd 349