blob: a8229d39cc855ddcf542c01f37c9b4099a4961ff [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)) {
106 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
107 uint32_t efState = 0;
Mikhail Naganove8674562017-02-10 08:37:19 -0800108 mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800109 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
110 continue; // Nothing to do.
111 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800112 if (!mCommandMQ->read(&mParameters)) {
113 continue; // Nothing to do.
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800114 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800115 mStatus.replyTo = mParameters.command;
116 switch (mParameters.command) {
117 case IStreamIn::ReadCommand::READ:
118 doRead();
119 break;
120 case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
121 doGetCapturePosition();
122 break;
123 default:
124 ALOGE("Unknown read thread command code %d", mParameters.command);
125 mStatus.retval = Result::NOT_SUPPORTED;
126 break;
127 }
128 if (!mStatusMQ->write(&mStatus)) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800129 ALOGW("status message queue write failed");
130 }
131 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
132 }
133
134 return false;
135}
136
137} // namespace
138
Mikhail Naganov10548292016-10-31 10:39:47 -0700139StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800140 : mIsClosed(false), mDevice(device), mStream(stream),
Eric Laurent7deb7da2016-12-15 19:15:45 -0800141 mStreamCommon(new Stream(&stream->common)),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800142 mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
143 mEfGroup(nullptr), mStopReadThread(false) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700144}
145
146StreamIn::~StreamIn() {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800147 ATRACE_CALL();
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800148 close();
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800149 if (mReadThread.get()) {
150 ATRACE_NAME("mReadThread->join");
151 status_t status = mReadThread->join();
152 ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
153 }
154 if (mEfGroup) {
155 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
156 ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
157 }
158 mDevice->close_input_stream(mDevice, mStream);
Mikhail Naganov10548292016-10-31 10:39:47 -0700159 mStream = nullptr;
160 mDevice = nullptr;
161}
162
163// Methods from ::android::hardware::audio::V2_0::IStream follow.
164Return<uint64_t> StreamIn::getFrameSize() {
165 return audio_stream_in_frame_size(mStream);
166}
167
168Return<uint64_t> StreamIn::getFrameCount() {
169 return mStreamCommon->getFrameCount();
170}
171
172Return<uint64_t> StreamIn::getBufferSize() {
173 return mStreamCommon->getBufferSize();
174}
175
176Return<uint32_t> StreamIn::getSampleRate() {
177 return mStreamCommon->getSampleRate();
178}
179
180Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
181 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
182}
183
184Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
185 return mStreamCommon->setSampleRate(sampleRateHz);
186}
187
188Return<AudioChannelMask> StreamIn::getChannelMask() {
189 return mStreamCommon->getChannelMask();
190}
191
192Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
193 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
194}
195
196Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
197 return mStreamCommon->setChannelMask(mask);
198}
199
200Return<AudioFormat> StreamIn::getFormat() {
201 return mStreamCommon->getFormat();
202}
203
204Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
205 return mStreamCommon->getSupportedFormats(_hidl_cb);
206}
207
208Return<Result> StreamIn::setFormat(AudioFormat format) {
209 return mStreamCommon->setFormat(format);
210}
211
212Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
213 return mStreamCommon->getAudioProperties(_hidl_cb);
214}
215
216Return<Result> StreamIn::addEffect(uint64_t effectId) {
217 return mStreamCommon->addEffect(effectId);
218}
219
220Return<Result> StreamIn::removeEffect(uint64_t effectId) {
221 return mStreamCommon->removeEffect(effectId);
222}
223
224Return<Result> StreamIn::standby() {
225 return mStreamCommon->standby();
226}
227
228Return<AudioDevice> StreamIn::getDevice() {
229 return mStreamCommon->getDevice();
230}
231
232Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
233 return mStreamCommon->setDevice(address);
234}
235
236Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
237 return mStreamCommon->setConnectedState(address, connected);
238}
239
240Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
241 return mStreamCommon->setHwAvSync(hwAvSync);
242}
243
244Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
245 return mStreamCommon->getParameters(keys, _hidl_cb);
246}
247
248Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
249 return mStreamCommon->setParameters(parameters);
250}
251
Martijn Coenen70b9a152016-11-18 15:29:32 +0100252Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700253 return mStreamCommon->debugDump(fd);
254}
255
Eric Laurent7deb7da2016-12-15 19:15:45 -0800256Return<Result> StreamIn::start() {
257 return mStreamMmap->start();
258}
259
260Return<Result> StreamIn::stop() {
261 return mStreamMmap->stop();
262}
263
264Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
265 return mStreamMmap->createMmapBuffer(
266 minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
267}
268
269Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
270 return mStreamMmap->getMmapPosition(_hidl_cb);
271}
Mikhail Naganov10548292016-10-31 10:39:47 -0700272
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800273Return<Result> StreamIn::close() {
274 if (mIsClosed) return Result::INVALID_STATE;
275 mIsClosed = true;
276 if (mReadThread.get()) {
277 mStopReadThread.store(true, std::memory_order_release);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800278 }
279 if (mEfGroup) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800280 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800281 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800282 return Result::OK;
283}
284
Mikhail Naganov10548292016-10-31 10:39:47 -0700285// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
286Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
287 int halSource;
288 Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
289 AudioSource source(AudioSource::DEFAULT);
290 if (retval == Result::OK) {
291 source = AudioSource(halSource);
292 }
293 _hidl_cb(retval, source);
294 return Void();
295}
296
297Return<Result> StreamIn::setGain(float gain) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800298 return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
Mikhail Naganov10548292016-10-31 10:39:47 -0700299}
300
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800301Return<void> StreamIn::prepareForReading(
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800302 uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800303 status_t status;
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800304 ThreadInfo threadInfo = { 0, 0 };
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800305 // Create message queues.
306 if (mDataMQ) {
307 ALOGE("the client attempts to call prepareForReading twice");
308 _hidl_cb(Result::INVALID_STATE,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800309 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800310 return Void();
Mikhail Naganov10548292016-10-31 10:39:47 -0700311 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800312 std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800313 std::unique_ptr<DataMQ> tempDataMQ(
314 new DataMQ(frameSize * framesCount, true /* EventFlag */));
315 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
Mikhail Naganova468fa82017-01-31 13:56:02 -0800316 if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
317 ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800318 ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
319 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
320 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800321 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800322 return Void();
323 }
324 // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
325 status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
326 if (status != OK || !mEfGroup) {
327 ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
328 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800329 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800330 return Void();
331 }
332
333 // Create and launch the thread.
334 mReadThread = new ReadThread(
335 &mStopReadThread,
336 mStream,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800337 tempCommandMQ.get(),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800338 tempDataMQ.get(),
339 tempStatusMQ.get(),
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800340 mEfGroup);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800341 status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
342 if (status != OK) {
343 ALOGW("failed to start reader thread: %s", strerror(-status));
344 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800345 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800346 return Void();
347 }
348
Mikhail Naganova468fa82017-01-31 13:56:02 -0800349 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800350 mDataMQ = std::move(tempDataMQ);
351 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800352 threadInfo.pid = getpid();
353 threadInfo.tid = mReadThread->getTid();
354 _hidl_cb(Result::OK,
355 *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
356 threadInfo);
Mikhail Naganov10548292016-10-31 10:39:47 -0700357 return Void();
358}
359
360Return<uint32_t> StreamIn::getInputFramesLost() {
361 return mStream->get_input_frames_lost(mStream);
362}
363
Mikhail Naganova468fa82017-01-31 13:56:02 -0800364// static
365Result StreamIn::getCapturePositionImpl(
366 audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700367 Result retval(Result::NOT_SUPPORTED);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800368 if (stream->get_capture_position != NULL) return retval;
369 int64_t halFrames, halTime;
370 retval = Stream::analyzeStatus(
371 "get_capture_position",
372 stream->get_capture_position(stream, &halFrames, &halTime),
373 // HAL may have a stub function, always returning ENOSYS, don't
374 // spam the log in this case.
375 ENOSYS);
376 if (retval == Result::OK) {
377 *frames = halFrames;
378 *time = halTime;
Mikhail Naganov10548292016-10-31 10:39:47 -0700379 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800380 return retval;
381};
382
383Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
384 uint64_t frames = 0, time = 0;
385 Result retval = getCapturePositionImpl(mStream, &frames, &time);
Mikhail Naganov10548292016-10-31 10:39:47 -0700386 _hidl_cb(retval, frames, time);
387 return Void();
388}
389
390} // namespace implementation
391} // namespace V2_0
392} // namespace audio
393} // namespace hardware
394} // namespace android