blob: b641e823c6135a845ccc104643518547d6676f9f [file] [log] [blame]
Mikhail Naganov10548292016-10-31 10:39:47 -07001/*
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 "StreamInHAL"
Mikhail Naganovb29438e2016-12-22 09:21:34 -080018//#define LOG_NDEBUG 0
Mikhail Naganovb0abafb2017-01-31 17:24:48 -080019#define ATRACE_TAG ATRACE_TAG_AUDIO
Mikhail Naganov10548292016-10-31 10:39:47 -070020
Yifan Hongf9d30342016-11-30 13:45:34 -080021#include <android/log.h>
Mikhail Naganovb29438e2016-12-22 09:21:34 -080022#include <hardware/audio.h>
Mikhail Naganovb0abafb2017-01-31 17:24:48 -080023#include <utils/Trace.h>
Mikhail Naganov10548292016-10-31 10:39:47 -070024
25#include "StreamIn.h"
26
Mikhail Naganovb29438e2016-12-22 09:21:34 -080027using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
28
Mikhail Naganov10548292016-10-31 10:39:47 -070029namespace android {
30namespace hardware {
31namespace audio {
32namespace V2_0 {
33namespace implementation {
34
Mikhail Naganova1db22a2017-02-07 10:49:18 -080035using ::android::hardware::audio::common::V2_0::ThreadInfo;
36
Mikhail Naganovb29438e2016-12-22 09:21:34 -080037namespace {
38
39class ReadThread : public Thread {
40 public:
41 // ReadThread's lifespan never exceeds StreamIn's lifespan.
42 ReadThread(std::atomic<bool>* stop,
43 audio_stream_in_t* stream,
Mikhail Naganova468fa82017-01-31 13:56:02 -080044 StreamIn::CommandMQ* commandMQ,
Mikhail Naganovb29438e2016-12-22 09:21:34 -080045 StreamIn::DataMQ* dataMQ,
46 StreamIn::StatusMQ* statusMQ,
Mikhail Naganova1db22a2017-02-07 10:49:18 -080047 EventFlag* efGroup)
Mikhail Naganovb29438e2016-12-22 09:21:34 -080048 : Thread(false /*canCallJava*/),
49 mStop(stop),
50 mStream(stream),
Mikhail Naganova468fa82017-01-31 13:56:02 -080051 mCommandMQ(commandMQ),
Mikhail Naganovb29438e2016-12-22 09:21:34 -080052 mDataMQ(dataMQ),
53 mStatusMQ(statusMQ),
54 mEfGroup(efGroup),
Mikhail Naganovb29438e2016-12-22 09:21:34 -080055 mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
56 }
57 virtual ~ReadThread() {}
58
Mikhail Naganovb29438e2016-12-22 09:21:34 -080059 private:
60 std::atomic<bool>* mStop;
61 audio_stream_in_t* mStream;
Mikhail Naganova468fa82017-01-31 13:56:02 -080062 StreamIn::CommandMQ* mCommandMQ;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080063 StreamIn::DataMQ* mDataMQ;
64 StreamIn::StatusMQ* mStatusMQ;
65 EventFlag* mEfGroup;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080066 std::unique_ptr<uint8_t[]> mBuffer;
Mikhail Naganova468fa82017-01-31 13:56:02 -080067 IStreamIn::ReadParameters mParameters;
68 IStreamIn::ReadStatus mStatus;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080069
70 bool threadLoop() override;
Mikhail Naganova468fa82017-01-31 13:56:02 -080071
72 void doGetCapturePosition();
73 void doRead();
Mikhail Naganovb29438e2016-12-22 09:21:34 -080074};
75
Mikhail Naganova468fa82017-01-31 13:56:02 -080076void ReadThread::doRead() {
77 size_t availableToWrite = mDataMQ->availableToWrite();
78 size_t requestedToRead = mParameters.params.read;
79 if (requestedToRead > availableToWrite) {
80 ALOGW("truncating read data from %d to %d due to insufficient data queue space",
81 (int32_t)requestedToRead, (int32_t)availableToWrite);
82 requestedToRead = availableToWrite;
83 }
84 ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
85 mStatus.retval = Result::OK;
86 uint64_t read = 0;
87 if (readResult >= 0) {
88 mStatus.reply.read = readResult;
89 if (!mDataMQ->write(&mBuffer[0], readResult)) {
90 ALOGW("data message queue write failed");
91 }
92 } else {
93 mStatus.retval = Stream::analyzeStatus("read", readResult);
94 }
95}
96
97void ReadThread::doGetCapturePosition() {
98 mStatus.retval = StreamIn::getCapturePositionImpl(
99 mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
100}
101
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800102bool ReadThread::threadLoop() {
103 // This implementation doesn't return control back to the Thread until it decides to stop,
104 // as the Thread uses mutexes, and this can lead to priority inversion.
105 while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800106 uint32_t efState = 0;
Mikhail Naganove8674562017-02-10 08:37:19 -0800107 mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800108 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
109 continue; // Nothing to do.
110 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800111 if (!mCommandMQ->read(&mParameters)) {
112 continue; // Nothing to do.
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800113 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800114 mStatus.replyTo = mParameters.command;
115 switch (mParameters.command) {
116 case IStreamIn::ReadCommand::READ:
117 doRead();
118 break;
119 case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
120 doGetCapturePosition();
121 break;
122 default:
123 ALOGE("Unknown read thread command code %d", mParameters.command);
124 mStatus.retval = Result::NOT_SUPPORTED;
125 break;
126 }
127 if (!mStatusMQ->write(&mStatus)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800128 ALOGW("status message queue write failed");
129 }
130 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
131 }
132
133 return false;
134}
135
136} // namespace
137
Mikhail Naganov10548292016-10-31 10:39:47 -0700138StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800139 : mIsClosed(false), mDevice(device), mStream(stream),
Eric Laurent7deb7da2016-12-15 19:15:45 -0800140 mStreamCommon(new Stream(&stream->common)),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800141 mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
142 mEfGroup(nullptr), mStopReadThread(false) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700143}
144
145StreamIn::~StreamIn() {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800146 ATRACE_CALL();
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800147 close();
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800148 if (mReadThread.get()) {
149 ATRACE_NAME("mReadThread->join");
150 status_t status = mReadThread->join();
151 ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
152 }
153 if (mEfGroup) {
154 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
155 ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
156 }
157 mDevice->close_input_stream(mDevice, mStream);
Mikhail Naganov10548292016-10-31 10:39:47 -0700158 mStream = nullptr;
159 mDevice = nullptr;
160}
161
162// Methods from ::android::hardware::audio::V2_0::IStream follow.
163Return<uint64_t> StreamIn::getFrameSize() {
164 return audio_stream_in_frame_size(mStream);
165}
166
167Return<uint64_t> StreamIn::getFrameCount() {
168 return mStreamCommon->getFrameCount();
169}
170
171Return<uint64_t> StreamIn::getBufferSize() {
172 return mStreamCommon->getBufferSize();
173}
174
175Return<uint32_t> StreamIn::getSampleRate() {
176 return mStreamCommon->getSampleRate();
177}
178
179Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
180 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
181}
182
183Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
184 return mStreamCommon->setSampleRate(sampleRateHz);
185}
186
187Return<AudioChannelMask> StreamIn::getChannelMask() {
188 return mStreamCommon->getChannelMask();
189}
190
191Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
192 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
193}
194
195Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
196 return mStreamCommon->setChannelMask(mask);
197}
198
199Return<AudioFormat> StreamIn::getFormat() {
200 return mStreamCommon->getFormat();
201}
202
203Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
204 return mStreamCommon->getSupportedFormats(_hidl_cb);
205}
206
207Return<Result> StreamIn::setFormat(AudioFormat format) {
208 return mStreamCommon->setFormat(format);
209}
210
211Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
212 return mStreamCommon->getAudioProperties(_hidl_cb);
213}
214
215Return<Result> StreamIn::addEffect(uint64_t effectId) {
216 return mStreamCommon->addEffect(effectId);
217}
218
219Return<Result> StreamIn::removeEffect(uint64_t effectId) {
220 return mStreamCommon->removeEffect(effectId);
221}
222
223Return<Result> StreamIn::standby() {
224 return mStreamCommon->standby();
225}
226
227Return<AudioDevice> StreamIn::getDevice() {
228 return mStreamCommon->getDevice();
229}
230
231Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
232 return mStreamCommon->setDevice(address);
233}
234
235Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
236 return mStreamCommon->setConnectedState(address, connected);
237}
238
239Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
240 return mStreamCommon->setHwAvSync(hwAvSync);
241}
242
243Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
244 return mStreamCommon->getParameters(keys, _hidl_cb);
245}
246
247Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
248 return mStreamCommon->setParameters(parameters);
249}
250
Martijn Coenen70b9a152016-11-18 15:29:32 +0100251Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700252 return mStreamCommon->debugDump(fd);
253}
254
Eric Laurent7deb7da2016-12-15 19:15:45 -0800255Return<Result> StreamIn::start() {
256 return mStreamMmap->start();
257}
258
259Return<Result> StreamIn::stop() {
260 return mStreamMmap->stop();
261}
262
263Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
264 return mStreamMmap->createMmapBuffer(
265 minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
266}
267
268Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
269 return mStreamMmap->getMmapPosition(_hidl_cb);
270}
Mikhail Naganov10548292016-10-31 10:39:47 -0700271
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800272Return<Result> StreamIn::close() {
273 if (mIsClosed) return Result::INVALID_STATE;
274 mIsClosed = true;
275 if (mReadThread.get()) {
276 mStopReadThread.store(true, std::memory_order_release);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800277 }
278 if (mEfGroup) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800279 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800280 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800281 return Result::OK;
282}
283
Mikhail Naganov10548292016-10-31 10:39:47 -0700284// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
285Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
286 int halSource;
287 Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
288 AudioSource source(AudioSource::DEFAULT);
289 if (retval == Result::OK) {
290 source = AudioSource(halSource);
291 }
292 _hidl_cb(retval, source);
293 return Void();
294}
295
296Return<Result> StreamIn::setGain(float gain) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800297 return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
Mikhail Naganov10548292016-10-31 10:39:47 -0700298}
299
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800300Return<void> StreamIn::prepareForReading(
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800301 uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800302 status_t status;
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800303 ThreadInfo threadInfo = { 0, 0 };
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800304 // Create message queues.
305 if (mDataMQ) {
306 ALOGE("the client attempts to call prepareForReading twice");
307 _hidl_cb(Result::INVALID_STATE,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800308 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800309 return Void();
Mikhail Naganov10548292016-10-31 10:39:47 -0700310 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800311 std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800312 std::unique_ptr<DataMQ> tempDataMQ(
313 new DataMQ(frameSize * framesCount, true /* EventFlag */));
314 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
Mikhail Naganova468fa82017-01-31 13:56:02 -0800315 if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
316 ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800317 ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
318 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
319 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800320 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800321 return Void();
322 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800323 status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
324 if (status != OK || !mEfGroup) {
325 ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
326 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800327 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800328 return Void();
329 }
330
331 // Create and launch the thread.
332 mReadThread = new ReadThread(
333 &mStopReadThread,
334 mStream,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800335 tempCommandMQ.get(),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800336 tempDataMQ.get(),
337 tempStatusMQ.get(),
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800338 mEfGroup);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800339 status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
340 if (status != OK) {
341 ALOGW("failed to start reader thread: %s", strerror(-status));
342 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800343 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800344 return Void();
345 }
346
Mikhail Naganova468fa82017-01-31 13:56:02 -0800347 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800348 mDataMQ = std::move(tempDataMQ);
349 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800350 threadInfo.pid = getpid();
351 threadInfo.tid = mReadThread->getTid();
352 _hidl_cb(Result::OK,
353 *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
354 threadInfo);
Mikhail Naganov10548292016-10-31 10:39:47 -0700355 return Void();
356}
357
358Return<uint32_t> StreamIn::getInputFramesLost() {
359 return mStream->get_input_frames_lost(mStream);
360}
361
Mikhail Naganova468fa82017-01-31 13:56:02 -0800362// static
363Result StreamIn::getCapturePositionImpl(
364 audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700365 Result retval(Result::NOT_SUPPORTED);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800366 if (stream->get_capture_position != NULL) return retval;
367 int64_t halFrames, halTime;
368 retval = Stream::analyzeStatus(
369 "get_capture_position",
370 stream->get_capture_position(stream, &halFrames, &halTime),
371 // HAL may have a stub function, always returning ENOSYS, don't
372 // spam the log in this case.
373 ENOSYS);
374 if (retval == Result::OK) {
375 *frames = halFrames;
376 *time = halTime;
Mikhail Naganov10548292016-10-31 10:39:47 -0700377 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800378 return retval;
379};
380
381Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
382 uint64_t frames = 0, time = 0;
383 Result retval = getCapturePositionImpl(mStream, &frames, &time);
Mikhail Naganov10548292016-10-31 10:39:47 -0700384 _hidl_cb(retval, frames, time);
385 return Void();
386}
387
388} // namespace implementation
389} // namespace V2_0
390} // namespace audio
391} // namespace hardware
392} // namespace android