• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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