blob: 97f8307bdfb229be19b7c36a667487d54bcb4c6f [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>
Kevin Rocard67d55082017-03-31 19:34:04 -070023#include <memory>
Mikhail Naganovb0abafb2017-01-31 17:24:48 -080024#include <utils/Trace.h>
Mikhail Naganov10548292016-10-31 10:39:47 -070025
26#include "StreamIn.h"
27
Mikhail Naganovb29438e2016-12-22 09:21:34 -080028using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
29
Mikhail Naganov10548292016-10-31 10:39:47 -070030namespace android {
31namespace hardware {
32namespace audio {
33namespace V2_0 {
34namespace implementation {
35
Mikhail Naganova1db22a2017-02-07 10:49:18 -080036using ::android::hardware::audio::common::V2_0::ThreadInfo;
37
Mikhail Naganovb29438e2016-12-22 09:21:34 -080038namespace {
39
40class ReadThread : public Thread {
41 public:
42 // ReadThread's lifespan never exceeds StreamIn's lifespan.
43 ReadThread(std::atomic<bool>* stop,
44 audio_stream_in_t* stream,
Mikhail Naganova468fa82017-01-31 13:56:02 -080045 StreamIn::CommandMQ* commandMQ,
Mikhail Naganovb29438e2016-12-22 09:21:34 -080046 StreamIn::DataMQ* dataMQ,
47 StreamIn::StatusMQ* statusMQ,
Mikhail Naganova1db22a2017-02-07 10:49:18 -080048 EventFlag* efGroup)
Mikhail Naganovb29438e2016-12-22 09:21:34 -080049 : Thread(false /*canCallJava*/),
50 mStop(stop),
51 mStream(stream),
Mikhail Naganova468fa82017-01-31 13:56:02 -080052 mCommandMQ(commandMQ),
Mikhail Naganovb29438e2016-12-22 09:21:34 -080053 mDataMQ(dataMQ),
54 mStatusMQ(statusMQ),
55 mEfGroup(efGroup),
Kevin Rocard67d55082017-03-31 19:34:04 -070056 mBuffer(nullptr) {
57 }
58 bool init() {
59 mBuffer.reset(new(std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
60 return mBuffer != nullptr;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080061 }
62 virtual ~ReadThread() {}
63
Mikhail Naganovb29438e2016-12-22 09:21:34 -080064 private:
65 std::atomic<bool>* mStop;
66 audio_stream_in_t* mStream;
Mikhail Naganova468fa82017-01-31 13:56:02 -080067 StreamIn::CommandMQ* mCommandMQ;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080068 StreamIn::DataMQ* mDataMQ;
69 StreamIn::StatusMQ* mStatusMQ;
70 EventFlag* mEfGroup;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080071 std::unique_ptr<uint8_t[]> mBuffer;
Mikhail Naganova468fa82017-01-31 13:56:02 -080072 IStreamIn::ReadParameters mParameters;
73 IStreamIn::ReadStatus mStatus;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080074
75 bool threadLoop() override;
Mikhail Naganova468fa82017-01-31 13:56:02 -080076
77 void doGetCapturePosition();
78 void doRead();
Mikhail Naganovb29438e2016-12-22 09:21:34 -080079};
80
Mikhail Naganova468fa82017-01-31 13:56:02 -080081void ReadThread::doRead() {
82 size_t availableToWrite = mDataMQ->availableToWrite();
83 size_t requestedToRead = mParameters.params.read;
84 if (requestedToRead > availableToWrite) {
85 ALOGW("truncating read data from %d to %d due to insufficient data queue space",
86 (int32_t)requestedToRead, (int32_t)availableToWrite);
87 requestedToRead = availableToWrite;
88 }
89 ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
90 mStatus.retval = Result::OK;
91 uint64_t read = 0;
92 if (readResult >= 0) {
93 mStatus.reply.read = readResult;
94 if (!mDataMQ->write(&mBuffer[0], readResult)) {
95 ALOGW("data message queue write failed");
96 }
97 } else {
98 mStatus.retval = Stream::analyzeStatus("read", readResult);
99 }
100}
101
102void ReadThread::doGetCapturePosition() {
103 mStatus.retval = StreamIn::getCapturePositionImpl(
104 mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
105}
106
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800107bool ReadThread::threadLoop() {
108 // This implementation doesn't return control back to the Thread until it decides to stop,
109 // as the Thread uses mutexes, and this can lead to priority inversion.
110 while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800111 uint32_t efState = 0;
Mikhail Naganove8674562017-02-10 08:37:19 -0800112 mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800113 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
114 continue; // Nothing to do.
115 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800116 if (!mCommandMQ->read(&mParameters)) {
117 continue; // Nothing to do.
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800118 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800119 mStatus.replyTo = mParameters.command;
120 switch (mParameters.command) {
121 case IStreamIn::ReadCommand::READ:
122 doRead();
123 break;
124 case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
125 doGetCapturePosition();
126 break;
127 default:
128 ALOGE("Unknown read thread command code %d", mParameters.command);
129 mStatus.retval = Result::NOT_SUPPORTED;
130 break;
131 }
132 if (!mStatusMQ->write(&mStatus)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800133 ALOGW("status message queue write failed");
134 }
135 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
136 }
137
138 return false;
139}
140
141} // namespace
142
Mikhail Naganov936279e2017-03-29 09:31:18 -0700143StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800144 : mIsClosed(false), mDevice(device), mStream(stream),
Eric Laurent7deb7da2016-12-15 19:15:45 -0800145 mStreamCommon(new Stream(&stream->common)),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800146 mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
147 mEfGroup(nullptr), mStopReadThread(false) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700148}
149
150StreamIn::~StreamIn() {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800151 ATRACE_CALL();
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800152 close();
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800153 if (mReadThread.get()) {
154 ATRACE_NAME("mReadThread->join");
155 status_t status = mReadThread->join();
156 ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
157 }
158 if (mEfGroup) {
159 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
160 ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
161 }
Mikhail Naganov936279e2017-03-29 09:31:18 -0700162 mDevice->closeInputStream(mStream);
Mikhail Naganov10548292016-10-31 10:39:47 -0700163 mStream = nullptr;
Mikhail Naganov10548292016-10-31 10:39:47 -0700164}
165
166// Methods from ::android::hardware::audio::V2_0::IStream follow.
167Return<uint64_t> StreamIn::getFrameSize() {
168 return audio_stream_in_frame_size(mStream);
169}
170
171Return<uint64_t> StreamIn::getFrameCount() {
172 return mStreamCommon->getFrameCount();
173}
174
175Return<uint64_t> StreamIn::getBufferSize() {
176 return mStreamCommon->getBufferSize();
177}
178
179Return<uint32_t> StreamIn::getSampleRate() {
180 return mStreamCommon->getSampleRate();
181}
182
183Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
184 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
185}
186
187Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
188 return mStreamCommon->setSampleRate(sampleRateHz);
189}
190
191Return<AudioChannelMask> StreamIn::getChannelMask() {
192 return mStreamCommon->getChannelMask();
193}
194
195Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
196 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
197}
198
199Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
200 return mStreamCommon->setChannelMask(mask);
201}
202
203Return<AudioFormat> StreamIn::getFormat() {
204 return mStreamCommon->getFormat();
205}
206
207Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
208 return mStreamCommon->getSupportedFormats(_hidl_cb);
209}
210
211Return<Result> StreamIn::setFormat(AudioFormat format) {
212 return mStreamCommon->setFormat(format);
213}
214
215Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
216 return mStreamCommon->getAudioProperties(_hidl_cb);
217}
218
219Return<Result> StreamIn::addEffect(uint64_t effectId) {
220 return mStreamCommon->addEffect(effectId);
221}
222
223Return<Result> StreamIn::removeEffect(uint64_t effectId) {
224 return mStreamCommon->removeEffect(effectId);
225}
226
227Return<Result> StreamIn::standby() {
228 return mStreamCommon->standby();
229}
230
231Return<AudioDevice> StreamIn::getDevice() {
232 return mStreamCommon->getDevice();
233}
234
235Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
236 return mStreamCommon->setDevice(address);
237}
238
239Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
240 return mStreamCommon->setConnectedState(address, connected);
241}
242
243Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
244 return mStreamCommon->setHwAvSync(hwAvSync);
245}
246
247Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
248 return mStreamCommon->getParameters(keys, _hidl_cb);
249}
250
251Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
252 return mStreamCommon->setParameters(parameters);
253}
254
Martijn Coenen70b9a152016-11-18 15:29:32 +0100255Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700256 return mStreamCommon->debugDump(fd);
257}
258
Eric Laurent7deb7da2016-12-15 19:15:45 -0800259Return<Result> StreamIn::start() {
260 return mStreamMmap->start();
261}
262
263Return<Result> StreamIn::stop() {
264 return mStreamMmap->stop();
265}
266
267Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
268 return mStreamMmap->createMmapBuffer(
269 minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
270}
271
272Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
273 return mStreamMmap->getMmapPosition(_hidl_cb);
274}
Mikhail Naganov10548292016-10-31 10:39:47 -0700275
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800276Return<Result> StreamIn::close() {
277 if (mIsClosed) return Result::INVALID_STATE;
278 mIsClosed = true;
279 if (mReadThread.get()) {
280 mStopReadThread.store(true, std::memory_order_release);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800281 }
282 if (mEfGroup) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800283 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800284 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800285 return Result::OK;
286}
287
Mikhail Naganov10548292016-10-31 10:39:47 -0700288// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
289Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
290 int halSource;
291 Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
292 AudioSource source(AudioSource::DEFAULT);
293 if (retval == Result::OK) {
294 source = AudioSource(halSource);
295 }
296 _hidl_cb(retval, source);
297 return Void();
298}
299
300Return<Result> StreamIn::setGain(float gain) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800301 return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
Mikhail Naganov10548292016-10-31 10:39:47 -0700302}
303
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800304Return<void> StreamIn::prepareForReading(
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800305 uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800306 status_t status;
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800307 ThreadInfo threadInfo = { 0, 0 };
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800308 // Create message queues.
309 if (mDataMQ) {
310 ALOGE("the client attempts to call prepareForReading twice");
311 _hidl_cb(Result::INVALID_STATE,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800312 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800313 return Void();
Mikhail Naganov10548292016-10-31 10:39:47 -0700314 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800315 std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800316 std::unique_ptr<DataMQ> tempDataMQ(
317 new DataMQ(frameSize * framesCount, true /* EventFlag */));
318 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
Mikhail Naganova468fa82017-01-31 13:56:02 -0800319 if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
320 ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800321 ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
322 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
323 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800324 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800325 return Void();
326 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800327 status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
328 if (status != OK || !mEfGroup) {
329 ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
330 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800331 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800332 return Void();
333 }
334
335 // Create and launch the thread.
Kevin Rocard67d55082017-03-31 19:34:04 -0700336 auto tempReadThread = std::make_unique<ReadThread>(
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800337 &mStopReadThread,
338 mStream,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800339 tempCommandMQ.get(),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800340 tempDataMQ.get(),
341 tempStatusMQ.get(),
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800342 mEfGroup);
Kevin Rocard67d55082017-03-31 19:34:04 -0700343 if (!tempReadThread->init()) {
344 _hidl_cb(Result::INVALID_ARGUMENTS,
345 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
346 return Void();
347 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800348 status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
349 if (status != OK) {
350 ALOGW("failed to start reader thread: %s", strerror(-status));
351 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800352 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800353 return Void();
354 }
355
Mikhail Naganova468fa82017-01-31 13:56:02 -0800356 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800357 mDataMQ = std::move(tempDataMQ);
358 mStatusMQ = std::move(tempStatusMQ);
Kevin Rocard67d55082017-03-31 19:34:04 -0700359 mReadThread = tempReadThread.release();
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800360 threadInfo.pid = getpid();
361 threadInfo.tid = mReadThread->getTid();
362 _hidl_cb(Result::OK,
363 *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
364 threadInfo);
Mikhail Naganov10548292016-10-31 10:39:47 -0700365 return Void();
366}
367
368Return<uint32_t> StreamIn::getInputFramesLost() {
369 return mStream->get_input_frames_lost(mStream);
370}
371
Mikhail Naganova468fa82017-01-31 13:56:02 -0800372// static
373Result StreamIn::getCapturePositionImpl(
374 audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700375 Result retval(Result::NOT_SUPPORTED);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800376 if (stream->get_capture_position != NULL) return retval;
377 int64_t halFrames, halTime;
378 retval = Stream::analyzeStatus(
379 "get_capture_position",
380 stream->get_capture_position(stream, &halFrames, &halTime),
381 // HAL may have a stub function, always returning ENOSYS, don't
382 // spam the log in this case.
383 ENOSYS);
384 if (retval == Result::OK) {
385 *frames = halFrames;
386 *time = halTime;
Mikhail Naganov10548292016-10-31 10:39:47 -0700387 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800388 return retval;
389};
390
391Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
392 uint64_t frames = 0, time = 0;
393 Result retval = getCapturePositionImpl(mStream, &frames, &time);
Mikhail Naganov10548292016-10-31 10:39:47 -0700394 _hidl_cb(retval, frames, time);
395 return Void();
396}
397
398} // namespace implementation
399} // namespace V2_0
400} // namespace audio
401} // namespace hardware
402} // namespace android