• 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 
17 #define LOG_TAG "StreamHalHidl"
18 //#define LOG_NDEBUG 0
19 
20 #include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.h)
21 #include <hwbinder/IPCThreadState.h>
22 #include <media/AudioParameter.h>
23 #include <mediautils/SchedulingPolicyService.h>
24 #include <utils/Log.h>
25 
26 #include "DeviceHalHidl.h"
27 #include "EffectHalHidl.h"
28 #include "StreamHalHidl.h"
29 #include "VersionUtils.h"
30 
31 using ::android::hardware::MQDescriptorSync;
32 using ::android::hardware::Return;
33 using ::android::hardware::Void;
34 
35 namespace android {
36 namespace CPP_VERSION {
37 
38 using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
39 using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
40 
41 using namespace ::android::hardware::audio::common::CPP_VERSION;
42 using namespace ::android::hardware::audio::CPP_VERSION;
43 
StreamHalHidl(IStream * stream)44 StreamHalHidl::StreamHalHidl(IStream *stream)
45         : ConversionHelperHidl("Stream"),
46           mStream(stream),
47           mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
48           mCachedBufferSize(0){
49 
50     // Instrument audio signal power logging.
51     // Note: This assumes channel mask, format, and sample rate do not change after creation.
52     if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
53         // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
54         Return<void> ret = mStream->getAudioProperties(
55                 [&](auto sr, auto m, auto f) {
56                 mStreamPowerLog.init(sr,
57                         static_cast<audio_channel_mask_t>(m),
58                         static_cast<audio_format_t>(f));
59             });
60     }
61 }
62 
~StreamHalHidl()63 StreamHalHidl::~StreamHalHidl() {
64     mStream = nullptr;
65 }
66 
getSampleRate(uint32_t * rate)67 status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
68     if (!mStream) return NO_INIT;
69     return processReturn("getSampleRate", mStream->getSampleRate(), rate);
70 }
71 
getBufferSize(size_t * size)72 status_t StreamHalHidl::getBufferSize(size_t *size) {
73     if (!mStream) return NO_INIT;
74     status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
75     if (status == OK) {
76         mCachedBufferSize = *size;
77     }
78     return status;
79 }
80 
getChannelMask(audio_channel_mask_t * mask)81 status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
82     if (!mStream) return NO_INIT;
83     return processReturn("getChannelMask", mStream->getChannelMask(), mask);
84 }
85 
getFormat(audio_format_t * format)86 status_t StreamHalHidl::getFormat(audio_format_t *format) {
87     if (!mStream) return NO_INIT;
88     return processReturn("getFormat", mStream->getFormat(), format);
89 }
90 
getAudioProperties(uint32_t * sampleRate,audio_channel_mask_t * mask,audio_format_t * format)91 status_t StreamHalHidl::getAudioProperties(
92         uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
93     if (!mStream) return NO_INIT;
94     Return<void> ret = mStream->getAudioProperties(
95             [&](uint32_t sr, auto m, auto f) {
96                 *sampleRate = sr;
97                 *mask = static_cast<audio_channel_mask_t>(m);
98                 *format = static_cast<audio_format_t>(f);
99             });
100     return processReturn("getAudioProperties", ret);
101 }
102 
setParameters(const String8 & kvPairs)103 status_t StreamHalHidl::setParameters(const String8& kvPairs) {
104     if (!mStream) return NO_INIT;
105     hidl_vec<ParameterValue> hidlParams;
106     status_t status = parametersFromHal(kvPairs, &hidlParams);
107     if (status != OK) return status;
108     return processReturn("setParameters",
109                          utils::setParameters(mStream, {} /* context */, hidlParams));
110 }
111 
getParameters(const String8 & keys,String8 * values)112 status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
113     values->clear();
114     if (!mStream) return NO_INIT;
115     hidl_vec<hidl_string> hidlKeys;
116     status_t status = keysFromHal(keys, &hidlKeys);
117     if (status != OK) return status;
118     Result retval;
119     Return<void> ret = utils::getParameters(
120             mStream,
121             {} /* context */,
122             hidlKeys,
123             [&](Result r, const hidl_vec<ParameterValue>& parameters) {
124                 retval = r;
125                 if (retval == Result::OK) {
126                     parametersToHal(parameters, values);
127                 }
128             });
129     return processReturn("getParameters", ret, retval);
130 }
131 
addEffect(sp<EffectHalInterface> effect)132 status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
133     if (!mStream) return NO_INIT;
134     return processReturn("addEffect", mStream->addEffect(
135                     static_cast<EffectHalHidl*>(effect.get())->effectId()));
136 }
137 
removeEffect(sp<EffectHalInterface> effect)138 status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
139     if (!mStream) return NO_INIT;
140     return processReturn("removeEffect", mStream->removeEffect(
141                     static_cast<EffectHalHidl*>(effect.get())->effectId()));
142 }
143 
standby()144 status_t StreamHalHidl::standby() {
145     if (!mStream) return NO_INIT;
146     return processReturn("standby", mStream->standby());
147 }
148 
dump(int fd)149 status_t StreamHalHidl::dump(int fd) {
150     if (!mStream) return NO_INIT;
151     native_handle_t* hidlHandle = native_handle_create(1, 0);
152     hidlHandle->data[0] = fd;
153     Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
154     native_handle_delete(hidlHandle);
155     mStreamPowerLog.dump(fd);
156     return processReturn("dump", ret);
157 }
158 
start()159 status_t StreamHalHidl::start() {
160     if (!mStream) return NO_INIT;
161     return processReturn("start", mStream->start());
162 }
163 
stop()164 status_t StreamHalHidl::stop() {
165     if (!mStream) return NO_INIT;
166     return processReturn("stop", mStream->stop());
167 }
168 
createMmapBuffer(int32_t minSizeFrames,struct audio_mmap_buffer_info * info)169 status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
170                                   struct audio_mmap_buffer_info *info) {
171     Result retval;
172     Return<void> ret = mStream->createMmapBuffer(
173             minSizeFrames,
174             [&](Result r, const MmapBufferInfo& hidlInfo) {
175                 retval = r;
176                 if (retval == Result::OK) {
177                     const native_handle *handle = hidlInfo.sharedMemory.handle();
178                     if (handle->numFds > 0) {
179                         info->shared_memory_fd = handle->data[0];
180 #if MAJOR_VERSION >= 4
181                         info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
182 #endif
183                         info->buffer_size_frames = hidlInfo.bufferSizeFrames;
184                         // Negative buffer size frame was a hack in O and P to
185                         // indicate that the buffer is shareable to applications
186                         if (info->buffer_size_frames < 0) {
187                             info->buffer_size_frames *= -1;
188                             info->flags = audio_mmap_buffer_flag(
189                                     info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
190                         }
191                         info->burst_size_frames = hidlInfo.burstSizeFrames;
192                         // info->shared_memory_address is not needed in HIDL context
193                         info->shared_memory_address = NULL;
194                     } else {
195                         retval = Result::NOT_INITIALIZED;
196                     }
197                 }
198             });
199     return processReturn("createMmapBuffer", ret, retval);
200 }
201 
getMmapPosition(struct audio_mmap_position * position)202 status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
203     Result retval;
204     Return<void> ret = mStream->getMmapPosition(
205             [&](Result r, const MmapPosition& hidlPosition) {
206                 retval = r;
207                 if (retval == Result::OK) {
208                     position->time_nanoseconds = hidlPosition.timeNanoseconds;
209                     position->position_frames = hidlPosition.positionFrames;
210                 }
211             });
212     return processReturn("getMmapPosition", ret, retval);
213 }
214 
setHalThreadPriority(int priority)215 status_t StreamHalHidl::setHalThreadPriority(int priority) {
216     mHalThreadPriority = priority;
217     return OK;
218 }
219 
getCachedBufferSize(size_t * size)220 status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
221     if (mCachedBufferSize != 0) {
222         *size = mCachedBufferSize;
223         return OK;
224     }
225     return getBufferSize(size);
226 }
227 
requestHalThreadPriority(pid_t threadPid,pid_t threadId)228 bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
229     if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
230         return true;
231     }
232     int err = requestPriority(
233             threadPid, threadId,
234             mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
235     ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
236             mHalThreadPriority, threadPid, threadId, err);
237     // Audio will still work, but latency will be higher and sometimes unacceptable.
238     return err == 0;
239 }
240 
241 namespace {
242 
243 /* Notes on callback ownership.
244 
245 This is how (Hw)Binder ownership model looks like. The server implementation
246 is owned by Binder framework (via sp<>). Proxies are owned by clients.
247 When the last proxy disappears, Binder framework releases the server impl.
248 
249 Thus, it is not needed to keep any references to StreamOutCallback (this is
250 the server impl) -- it will live as long as HAL server holds a strong ref to
251 IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
252 from the destructor of StreamOutHalHidl.
253 
254 The callback only keeps a weak reference to the stream. The stream is owned
255 by AudioFlinger.
256 
257 */
258 
259 struct StreamOutCallback : public IStreamOutCallback {
StreamOutCallbackandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback260     StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
261 
262     // IStreamOutCallback implementation
onWriteReadyandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback263     Return<void> onWriteReady()  override {
264         sp<StreamOutHalHidl> stream = mStream.promote();
265         if (stream != 0) {
266             stream->onWriteReady();
267         }
268         return Void();
269     }
270 
onDrainReadyandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback271     Return<void> onDrainReady()  override {
272         sp<StreamOutHalHidl> stream = mStream.promote();
273         if (stream != 0) {
274             stream->onDrainReady();
275         }
276         return Void();
277     }
278 
onErrorandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback279     Return<void> onError()  override {
280         sp<StreamOutHalHidl> stream = mStream.promote();
281         if (stream != 0) {
282             stream->onError();
283         }
284         return Void();
285     }
286 
287   private:
288     wp<StreamOutHalHidl> mStream;
289 };
290 
291 }  // namespace
292 
StreamOutHalHidl(const sp<IStreamOut> & stream)293 StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
294         : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
295 }
296 
~StreamOutHalHidl()297 StreamOutHalHidl::~StreamOutHalHidl() {
298     if (mStream != 0) {
299         if (mCallback.unsafe_get()) {
300             processReturn("clearCallback", mStream->clearCallback());
301         }
302         processReturn("close", mStream->close());
303         mStream.clear();
304     }
305     mCallback.clear();
306     hardware::IPCThreadState::self()->flushCommands();
307     if (mEfGroup) {
308         EventFlag::deleteEventFlag(&mEfGroup);
309     }
310 }
311 
getFrameSize(size_t * size)312 status_t StreamOutHalHidl::getFrameSize(size_t *size) {
313     if (mStream == 0) return NO_INIT;
314     return processReturn("getFrameSize", mStream->getFrameSize(), size);
315 }
316 
getLatency(uint32_t * latency)317 status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
318     if (mStream == 0) return NO_INIT;
319     if (mWriterClient == gettid() && mCommandMQ) {
320         return callWriterThread(
321                 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
322                 [&](const WriteStatus& writeStatus) {
323                     *latency = writeStatus.reply.latencyMs;
324                 });
325     } else {
326         return processReturn("getLatency", mStream->getLatency(), latency);
327     }
328 }
329 
setVolume(float left,float right)330 status_t StreamOutHalHidl::setVolume(float left, float right) {
331     if (mStream == 0) return NO_INIT;
332     return processReturn("setVolume", mStream->setVolume(left, right));
333 }
334 
335 #if MAJOR_VERSION == 2
selectPresentation(int presentationId,int programId)336 status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
337     if (mStream == 0) return NO_INIT;
338     std::vector<ParameterValue> parameters;
339     String8 halParameters;
340     parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
341     parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
342     parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
343     return setParameters(halParameters);
344 }
345 #elif MAJOR_VERSION >= 4
selectPresentation(int presentationId,int programId)346 status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
347     if (mStream == 0) return NO_INIT;
348     return processReturn("selectPresentation",
349             mStream->selectPresentation(presentationId, programId));
350 }
351 #endif
352 
write(const void * buffer,size_t bytes,size_t * written)353 status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
354     if (mStream == 0) return NO_INIT;
355     *written = 0;
356 
357     if (bytes == 0 && !mDataMQ) {
358         // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
359         ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
360         return OK;
361     }
362 
363     status_t status;
364     if (!mDataMQ) {
365         // In case if playback starts close to the end of a compressed track, the bytes
366         // that need to be written is less than the actual buffer size. Need to use
367         // full buffer size for the MQ since otherwise after seeking back to the middle
368         // data will be truncated.
369         size_t bufferSize;
370         if ((status = getCachedBufferSize(&bufferSize)) != OK) {
371             return status;
372         }
373         if (bytes > bufferSize) bufferSize = bytes;
374         if ((status = prepareForWriting(bufferSize)) != OK) {
375             return status;
376         }
377     }
378 
379     status = callWriterThread(
380             WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
381             [&] (const WriteStatus& writeStatus) {
382                 *written = writeStatus.reply.written;
383                 // Diagnostics of the cause of b/35813113.
384                 ALOGE_IF(*written > bytes,
385                         "hal reports more bytes written than asked for: %lld > %lld",
386                         (long long)*written, (long long)bytes);
387             });
388     mStreamPowerLog.log(buffer, *written);
389     return status;
390 }
391 
callWriterThread(WriteCommand cmd,const char * cmdName,const uint8_t * data,size_t dataSize,StreamOutHalHidl::WriterCallback callback)392 status_t StreamOutHalHidl::callWriterThread(
393         WriteCommand cmd, const char* cmdName,
394         const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
395     if (!mCommandMQ->write(&cmd)) {
396         ALOGE("command message queue write failed for \"%s\"", cmdName);
397         return -EAGAIN;
398     }
399     if (data != nullptr) {
400         size_t availableToWrite = mDataMQ->availableToWrite();
401         if (dataSize > availableToWrite) {
402             ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
403                     (long long)dataSize, (long long)availableToWrite);
404             dataSize = availableToWrite;
405         }
406         if (!mDataMQ->write(data, dataSize)) {
407             ALOGE("data message queue write failed for \"%s\"", cmdName);
408         }
409     }
410     mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
411 
412     // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
413     uint32_t efState = 0;
414 retry:
415     status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
416     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
417         WriteStatus writeStatus;
418         writeStatus.retval = Result::NOT_INITIALIZED;
419         if (!mStatusMQ->read(&writeStatus)) {
420             ALOGE("status message read failed for \"%s\"", cmdName);
421         }
422         if (writeStatus.retval == Result::OK) {
423             ret = OK;
424             callback(writeStatus);
425         } else {
426             ret = processReturn(cmdName, writeStatus.retval);
427         }
428         return ret;
429     }
430     if (ret == -EAGAIN || ret == -EINTR) {
431         // Spurious wakeup. This normally retries no more than once.
432         goto retry;
433     }
434     return ret;
435 }
436 
prepareForWriting(size_t bufferSize)437 status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
438     std::unique_ptr<CommandMQ> tempCommandMQ;
439     std::unique_ptr<DataMQ> tempDataMQ;
440     std::unique_ptr<StatusMQ> tempStatusMQ;
441     Result retval;
442     pid_t halThreadPid, halThreadTid;
443     Return<void> ret = mStream->prepareForWriting(
444             1, bufferSize,
445             [&](Result r,
446                     const CommandMQ::Descriptor& commandMQ,
447                     const DataMQ::Descriptor& dataMQ,
448                     const StatusMQ::Descriptor& statusMQ,
449                     const ThreadInfo& halThreadInfo) {
450                 retval = r;
451                 if (retval == Result::OK) {
452                     tempCommandMQ.reset(new CommandMQ(commandMQ));
453                     tempDataMQ.reset(new DataMQ(dataMQ));
454                     tempStatusMQ.reset(new StatusMQ(statusMQ));
455                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
456                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
457                     }
458                     halThreadPid = halThreadInfo.pid;
459                     halThreadTid = halThreadInfo.tid;
460                 }
461             });
462     if (!ret.isOk() || retval != Result::OK) {
463         return processReturn("prepareForWriting", ret, retval);
464     }
465     if (!tempCommandMQ || !tempCommandMQ->isValid() ||
466             !tempDataMQ || !tempDataMQ->isValid() ||
467             !tempStatusMQ || !tempStatusMQ->isValid() ||
468             !mEfGroup) {
469         ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
470         ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
471                 "Command message queue for writing is invalid");
472         ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
473         ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
474         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
475         ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
476                 "Status message queue for writing is invalid");
477         ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
478         return NO_INIT;
479     }
480     requestHalThreadPriority(halThreadPid, halThreadTid);
481 
482     mCommandMQ = std::move(tempCommandMQ);
483     mDataMQ = std::move(tempDataMQ);
484     mStatusMQ = std::move(tempStatusMQ);
485     mWriterClient = gettid();
486     return OK;
487 }
488 
getRenderPosition(uint32_t * dspFrames)489 status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
490     if (mStream == 0) return NO_INIT;
491     Result retval;
492     Return<void> ret = mStream->getRenderPosition(
493             [&](Result r, uint32_t d) {
494                 retval = r;
495                 if (retval == Result::OK) {
496                     *dspFrames = d;
497                 }
498             });
499     return processReturn("getRenderPosition", ret, retval);
500 }
501 
getNextWriteTimestamp(int64_t * timestamp)502 status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
503     if (mStream == 0) return NO_INIT;
504     Result retval;
505     Return<void> ret = mStream->getNextWriteTimestamp(
506             [&](Result r, int64_t t) {
507                 retval = r;
508                 if (retval == Result::OK) {
509                     *timestamp = t;
510                 }
511             });
512     return processReturn("getRenderPosition", ret, retval);
513 }
514 
setCallback(wp<StreamOutHalInterfaceCallback> callback)515 status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
516     if (mStream == 0) return NO_INIT;
517     status_t status = processReturn(
518             "setCallback", mStream->setCallback(new StreamOutCallback(this)));
519     if (status == OK) {
520         mCallback = callback;
521     }
522     return status;
523 }
524 
supportsPauseAndResume(bool * supportsPause,bool * supportsResume)525 status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
526     if (mStream == 0) return NO_INIT;
527     Return<void> ret = mStream->supportsPauseAndResume(
528             [&](bool p, bool r) {
529                 *supportsPause = p;
530                 *supportsResume = r;
531             });
532     return processReturn("supportsPauseAndResume", ret);
533 }
534 
pause()535 status_t StreamOutHalHidl::pause() {
536     if (mStream == 0) return NO_INIT;
537     return processReturn("pause", mStream->pause());
538 }
539 
resume()540 status_t StreamOutHalHidl::resume() {
541     if (mStream == 0) return NO_INIT;
542     return processReturn("pause", mStream->resume());
543 }
544 
supportsDrain(bool * supportsDrain)545 status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
546     if (mStream == 0) return NO_INIT;
547     return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
548 }
549 
drain(bool earlyNotify)550 status_t StreamOutHalHidl::drain(bool earlyNotify) {
551     if (mStream == 0) return NO_INIT;
552     return processReturn(
553             "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
554 }
555 
flush()556 status_t StreamOutHalHidl::flush() {
557     if (mStream == 0) return NO_INIT;
558     return processReturn("pause", mStream->flush());
559 }
560 
getPresentationPosition(uint64_t * frames,struct timespec * timestamp)561 status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
562     if (mStream == 0) return NO_INIT;
563     if (mWriterClient == gettid() && mCommandMQ) {
564         return callWriterThread(
565                 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
566                 [&](const WriteStatus& writeStatus) {
567                     *frames = writeStatus.reply.presentationPosition.frames;
568                     timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
569                     timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
570                 });
571     } else {
572         Result retval;
573         Return<void> ret = mStream->getPresentationPosition(
574                 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
575                     retval = r;
576                     if (retval == Result::OK) {
577                         *frames = hidlFrames;
578                         timestamp->tv_sec = hidlTimeStamp.tvSec;
579                         timestamp->tv_nsec = hidlTimeStamp.tvNSec;
580                     }
581                 });
582         return processReturn("getPresentationPosition", ret, retval);
583     }
584 }
585 
586 #if MAJOR_VERSION == 2
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata &)587 status_t StreamOutHalHidl::updateSourceMetadata(
588         const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
589     // Audio HAL V2.0 does not support propagating source metadata
590     return INVALID_OPERATION;
591 }
592 #elif MAJOR_VERSION >= 4
593 /** Transform a standard collection to an HIDL vector. */
594 template <class Values, class ElementConverter>
transformToHidlVec(const Values & values,ElementConverter converter)595 static auto transformToHidlVec(const Values& values, ElementConverter converter) {
596     hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
597     using namespace std;
598     transform(begin(values), end(values), begin(result), converter);
599     return result;
600 }
601 
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata & sourceMetadata)602 status_t StreamOutHalHidl::updateSourceMetadata(
603         const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
604     CPP_VERSION::SourceMetadata halMetadata = {
605         .tracks = transformToHidlVec(sourceMetadata.tracks,
606               [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
607                   return {
608                     .usage=static_cast<AudioUsage>(metadata.usage),
609                     .contentType=static_cast<AudioContentType>(metadata.content_type),
610                     .gain=metadata.gain,
611                   };
612               })};
613     return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
614 }
615 #endif
616 
onWriteReady()617 void StreamOutHalHidl::onWriteReady() {
618     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
619     if (callback == 0) return;
620     ALOGV("asyncCallback onWriteReady");
621     callback->onWriteReady();
622 }
623 
onDrainReady()624 void StreamOutHalHidl::onDrainReady() {
625     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
626     if (callback == 0) return;
627     ALOGV("asyncCallback onDrainReady");
628     callback->onDrainReady();
629 }
630 
onError()631 void StreamOutHalHidl::onError() {
632     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
633     if (callback == 0) return;
634     ALOGV("asyncCallback onError");
635     callback->onError();
636 }
637 
638 
StreamInHalHidl(const sp<IStreamIn> & stream)639 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
640         : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
641 }
642 
~StreamInHalHidl()643 StreamInHalHidl::~StreamInHalHidl() {
644     if (mStream != 0) {
645         processReturn("close", mStream->close());
646         mStream.clear();
647         hardware::IPCThreadState::self()->flushCommands();
648     }
649     if (mEfGroup) {
650         EventFlag::deleteEventFlag(&mEfGroup);
651     }
652 }
653 
getFrameSize(size_t * size)654 status_t StreamInHalHidl::getFrameSize(size_t *size) {
655     if (mStream == 0) return NO_INIT;
656     return processReturn("getFrameSize", mStream->getFrameSize(), size);
657 }
658 
setGain(float gain)659 status_t StreamInHalHidl::setGain(float gain) {
660     if (mStream == 0) return NO_INIT;
661     return processReturn("setGain", mStream->setGain(gain));
662 }
663 
read(void * buffer,size_t bytes,size_t * read)664 status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
665     if (mStream == 0) return NO_INIT;
666     *read = 0;
667 
668     if (bytes == 0 && !mDataMQ) {
669         // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
670         return OK;
671     }
672 
673     status_t status;
674     if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
675         return status;
676     }
677 
678     ReadParameters params;
679     params.command = ReadCommand::READ;
680     params.params.read = bytes;
681     status = callReaderThread(params, "read",
682             [&](const ReadStatus& readStatus) {
683                 const size_t availToRead = mDataMQ->availableToRead();
684                 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
685                     ALOGE("data message queue read failed for \"read\"");
686                 }
687                 ALOGW_IF(availToRead != readStatus.reply.read,
688                         "HAL read report inconsistent: mq = %d, status = %d",
689                         (int32_t)availToRead, (int32_t)readStatus.reply.read);
690                 *read = readStatus.reply.read;
691             });
692     mStreamPowerLog.log(buffer, *read);
693     return status;
694 }
695 
callReaderThread(const ReadParameters & params,const char * cmdName,StreamInHalHidl::ReaderCallback callback)696 status_t StreamInHalHidl::callReaderThread(
697         const ReadParameters& params, const char* cmdName,
698         StreamInHalHidl::ReaderCallback callback) {
699     if (!mCommandMQ->write(&params)) {
700         ALOGW("command message queue write failed");
701         return -EAGAIN;
702     }
703     mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
704 
705     // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
706     uint32_t efState = 0;
707 retry:
708     status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
709     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
710         ReadStatus readStatus;
711         readStatus.retval = Result::NOT_INITIALIZED;
712         if (!mStatusMQ->read(&readStatus)) {
713             ALOGE("status message read failed for \"%s\"", cmdName);
714         }
715          if (readStatus.retval == Result::OK) {
716             ret = OK;
717             callback(readStatus);
718         } else {
719             ret = processReturn(cmdName, readStatus.retval);
720         }
721         return ret;
722     }
723     if (ret == -EAGAIN || ret == -EINTR) {
724         // Spurious wakeup. This normally retries no more than once.
725         goto retry;
726     }
727     return ret;
728 }
729 
prepareForReading(size_t bufferSize)730 status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
731     std::unique_ptr<CommandMQ> tempCommandMQ;
732     std::unique_ptr<DataMQ> tempDataMQ;
733     std::unique_ptr<StatusMQ> tempStatusMQ;
734     Result retval;
735     pid_t halThreadPid, halThreadTid;
736     Return<void> ret = mStream->prepareForReading(
737             1, bufferSize,
738             [&](Result r,
739                     const CommandMQ::Descriptor& commandMQ,
740                     const DataMQ::Descriptor& dataMQ,
741                     const StatusMQ::Descriptor& statusMQ,
742                     const ThreadInfo& halThreadInfo) {
743                 retval = r;
744                 if (retval == Result::OK) {
745                     tempCommandMQ.reset(new CommandMQ(commandMQ));
746                     tempDataMQ.reset(new DataMQ(dataMQ));
747                     tempStatusMQ.reset(new StatusMQ(statusMQ));
748                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
749                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
750                     }
751                     halThreadPid = halThreadInfo.pid;
752                     halThreadTid = halThreadInfo.tid;
753                 }
754             });
755     if (!ret.isOk() || retval != Result::OK) {
756         return processReturn("prepareForReading", ret, retval);
757     }
758     if (!tempCommandMQ || !tempCommandMQ->isValid() ||
759             !tempDataMQ || !tempDataMQ->isValid() ||
760             !tempStatusMQ || !tempStatusMQ->isValid() ||
761             !mEfGroup) {
762         ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
763         ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
764                 "Command message queue for writing is invalid");
765         ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
766         ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
767         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
768         ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
769                 "Status message queue for reading is invalid");
770         ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
771         return NO_INIT;
772     }
773     requestHalThreadPriority(halThreadPid, halThreadTid);
774 
775     mCommandMQ = std::move(tempCommandMQ);
776     mDataMQ = std::move(tempDataMQ);
777     mStatusMQ = std::move(tempStatusMQ);
778     mReaderClient = gettid();
779     return OK;
780 }
781 
getInputFramesLost(uint32_t * framesLost)782 status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
783     if (mStream == 0) return NO_INIT;
784     return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
785 }
786 
getCapturePosition(int64_t * frames,int64_t * time)787 status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
788     if (mStream == 0) return NO_INIT;
789     if (mReaderClient == gettid() && mCommandMQ) {
790         ReadParameters params;
791         params.command = ReadCommand::GET_CAPTURE_POSITION;
792         return callReaderThread(params, "getCapturePosition",
793                 [&](const ReadStatus& readStatus) {
794                     *frames = readStatus.reply.capturePosition.frames;
795                     *time = readStatus.reply.capturePosition.time;
796                 });
797     } else {
798         Result retval;
799         Return<void> ret = mStream->getCapturePosition(
800                 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
801                     retval = r;
802                     if (retval == Result::OK) {
803                         *frames = hidlFrames;
804                         *time = hidlTime;
805                     }
806                 });
807         return processReturn("getCapturePosition", ret, retval);
808     }
809 }
810 
811 #if MAJOR_VERSION == 2
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphones __unused)812 status_t StreamInHalHidl::getActiveMicrophones(
813         std::vector<media::MicrophoneInfo> *microphones __unused) {
814     if (mStream == 0) return NO_INIT;
815     return INVALID_OPERATION;
816 }
817 
updateSinkMetadata(const StreamInHalInterface::SinkMetadata &)818 status_t StreamInHalHidl::updateSinkMetadata(
819         const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
820     // Audio HAL V2.0 does not support propagating sink metadata
821     return INVALID_OPERATION;
822 }
823 
824 #elif MAJOR_VERSION >= 4
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphonesInfo)825 status_t StreamInHalHidl::getActiveMicrophones(
826         std::vector<media::MicrophoneInfo> *microphonesInfo) {
827     if (!mStream) return NO_INIT;
828     Result retval;
829     Return<void> ret = mStream->getActiveMicrophones(
830             [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
831         retval = r;
832         for (size_t k = 0; k < micArrayHal.size(); k++) {
833             audio_microphone_characteristic_t dst;
834             // convert
835             microphoneInfoToHal(micArrayHal[k], &dst);
836             media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
837             microphonesInfo->push_back(microphone);
838         }
839     });
840     return processReturn("getActiveMicrophones", ret, retval);
841 }
842 
updateSinkMetadata(const StreamInHalInterface::SinkMetadata & sinkMetadata)843 status_t StreamInHalHidl::updateSinkMetadata(const
844         StreamInHalInterface::SinkMetadata& sinkMetadata) {
845     CPP_VERSION::SinkMetadata halMetadata = {
846         .tracks = transformToHidlVec(sinkMetadata.tracks,
847               [](const record_track_metadata& metadata) -> RecordTrackMetadata {
848                   return {
849                     .source=static_cast<AudioSource>(metadata.source),
850                     .gain=metadata.gain,
851                   };
852               })};
853     return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
854 }
855 #endif
856 
857 #if MAJOR_VERSION < 5
setPreferredMicrophoneDirection(audio_microphone_direction_t direction __unused)858 status_t StreamInHalHidl::setPreferredMicrophoneDirection(
859             audio_microphone_direction_t direction __unused) {
860     if (mStream == 0) return NO_INIT;
861     return INVALID_OPERATION;
862 }
863 
setPreferredMicrophoneFieldDimension(float zoom __unused)864 status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
865     if (mStream == 0) return NO_INIT;
866     return INVALID_OPERATION;
867 }
868 #else
setPreferredMicrophoneDirection(audio_microphone_direction_t direction)869 status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
870     if (!mStream) return NO_INIT;
871     return processReturn("setPreferredMicrophoneDirection",
872         mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
873 }
874 
setPreferredMicrophoneFieldDimension(float zoom)875 status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
876     if (!mStream) return NO_INIT;
877     return processReturn("setPreferredMicrophoneFieldDimension",
878                 mStream->setMicrophoneFieldDimension(zoom));
879 }
880 #endif
881 
882 } // namespace CPP_VERSION
883 } // namespace android
884