blob: 1cde4ac1b9bb3a39a7182f88d7a24ea1a9f4e90a [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 Naganov10548292016-10-31 10:39:47 -070019
Yifan Hongf9d30342016-11-30 13:45:34 -080020#include <android/log.h>
Mikhail Naganovb29438e2016-12-22 09:21:34 -080021#include <hardware/audio.h>
22#include <mediautils/SchedulingPolicyService.h>
Mikhail Naganov10548292016-10-31 10:39:47 -070023
24#include "StreamIn.h"
25
Mikhail Naganovb29438e2016-12-22 09:21:34 -080026using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
27
Mikhail Naganov10548292016-10-31 10:39:47 -070028namespace android {
29namespace hardware {
30namespace audio {
31namespace V2_0 {
32namespace implementation {
33
Mikhail Naganovb29438e2016-12-22 09:21:34 -080034namespace {
35
36class ReadThread : public Thread {
37 public:
38 // ReadThread's lifespan never exceeds StreamIn's lifespan.
39 ReadThread(std::atomic<bool>* stop,
40 audio_stream_in_t* stream,
Mikhail Naganova468fa82017-01-31 13:56:02 -080041 StreamIn::CommandMQ* commandMQ,
Mikhail Naganovb29438e2016-12-22 09:21:34 -080042 StreamIn::DataMQ* dataMQ,
43 StreamIn::StatusMQ* statusMQ,
44 EventFlag* efGroup,
45 ThreadPriority threadPriority)
46 : Thread(false /*canCallJava*/),
47 mStop(stop),
48 mStream(stream),
Mikhail Naganova468fa82017-01-31 13:56:02 -080049 mCommandMQ(commandMQ),
Mikhail Naganovb29438e2016-12-22 09:21:34 -080050 mDataMQ(dataMQ),
51 mStatusMQ(statusMQ),
52 mEfGroup(efGroup),
53 mThreadPriority(threadPriority),
54 mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
55 }
56 virtual ~ReadThread() {}
57
58 status_t readyToRun() override;
59
60 private:
61 std::atomic<bool>* mStop;
62 audio_stream_in_t* mStream;
Mikhail Naganova468fa82017-01-31 13:56:02 -080063 StreamIn::CommandMQ* mCommandMQ;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080064 StreamIn::DataMQ* mDataMQ;
65 StreamIn::StatusMQ* mStatusMQ;
66 EventFlag* mEfGroup;
67 ThreadPriority mThreadPriority;
68 std::unique_ptr<uint8_t[]> mBuffer;
Mikhail Naganova468fa82017-01-31 13:56:02 -080069 IStreamIn::ReadParameters mParameters;
70 IStreamIn::ReadStatus mStatus;
Mikhail Naganovb29438e2016-12-22 09:21:34 -080071
72 bool threadLoop() override;
Mikhail Naganova468fa82017-01-31 13:56:02 -080073
74 void doGetCapturePosition();
75 void doRead();
Mikhail Naganovb29438e2016-12-22 09:21:34 -080076};
77
78status_t ReadThread::readyToRun() {
79 if (mThreadPriority != ThreadPriority::NORMAL) {
80 int err = requestPriority(
81 getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/);
82 ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
83 static_cast<int>(mThreadPriority), getpid(), getTid(), err);
84 }
85 return OK;
86}
87
Mikhail Naganova468fa82017-01-31 13:56:02 -080088void ReadThread::doRead() {
89 size_t availableToWrite = mDataMQ->availableToWrite();
90 size_t requestedToRead = mParameters.params.read;
91 if (requestedToRead > availableToWrite) {
92 ALOGW("truncating read data from %d to %d due to insufficient data queue space",
93 (int32_t)requestedToRead, (int32_t)availableToWrite);
94 requestedToRead = availableToWrite;
95 }
96 ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
97 mStatus.retval = Result::OK;
98 uint64_t read = 0;
99 if (readResult >= 0) {
100 mStatus.reply.read = readResult;
101 if (!mDataMQ->write(&mBuffer[0], readResult)) {
102 ALOGW("data message queue write failed");
103 }
104 } else {
105 mStatus.retval = Stream::analyzeStatus("read", readResult);
106 }
107}
108
109void ReadThread::doGetCapturePosition() {
110 mStatus.retval = StreamIn::getCapturePositionImpl(
111 mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
112}
113
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800114bool ReadThread::threadLoop() {
115 // This implementation doesn't return control back to the Thread until it decides to stop,
116 // as the Thread uses mutexes, and this can lead to priority inversion.
117 while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
118 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
119 uint32_t efState = 0;
120 mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
121 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
122 continue; // Nothing to do.
123 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800124 if (!mCommandMQ->read(&mParameters)) {
125 continue; // Nothing to do.
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800126 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800127 mStatus.replyTo = mParameters.command;
128 switch (mParameters.command) {
129 case IStreamIn::ReadCommand::READ:
130 doRead();
131 break;
132 case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
133 doGetCapturePosition();
134 break;
135 default:
136 ALOGE("Unknown read thread command code %d", mParameters.command);
137 mStatus.retval = Result::NOT_SUPPORTED;
138 break;
139 }
140 if (!mStatusMQ->write(&mStatus)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800141 ALOGW("status message queue write failed");
142 }
143 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
144 }
145
146 return false;
147}
148
149} // namespace
150
Mikhail Naganov10548292016-10-31 10:39:47 -0700151StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800152 : mIsClosed(false), mDevice(device), mStream(stream),
Eric Laurent7deb7da2016-12-15 19:15:45 -0800153 mStreamCommon(new Stream(&stream->common)),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800154 mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
155 mEfGroup(nullptr), mStopReadThread(false) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700156}
157
158StreamIn::~StreamIn() {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800159 close();
Mikhail Naganov10548292016-10-31 10:39:47 -0700160 mStream = nullptr;
161 mDevice = nullptr;
162}
163
164// Methods from ::android::hardware::audio::V2_0::IStream follow.
165Return<uint64_t> StreamIn::getFrameSize() {
166 return audio_stream_in_frame_size(mStream);
167}
168
169Return<uint64_t> StreamIn::getFrameCount() {
170 return mStreamCommon->getFrameCount();
171}
172
173Return<uint64_t> StreamIn::getBufferSize() {
174 return mStreamCommon->getBufferSize();
175}
176
177Return<uint32_t> StreamIn::getSampleRate() {
178 return mStreamCommon->getSampleRate();
179}
180
181Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
182 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
183}
184
185Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
186 return mStreamCommon->setSampleRate(sampleRateHz);
187}
188
189Return<AudioChannelMask> StreamIn::getChannelMask() {
190 return mStreamCommon->getChannelMask();
191}
192
193Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
194 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
195}
196
197Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
198 return mStreamCommon->setChannelMask(mask);
199}
200
201Return<AudioFormat> StreamIn::getFormat() {
202 return mStreamCommon->getFormat();
203}
204
205Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
206 return mStreamCommon->getSupportedFormats(_hidl_cb);
207}
208
209Return<Result> StreamIn::setFormat(AudioFormat format) {
210 return mStreamCommon->setFormat(format);
211}
212
213Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
214 return mStreamCommon->getAudioProperties(_hidl_cb);
215}
216
217Return<Result> StreamIn::addEffect(uint64_t effectId) {
218 return mStreamCommon->addEffect(effectId);
219}
220
221Return<Result> StreamIn::removeEffect(uint64_t effectId) {
222 return mStreamCommon->removeEffect(effectId);
223}
224
225Return<Result> StreamIn::standby() {
226 return mStreamCommon->standby();
227}
228
229Return<AudioDevice> StreamIn::getDevice() {
230 return mStreamCommon->getDevice();
231}
232
233Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
234 return mStreamCommon->setDevice(address);
235}
236
237Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
238 return mStreamCommon->setConnectedState(address, connected);
239}
240
241Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
242 return mStreamCommon->setHwAvSync(hwAvSync);
243}
244
245Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
246 return mStreamCommon->getParameters(keys, _hidl_cb);
247}
248
249Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
250 return mStreamCommon->setParameters(parameters);
251}
252
Martijn Coenen70b9a152016-11-18 15:29:32 +0100253Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700254 return mStreamCommon->debugDump(fd);
255}
256
Eric Laurent7deb7da2016-12-15 19:15:45 -0800257Return<Result> StreamIn::start() {
258 return mStreamMmap->start();
259}
260
261Return<Result> StreamIn::stop() {
262 return mStreamMmap->stop();
263}
264
265Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
266 return mStreamMmap->createMmapBuffer(
267 minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
268}
269
270Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
271 return mStreamMmap->getMmapPosition(_hidl_cb);
272}
Mikhail Naganov10548292016-10-31 10:39:47 -0700273
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800274Return<Result> StreamIn::close() {
275 if (mIsClosed) return Result::INVALID_STATE;
276 mIsClosed = true;
277 if (mReadThread.get()) {
278 mStopReadThread.store(true, std::memory_order_release);
279 status_t status = mReadThread->requestExitAndWait();
280 ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
281 }
282 if (mEfGroup) {
283 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
284 ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
285 }
286 mDevice->close_input_stream(mDevice, mStream);
287 return Result::OK;
288}
289
Mikhail Naganov10548292016-10-31 10:39:47 -0700290// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
291Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
292 int halSource;
293 Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
294 AudioSource source(AudioSource::DEFAULT);
295 if (retval == Result::OK) {
296 source = AudioSource(halSource);
297 }
298 _hidl_cb(retval, source);
299 return Void();
300}
301
302Return<Result> StreamIn::setGain(float gain) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800303 return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
Mikhail Naganov10548292016-10-31 10:39:47 -0700304}
305
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800306Return<void> StreamIn::prepareForReading(
307 uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
308 prepareForReading_cb _hidl_cb) {
309 status_t status;
310 // Create message queues.
311 if (mDataMQ) {
312 ALOGE("the client attempts to call prepareForReading twice");
313 _hidl_cb(Result::INVALID_STATE,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800314 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800315 return Void();
Mikhail Naganov10548292016-10-31 10:39:47 -0700316 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800317 std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800318 std::unique_ptr<DataMQ> tempDataMQ(
319 new DataMQ(frameSize * framesCount, true /* EventFlag */));
320 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
Mikhail Naganova468fa82017-01-31 13:56:02 -0800321 if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
322 ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800323 ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
324 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
325 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800326 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800327 return Void();
328 }
329 // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
330 status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
331 if (status != OK || !mEfGroup) {
332 ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
333 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800334 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800335 return Void();
336 }
337
338 // Create and launch the thread.
339 mReadThread = new ReadThread(
340 &mStopReadThread,
341 mStream,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800342 tempCommandMQ.get(),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800343 tempDataMQ.get(),
344 tempStatusMQ.get(),
345 mEfGroup,
346 threadPriority);
347 status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
348 if (status != OK) {
349 ALOGW("failed to start reader thread: %s", strerror(-status));
350 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800351 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor());
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800352 return Void();
353 }
354
Mikhail Naganova468fa82017-01-31 13:56:02 -0800355 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800356 mDataMQ = std::move(tempDataMQ);
357 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800358 _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc());
Mikhail Naganov10548292016-10-31 10:39:47 -0700359 return Void();
360}
361
362Return<uint32_t> StreamIn::getInputFramesLost() {
363 return mStream->get_input_frames_lost(mStream);
364}
365
Mikhail Naganova468fa82017-01-31 13:56:02 -0800366// static
367Result StreamIn::getCapturePositionImpl(
368 audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700369 Result retval(Result::NOT_SUPPORTED);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800370 if (stream->get_capture_position != NULL) return retval;
371 int64_t halFrames, halTime;
372 retval = Stream::analyzeStatus(
373 "get_capture_position",
374 stream->get_capture_position(stream, &halFrames, &halTime),
375 // HAL may have a stub function, always returning ENOSYS, don't
376 // spam the log in this case.
377 ENOSYS);
378 if (retval == Result::OK) {
379 *frames = halFrames;
380 *time = halTime;
Mikhail Naganov10548292016-10-31 10:39:47 -0700381 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800382 return retval;
383};
384
385Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
386 uint64_t frames = 0, time = 0;
387 Result retval = getCapturePositionImpl(mStream, &frames, &time);
Mikhail Naganov10548292016-10-31 10:39:47 -0700388 _hidl_cb(retval, frames, time);
389 return Void();
390}
391
392} // namespace implementation
393} // namespace V2_0
394} // namespace audio
395} // namespace hardware
396} // namespace android