]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android/platform-hardware-interfaces.git/blob - audio/2.0/default/StreamIn.cpp
Use -Werror in hardware/interfaces/audio
[android/platform-hardware-interfaces.git] / audio / 2.0 / default / StreamIn.cpp
1 /*
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  */
17 #define LOG_TAG "StreamInHAL"
18 //#define LOG_NDEBUG 0
19 #define ATRACE_TAG ATRACE_TAG_AUDIO
21 #include <android/log.h>
22 #include <hardware/audio.h>
23 #include <utils/Trace.h>
24 #include <memory>
26 #include "StreamIn.h"
27 #include "Util.h"
29 using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
31 namespace android {
32 namespace hardware {
33 namespace audio {
34 namespace V2_0 {
35 namespace implementation {
37 using ::android::hardware::audio::common::V2_0::ThreadInfo;
39 namespace {
41 class ReadThread : public Thread {
42    public:
43     // ReadThread's lifespan never exceeds StreamIn's lifespan.
44     ReadThread(std::atomic<bool>* stop, audio_stream_in_t* stream,
45                StreamIn::CommandMQ* commandMQ, StreamIn::DataMQ* dataMQ,
46                StreamIn::StatusMQ* statusMQ, EventFlag* efGroup)
47         : Thread(false /*canCallJava*/),
48           mStop(stop),
49           mStream(stream),
50           mCommandMQ(commandMQ),
51           mDataMQ(dataMQ),
52           mStatusMQ(statusMQ),
53           mEfGroup(efGroup),
54           mBuffer(nullptr) {}
55     bool init() {
56         mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
57         return mBuffer != nullptr;
58     }
59     virtual ~ReadThread() {}
61    private:
62     std::atomic<bool>* mStop;
63     audio_stream_in_t* mStream;
64     StreamIn::CommandMQ* mCommandMQ;
65     StreamIn::DataMQ* mDataMQ;
66     StreamIn::StatusMQ* mStatusMQ;
67     EventFlag* mEfGroup;
68     std::unique_ptr<uint8_t[]> mBuffer;
69     IStreamIn::ReadParameters mParameters;
70     IStreamIn::ReadStatus mStatus;
72     bool threadLoop() override;
74     void doGetCapturePosition();
75     void doRead();
76 };
78 void ReadThread::doRead() {
79     size_t availableToWrite = mDataMQ->availableToWrite();
80     size_t requestedToRead = mParameters.params.read;
81     if (requestedToRead > availableToWrite) {
82         ALOGW(
83             "truncating read data from %d to %d due to insufficient data queue "
84             "space",
85             (int32_t)requestedToRead, (int32_t)availableToWrite);
86         requestedToRead = availableToWrite;
87     }
88     ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
89     mStatus.retval = Result::OK;
90     if (readResult >= 0) {
91         mStatus.reply.read = readResult;
92         if (!mDataMQ->write(&mBuffer[0], readResult)) {
93             ALOGW("data message queue write failed");
94         }
95     } else {
96         mStatus.retval = Stream::analyzeStatus("read", readResult);
97     }
98 }
100 void ReadThread::doGetCapturePosition() {
101     mStatus.retval = StreamIn::getCapturePositionImpl(
102         mStream, &mStatus.reply.capturePosition.frames,
103         &mStatus.reply.capturePosition.time);
106 bool ReadThread::threadLoop() {
107     // This implementation doesn't return control back to the Thread until it
108     // 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)) {
111         uint32_t efState = 0;
112         mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL),
113                        &efState);
114         if (!(efState &
115               static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
116             continue;  // Nothing to do.
117         }
118         if (!mCommandMQ->read(&mParameters)) {
119             continue;  // Nothing to do.
120         }
121         mStatus.replyTo = mParameters.command;
122         switch (mParameters.command) {
123             case IStreamIn::ReadCommand::READ:
124                 doRead();
125                 break;
126             case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
127                 doGetCapturePosition();
128                 break;
129             default:
130                 ALOGE("Unknown read thread command code %d",
131                       mParameters.command);
132                 mStatus.retval = Result::NOT_SUPPORTED;
133                 break;
134         }
135         if (!mStatusMQ->write(&mStatus)) {
136             ALOGW("status message queue write failed");
137         }
138         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
139     }
141     return false;
144 }  // namespace
146 StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
147     : mIsClosed(false),
148       mDevice(device),
149       mStream(stream),
150       mStreamCommon(new Stream(&stream->common)),
151       mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
152       mEfGroup(nullptr),
153       mStopReadThread(false) {}
155 StreamIn::~StreamIn() {
156     ATRACE_CALL();
157     close();
158     if (mReadThread.get()) {
159         ATRACE_NAME("mReadThread->join");
160         status_t status = mReadThread->join();
161         ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
162     }
163     if (mEfGroup) {
164         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
165         ALOGE_IF(status, "read MQ event flag deletion error: %s",
166                  strerror(-status));
167     }
168     mDevice->closeInputStream(mStream);
169     mStream = nullptr;
172 // Methods from ::android::hardware::audio::V2_0::IStream follow.
173 Return<uint64_t> StreamIn::getFrameSize() {
174     return audio_stream_in_frame_size(mStream);
177 Return<uint64_t> StreamIn::getFrameCount() {
178     return mStreamCommon->getFrameCount();
181 Return<uint64_t> StreamIn::getBufferSize() {
182     return mStreamCommon->getBufferSize();
185 Return<uint32_t> StreamIn::getSampleRate() {
186     return mStreamCommon->getSampleRate();
189 Return<void> StreamIn::getSupportedSampleRates(
190     getSupportedSampleRates_cb _hidl_cb) {
191     return mStreamCommon->getSupportedSampleRates(_hidl_cb);
194 Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
195     return mStreamCommon->setSampleRate(sampleRateHz);
198 Return<AudioChannelMask> StreamIn::getChannelMask() {
199     return mStreamCommon->getChannelMask();
202 Return<void> StreamIn::getSupportedChannelMasks(
203     getSupportedChannelMasks_cb _hidl_cb) {
204     return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
207 Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
208     return mStreamCommon->setChannelMask(mask);
211 Return<AudioFormat> StreamIn::getFormat() {
212     return mStreamCommon->getFormat();
215 Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
216     return mStreamCommon->getSupportedFormats(_hidl_cb);
219 Return<Result> StreamIn::setFormat(AudioFormat format) {
220     return mStreamCommon->setFormat(format);
223 Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
224     return mStreamCommon->getAudioProperties(_hidl_cb);
227 Return<Result> StreamIn::addEffect(uint64_t effectId) {
228     return mStreamCommon->addEffect(effectId);
231 Return<Result> StreamIn::removeEffect(uint64_t effectId) {
232     return mStreamCommon->removeEffect(effectId);
235 Return<Result> StreamIn::standby() {
236     return mStreamCommon->standby();
239 Return<AudioDevice> StreamIn::getDevice() {
240     return mStreamCommon->getDevice();
243 Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
244     return mStreamCommon->setDevice(address);
247 Return<Result> StreamIn::setConnectedState(const DeviceAddress& address,
248                                            bool connected) {
249     return mStreamCommon->setConnectedState(address, connected);
252 Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
253     return mStreamCommon->setHwAvSync(hwAvSync);
256 Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys,
257                                      getParameters_cb _hidl_cb) {
258     return mStreamCommon->getParameters(keys, _hidl_cb);
261 Return<Result> StreamIn::setParameters(
262     const hidl_vec<ParameterValue>& parameters) {
263     return mStreamCommon->setParameters(parameters);
266 Return<void> StreamIn::debugDump(const hidl_handle& fd) {
267     return mStreamCommon->debugDump(fd);
270 Return<Result> StreamIn::start() {
271     return mStreamMmap->start();
274 Return<Result> StreamIn::stop() {
275     return mStreamMmap->stop();
278 Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames,
279                                         createMmapBuffer_cb _hidl_cb) {
280     return mStreamMmap->createMmapBuffer(
281         minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
284 Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
285     return mStreamMmap->getMmapPosition(_hidl_cb);
288 Return<Result> StreamIn::close() {
289     if (mIsClosed) return Result::INVALID_STATE;
290     mIsClosed = true;
291     if (mReadThread.get()) {
292         mStopReadThread.store(true, std::memory_order_release);
293     }
294     if (mEfGroup) {
295         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
296     }
297     return Result::OK;
300 // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
301 Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
302     int halSource;
303     Result retval =
304         mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
305     AudioSource source(AudioSource::DEFAULT);
306     if (retval == Result::OK) {
307         source = AudioSource(halSource);
308     }
309     _hidl_cb(retval, source);
310     return Void();
313 Return<Result> StreamIn::setGain(float gain) {
314     if (!isGainNormalized(gain)) {
315         ALOGW("Can not set a stream input gain (%f) outside [0,1]", gain);
316         return Result::INVALID_ARGUMENTS;
317     }
318     return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
321 Return<void> StreamIn::prepareForReading(uint32_t frameSize,
322                                          uint32_t framesCount,
323                                          prepareForReading_cb _hidl_cb) {
324     status_t status;
325     ThreadInfo threadInfo = {0, 0};
327     // Wrap the _hidl_cb to return an error
328     auto sendError = [&threadInfo, &_hidl_cb](Result result) {
329         _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
330                  StatusMQ::Descriptor(), threadInfo);
332     };
334     // Create message queues.
335     if (mDataMQ) {
336         ALOGE("the client attempts to call prepareForReading twice");
337         sendError(Result::INVALID_STATE);
338         return Void();
339     }
340     std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
342     // Check frameSize and framesCount
343     if (frameSize == 0 || framesCount == 0) {
344         ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize,
345               framesCount);
346         sendError(Result::INVALID_ARGUMENTS);
347         return Void();
348     }
349     // A message queue asserts if it can not handle the requested buffer,
350     // thus the client has to guess the maximum size it can handle
351     // Choose an arbitrary margin for the overhead of a message queue
352     size_t metadataOverhead = 100000;
353     if (frameSize >
354         (std::numeric_limits<size_t>::max() - metadataOverhead) / framesCount) {
355         ALOGE("Buffer too big: %u*%u bytes can not fit in a message queue",
356               frameSize, framesCount);
357         sendError(Result::INVALID_ARGUMENTS);
358         return Void();
359     }
360     std::unique_ptr<DataMQ> tempDataMQ(
361         new DataMQ(frameSize * framesCount, true /* EventFlag */));
363     std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
364     if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() ||
365         !tempStatusMQ->isValid()) {
366         ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
367         ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
368         ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
369         sendError(Result::INVALID_ARGUMENTS);
370         return Void();
371     }
372     EventFlag* tempRawEfGroup{};
373     status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(),
374                                         &tempRawEfGroup);
375     std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
376         tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
377     if (status != OK || !tempElfGroup) {
378         ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
379         sendError(Result::INVALID_ARGUMENTS);
380         return Void();
381     }
383     // Create and launch the thread.
384     auto tempReadThread = std::make_unique<ReadThread>(
385         &mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
386         tempStatusMQ.get(), tempElfGroup.get());
387     if (!tempReadThread->init()) {
388         ALOGW("failed to start reader thread: %s", strerror(-status));
389         sendError(Result::INVALID_ARGUMENTS);
390         return Void();
391     }
392     status = tempReadThread->run("reader", PRIORITY_URGENT_AUDIO);
393     if (status != OK) {
394         ALOGW("failed to start reader thread: %s", strerror(-status));
395         sendError(Result::INVALID_ARGUMENTS);
396         return Void();
397     }
399     mCommandMQ = std::move(tempCommandMQ);
400     mDataMQ = std::move(tempDataMQ);
401     mStatusMQ = std::move(tempStatusMQ);
402     mReadThread = tempReadThread.release();
403     mEfGroup = tempElfGroup.release();
404     threadInfo.pid = getpid();
405     threadInfo.tid = mReadThread->getTid();
406     _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
407              *mStatusMQ->getDesc(), threadInfo);
408     return Void();
411 Return<uint32_t> StreamIn::getInputFramesLost() {
412     return mStream->get_input_frames_lost(mStream);
415 // static
416 Result StreamIn::getCapturePositionImpl(audio_stream_in_t* stream,
417                                         uint64_t* frames, uint64_t* time) {
418     // HAL may have a stub function, always returning ENOSYS, don't
419     // spam the log in this case.
420     static const std::vector<int> ignoredErrors{ENOSYS};
421     Result retval(Result::NOT_SUPPORTED);
422     if (stream->get_capture_position != NULL) return retval;
423     int64_t halFrames, halTime;
424     retval = Stream::analyzeStatus("get_capture_position",
425                                    stream->get_capture_position(stream, &halFrames, &halTime),
426                                    ignoredErrors);
427     if (retval == Result::OK) {
428         *frames = halFrames;
429         *time = halTime;
430     }
431     return retval;
432 };
434 Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
435     uint64_t frames = 0, time = 0;
436     Result retval = getCapturePositionImpl(mStream, &frames, &time);
437     _hidl_cb(retval, frames, time);
438     return Void();
441 }  // namespace implementation
442 }  // namespace V2_0
443 }  // namespace audio
444 }  // namespace hardware
445 }  // namespace android