blob: 8aba8c7b60cc26a9569cb6fd22fc550465f12842 [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>
23#include <mediautils/SchedulingPolicyService.h>
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 Naganovb29438e2016-12-22 09:21:34 -080036namespace {
37
38class ReadThread : public Thread {
39 public:
40 // ReadThread's lifespan never exceeds StreamIn's lifespan.
41 ReadThread(std::atomic<bool>* stop,
42 audio_stream_in_t* stream,
Mikhail Naganova468fa82017-01-31 13:56:02 -080043 StreamIn::CommandMQ* commandMQ,
Mikhail Naganovb29438e2016-12-22 09:21:34 -080044 StreamIn::DataMQ* dataMQ,
45 StreamIn::StatusMQ* statusMQ,
46 EventFlag* efGroup,
47 ThreadPriority threadPriority)
48 : 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),
55 mThreadPriority(threadPriority),
56 mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
57 }
58 virtual ~ReadThread() {}
59
60 status_t readyToRun() override;
61
62 private:
63 std::atomic<bool>* mStop;
64 audio_stream_in_t* mStream;
Mikhail Naganova468fa82017-01-31 13:56:02 -080065 StreamIn::CommandMQ* mCommandMQ;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080066 StreamIn::DataMQ* mDataMQ;
67 StreamIn::StatusMQ* mStatusMQ;
68 EventFlag* mEfGroup;
69 ThreadPriority mThreadPriority;
70 std::unique_ptr<uint8_t[]> mBuffer;
Mikhail Naganova468fa82017-01-31 13:56:02 -080071 IStreamIn::ReadParameters mParameters;
72 IStreamIn::ReadStatus mStatus;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080073
74 bool threadLoop() override;
Mikhail Naganova468fa82017-01-31 13:56:02 -080075
76 void doGetCapturePosition();
77 void doRead();
Mikhail Naganovb29438e2016-12-22 09:21:34 -080078};
79
80status_t ReadThread::readyToRun() {
81 if (mThreadPriority != ThreadPriority::NORMAL) {
82 int err = requestPriority(
83 getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/);
84 ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
85 static_cast<int>(mThreadPriority), getpid(), getTid(), err);
86 }
87 return OK;
88}
89
Mikhail Naganova468fa82017-01-31 13:56:02 -080090void ReadThread::doRead() {
91 size_t availableToWrite = mDataMQ->availableToWrite();
92 size_t requestedToRead = mParameters.params.read;
93 if (requestedToRead > availableToWrite) {
94 ALOGW("truncating read data from %d to %d due to insufficient data queue space",
95 (int32_t)requestedToRead, (int32_t)availableToWrite);
96 requestedToRead = availableToWrite;
97 }
98 ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
99 mStatus.retval = Result::OK;
100 uint64_t read = 0;
101 if (readResult >= 0) {
102 mStatus.reply.read = readResult;
103 if (!mDataMQ->write(&mBuffer[0], readResult)) {
104 ALOGW("data message queue write failed");
105 }
106 } else {
107 mStatus.retval = Stream::analyzeStatus("read", readResult);
108 }
109}
110
111void ReadThread::doGetCapturePosition() {
112 mStatus.retval = StreamIn::getCapturePositionImpl(
113 mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
114}
115
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800116bool ReadThread::threadLoop() {
117 // This implementation doesn't return control back to the Thread until it decides to stop,
118 // as the Thread uses mutexes, and this can lead to priority inversion.
119 while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
120 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
121 uint32_t efState = 0;
Mikhail Naganove8674562017-02-10 08:37:19 -0800122 mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800123 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
124 continue; // Nothing to do.
125 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800126 if (!mCommandMQ->read(&mParameters)) {
127 continue; // Nothing to do.
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800128 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800129 mStatus.replyTo = mParameters.command;
130 switch (mParameters.command) {
131 case IStreamIn::ReadCommand::READ:
132 doRead();
133 break;
134 case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
135 doGetCapturePosition();
136 break;
137 default:
138 ALOGE("Unknown read thread command code %d", mParameters.command);
139 mStatus.retval = Result::NOT_SUPPORTED;
140 break;
141 }
142 if (!mStatusMQ->write(&mStatus)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800143 ALOGW("status message queue write failed");
144 }
145 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
146 }
147
148 return false;
149}
150
151} // namespace
152
Mikhail Naganov10548292016-10-31 10:39:47 -0700153StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800154 : mIsClosed(false), mDevice(device), mStream(stream),
Eric Laurent7deb7da2016-12-15 19:15:45 -0800155 mStreamCommon(new Stream(&stream->common)),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800156 mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
157 mEfGroup(nullptr), mStopReadThread(false) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700158}
159
160StreamIn::~StreamIn() {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800161 ATRACE_CALL();
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800162 close();
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800163 if (mReadThread.get()) {
164 ATRACE_NAME("mReadThread->join");
165 status_t status = mReadThread->join();
166 ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
167 }
168 if (mEfGroup) {
169 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
170 ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
171 }
172 mDevice->close_input_stream(mDevice, mStream);
Mikhail Naganov10548292016-10-31 10:39:47 -0700173 mStream = nullptr;
174 mDevice = nullptr;
175}
176
177// Methods from ::android::hardware::audio::V2_0::IStream follow.
178Return<uint64_t> StreamIn::getFrameSize() {
179 return audio_stream_in_frame_size(mStream);
180}
181
182Return<uint64_t> StreamIn::getFrameCount() {
183 return mStreamCommon->getFrameCount();
184}
185
186Return<uint64_t> StreamIn::getBufferSize() {
187 return mStreamCommon->getBufferSize();
188}
189
190Return<uint32_t> StreamIn::getSampleRate() {
191 return mStreamCommon->getSampleRate();
192}
193
194Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
195 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
196}
197
198Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
199 return mStreamCommon->setSampleRate(sampleRateHz);
200}
201
202Return<AudioChannelMask> StreamIn::getChannelMask() {
203 return mStreamCommon->getChannelMask();
204}
205
206Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
207 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
208}
209
210Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
211 return mStreamCommon->setChannelMask(mask);
212}
213
214Return<AudioFormat> StreamIn::getFormat() {
215 return mStreamCommon->getFormat();
216}
217
218Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
219 return mStreamCommon->getSupportedFormats(_hidl_cb);
220}
221
222Return<Result> StreamIn::setFormat(AudioFormat format) {
223 return mStreamCommon->setFormat(format);
224}
225
226Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
227 return mStreamCommon->getAudioProperties(_hidl_cb);
228}
229
230Return<Result> StreamIn::addEffect(uint64_t effectId) {
231 return mStreamCommon->addEffect(effectId);
232}
233
234Return<Result> StreamIn::removeEffect(uint64_t effectId) {
235 return mStreamCommon->removeEffect(effectId);
236}
237
238Return<Result> StreamIn::standby() {
239 return mStreamCommon->standby();
240}
241
242Return<AudioDevice> StreamIn::getDevice() {
243 return mStreamCommon->getDevice();
244}
245
246Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
247 return mStreamCommon->setDevice(address);
248}
249
250Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
251 return mStreamCommon->setConnectedState(address, connected);
252}
253
254Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
255 return mStreamCommon->setHwAvSync(hwAvSync);
256}
257
258Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
259 return mStreamCommon->getParameters(keys, _hidl_cb);
260}
261
262Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
263 return mStreamCommon->setParameters(parameters);
264}
265
Martijn Coenen70b9a152016-11-18 15:29:32 +0100266Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700267 return mStreamCommon->debugDump(fd);
268}
269
Eric Laurent7deb7da2016-12-15 19:15:45 -0800270Return<Result> StreamIn::start() {
271 return mStreamMmap->start();
272}
273
274Return<Result> StreamIn::stop() {
275 return mStreamMmap->stop();
276}
277
278Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
279 return mStreamMmap->createMmapBuffer(
280 minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
281}
282
283Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
284 return mStreamMmap->getMmapPosition(_hidl_cb);
285}
Mikhail Naganov10548292016-10-31 10:39:47 -0700286
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800287Return<Result> StreamIn::close() {
288 if (mIsClosed) return Result::INVALID_STATE;
289 mIsClosed = true;
290 if (mReadThread.get()) {
291 mStopReadThread.store(true, std::memory_order_release);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800292 }
293 if (mEfGroup) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800294 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800295 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800296 return Result::OK;
297}
298
Mikhail Naganov10548292016-10-31 10:39:47 -0700299// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
300Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
301 int halSource;
302 Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
303 AudioSource source(AudioSource::DEFAULT);
304 if (retval == Result::OK) {
305 source = AudioSource(halSource);
306 }
307 _hidl_cb(retval, source);
308 return Void();
309}
310
311Return<Result> StreamIn::setGain(float gain) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800312 return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
Mikhail Naganov10548292016-10-31 10:39:47 -0700313}
314
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800315Return<void> StreamIn::prepareForReading(
316 uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
317 prepareForReading_cb _hidl_cb) {
318 status_t status;
319 // Create message queues.
320 if (mDataMQ) {
321 ALOGE("the client attempts to call prepareForReading twice");
322 _hidl_cb(Result::INVALID_STATE,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800323 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800324 return Void();
Mikhail Naganov10548292016-10-31 10:39:47 -0700325 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800326 std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800327 std::unique_ptr<DataMQ> tempDataMQ(
328 new DataMQ(frameSize * framesCount, true /* EventFlag */));
329 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
Mikhail Naganova468fa82017-01-31 13:56:02 -0800330 if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
331 ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800332 ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
333 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
334 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800335 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800336 return Void();
337 }
338 // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
339 status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
340 if (status != OK || !mEfGroup) {
341 ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
342 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800343 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800344 return Void();
345 }
346
347 // Create and launch the thread.
348 mReadThread = new ReadThread(
349 &mStopReadThread,
350 mStream,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800351 tempCommandMQ.get(),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800352 tempDataMQ.get(),
353 tempStatusMQ.get(),
354 mEfGroup,
355 threadPriority);
356 status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
357 if (status != OK) {
358 ALOGW("failed to start reader thread: %s", strerror(-status));
359 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800360 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800361 return Void();
362 }
363
Mikhail Naganova468fa82017-01-31 13:56:02 -0800364 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800365 mDataMQ = std::move(tempDataMQ);
366 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800367 _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc());
Mikhail Naganov10548292016-10-31 10:39:47 -0700368 return Void();
369}
370
371Return<uint32_t> StreamIn::getInputFramesLost() {
372 return mStream->get_input_frames_lost(mStream);
373}
374
Mikhail Naganova468fa82017-01-31 13:56:02 -0800375// static
376Result StreamIn::getCapturePositionImpl(
377 audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700378 Result retval(Result::NOT_SUPPORTED);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800379 if (stream->get_capture_position != NULL) return retval;
380 int64_t halFrames, halTime;
381 retval = Stream::analyzeStatus(
382 "get_capture_position",
383 stream->get_capture_position(stream, &halFrames, &halTime),
384 // HAL may have a stub function, always returning ENOSYS, don't
385 // spam the log in this case.
386 ENOSYS);
387 if (retval == Result::OK) {
388 *frames = halFrames;
389 *time = halTime;
Mikhail Naganov10548292016-10-31 10:39:47 -0700390 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800391 return retval;
392};
393
394Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
395 uint64_t frames = 0, time = 0;
396 Result retval = getCapturePositionImpl(mStream, &frames, &time);
Mikhail Naganov10548292016-10-31 10:39:47 -0700397 _hidl_cb(retval, frames, time);
398 return Void();
399}
400
401} // namespace implementation
402} // namespace V2_0
403} // namespace audio
404} // namespace hardware
405} // namespace android