blob: 2745607e8b3b9465124545bd5f04220b66a6f4f8 [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 Naganov936279e2017-03-29 09:31:18 -0700138StreamIn::StreamIn(const sp<Device>& 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 }
Mikhail Naganov936279e2017-03-29 09:31:18 -0700157 mDevice->closeInputStream(mStream);
Mikhail Naganov10548292016-10-31 10:39:47 -0700158 mStream = nullptr;
Mikhail Naganov10548292016-10-31 10:39:47 -0700159}
160
161// Methods from ::android::hardware::audio::V2_0::IStream follow.
162Return<uint64_t> StreamIn::getFrameSize() {
163 return audio_stream_in_frame_size(mStream);
164}
165
166Return<uint64_t> StreamIn::getFrameCount() {
167 return mStreamCommon->getFrameCount();
168}
169
170Return<uint64_t> StreamIn::getBufferSize() {
171 return mStreamCommon->getBufferSize();
172}
173
174Return<uint32_t> StreamIn::getSampleRate() {
175 return mStreamCommon->getSampleRate();
176}
177
178Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
179 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
180}
181
182Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
183 return mStreamCommon->setSampleRate(sampleRateHz);
184}
185
186Return<AudioChannelMask> StreamIn::getChannelMask() {
187 return mStreamCommon->getChannelMask();
188}
189
190Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
191 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
192}
193
194Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
195 return mStreamCommon->setChannelMask(mask);
196}
197
198Return<AudioFormat> StreamIn::getFormat() {
199 return mStreamCommon->getFormat();
200}
201
202Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
203 return mStreamCommon->getSupportedFormats(_hidl_cb);
204}
205
206Return<Result> StreamIn::setFormat(AudioFormat format) {
207 return mStreamCommon->setFormat(format);
208}
209
210Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
211 return mStreamCommon->getAudioProperties(_hidl_cb);
212}
213
214Return<Result> StreamIn::addEffect(uint64_t effectId) {
215 return mStreamCommon->addEffect(effectId);
216}
217
218Return<Result> StreamIn::removeEffect(uint64_t effectId) {
219 return mStreamCommon->removeEffect(effectId);
220}
221
222Return<Result> StreamIn::standby() {
223 return mStreamCommon->standby();
224}
225
226Return<AudioDevice> StreamIn::getDevice() {
227 return mStreamCommon->getDevice();
228}
229
230Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
231 return mStreamCommon->setDevice(address);
232}
233
234Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
235 return mStreamCommon->setConnectedState(address, connected);
236}
237
238Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
239 return mStreamCommon->setHwAvSync(hwAvSync);
240}
241
242Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
243 return mStreamCommon->getParameters(keys, _hidl_cb);
244}
245
246Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
247 return mStreamCommon->setParameters(parameters);
248}
249
Martijn Coenen70b9a152016-11-18 15:29:32 +0100250Return<void> StreamIn::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700251 return mStreamCommon->debugDump(fd);
252}
253
Eric Laurent7deb7da2016-12-15 19:15:45 -0800254Return<Result> StreamIn::start() {
255 return mStreamMmap->start();
256}
257
258Return<Result> StreamIn::stop() {
259 return mStreamMmap->stop();
260}
261
262Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
263 return mStreamMmap->createMmapBuffer(
264 minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
265}
266
267Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
268 return mStreamMmap->getMmapPosition(_hidl_cb);
269}
Mikhail Naganov10548292016-10-31 10:39:47 -0700270
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800271Return<Result> StreamIn::close() {
272 if (mIsClosed) return Result::INVALID_STATE;
273 mIsClosed = true;
274 if (mReadThread.get()) {
275 mStopReadThread.store(true, std::memory_order_release);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800276 }
277 if (mEfGroup) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800278 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800279 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800280 return Result::OK;
281}
282
Mikhail Naganov10548292016-10-31 10:39:47 -0700283// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
284Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
285 int halSource;
286 Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
287 AudioSource source(AudioSource::DEFAULT);
288 if (retval == Result::OK) {
289 source = AudioSource(halSource);
290 }
291 _hidl_cb(retval, source);
292 return Void();
293}
294
295Return<Result> StreamIn::setGain(float gain) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800296 return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
Mikhail Naganov10548292016-10-31 10:39:47 -0700297}
298
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800299Return<void> StreamIn::prepareForReading(
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800300 uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) {
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800301 status_t status;
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800302 ThreadInfo threadInfo = { 0, 0 };
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800303 // Create message queues.
304 if (mDataMQ) {
305 ALOGE("the client attempts to call prepareForReading twice");
306 _hidl_cb(Result::INVALID_STATE,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800307 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800308 return Void();
Mikhail Naganov10548292016-10-31 10:39:47 -0700309 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800310 std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800311 std::unique_ptr<DataMQ> tempDataMQ(
312 new DataMQ(frameSize * framesCount, true /* EventFlag */));
313 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
Mikhail Naganova468fa82017-01-31 13:56:02 -0800314 if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
315 ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800316 ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
317 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
318 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800319 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800320 return Void();
321 }
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800322 status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
323 if (status != OK || !mEfGroup) {
324 ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
325 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800326 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800327 return Void();
328 }
329
330 // Create and launch the thread.
331 mReadThread = new ReadThread(
332 &mStopReadThread,
333 mStream,
Mikhail Naganova468fa82017-01-31 13:56:02 -0800334 tempCommandMQ.get(),
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800335 tempDataMQ.get(),
336 tempStatusMQ.get(),
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800337 mEfGroup);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800338 status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
339 if (status != OK) {
340 ALOGW("failed to start reader thread: %s", strerror(-status));
341 _hidl_cb(Result::INVALID_ARGUMENTS,
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800342 CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800343 return Void();
344 }
345
Mikhail Naganova468fa82017-01-31 13:56:02 -0800346 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganovb29438e2016-12-22 09:21:34 -0800347 mDataMQ = std::move(tempDataMQ);
348 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganova1db22a2017-02-07 10:49:18 -0800349 threadInfo.pid = getpid();
350 threadInfo.tid = mReadThread->getTid();
351 _hidl_cb(Result::OK,
352 *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
353 threadInfo);
Mikhail Naganov10548292016-10-31 10:39:47 -0700354 return Void();
355}
356
357Return<uint32_t> StreamIn::getInputFramesLost() {
358 return mStream->get_input_frames_lost(mStream);
359}
360
Mikhail Naganova468fa82017-01-31 13:56:02 -0800361// static
362Result StreamIn::getCapturePositionImpl(
363 audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700364 Result retval(Result::NOT_SUPPORTED);
Mikhail Naganova468fa82017-01-31 13:56:02 -0800365 if (stream->get_capture_position != NULL) return retval;
366 int64_t halFrames, halTime;
367 retval = Stream::analyzeStatus(
368 "get_capture_position",
369 stream->get_capture_position(stream, &halFrames, &halTime),
370 // HAL may have a stub function, always returning ENOSYS, don't
371 // spam the log in this case.
372 ENOSYS);
373 if (retval == Result::OK) {
374 *frames = halFrames;
375 *time = halTime;
Mikhail Naganov10548292016-10-31 10:39:47 -0700376 }
Mikhail Naganova468fa82017-01-31 13:56:02 -0800377 return retval;
378};
379
380Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
381 uint64_t frames = 0, time = 0;
382 Result retval = getCapturePositionImpl(mStream, &frames, &time);
Mikhail Naganov10548292016-10-31 10:39:47 -0700383 _hidl_cb(retval, frames, time);
384 return Void();
385}
386
387} // namespace implementation
388} // namespace V2_0
389} // namespace audio
390} // namespace hardware
391} // namespace android