• Home
  • History
  • Annotate
  • 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/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