blob: 255496e5af36e3d8353299b476c8a4fa8cd019f8 [file] [log] [blame]
Glenn Kastenf91df1b2014-03-13 14:59:31 -07001/*
2 * Copyright (C) 2014 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 "FastCapture"
18//#define LOG_NDEBUG 0
19
20#define ATRACE_TAG ATRACE_TAG_AUDIO
21
22#include "Configuration.h"
23#include <linux/futex.h>
24#include <sys/syscall.h>
25#include <media/AudioBufferProvider.h>
26#include <utils/Log.h>
27#include <utils/Trace.h>
28#include "FastCapture.h"
29
30namespace android {
31
32/*static*/ const FastCaptureState FastCapture::initial;
33
34FastCapture::FastCapture() : FastThread(),
35 inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0),
36 readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0),
37 // dummyDumpState
38 totalNativeFramesRead(0)
39{
40 previous = &initial;
41 current = &initial;
42
43 mDummyDumpState = &dummyDumpState;
44}
45
46FastCapture::~FastCapture()
47{
48}
49
50FastCaptureStateQueue* FastCapture::sq()
51{
52 return &mSQ;
53}
54
55const FastThreadState *FastCapture::poll()
56{
57 return mSQ.poll();
58}
59
60void FastCapture::setLog(NBLog::Writer *logWriter __unused)
61{
62}
63
64void FastCapture::onIdle()
65{
66 preIdle = *(const FastCaptureState *)current;
67 current = &preIdle;
68}
69
70void FastCapture::onExit()
71{
72 delete[] readBuffer;
73}
74
75bool FastCapture::isSubClassCommand(FastThreadState::Command command)
76{
77 switch ((FastCaptureState::Command) command) {
78 case FastCaptureState::READ:
79 case FastCaptureState::WRITE:
80 case FastCaptureState::READ_WRITE:
81 return true;
82 default:
83 return false;
84 }
85}
86
87void FastCapture::onStateChange()
88{
89 const FastCaptureState * const current = (const FastCaptureState *) this->current;
90 const FastCaptureState * const previous = (const FastCaptureState *) this->previous;
91 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
92 const size_t frameCount = current->mFrameCount;
93
94 bool eitherChanged = false;
95
96 // check for change in input HAL configuration
97 NBAIO_Format previousFormat = format;
98 if (current->mInputSourceGen != inputSourceGen) {
99 inputSource = current->mInputSource;
100 inputSourceGen = current->mInputSourceGen;
101 if (inputSource == NULL) {
102 format = Format_Invalid;
103 sampleRate = 0;
104 } else {
105 format = inputSource->format();
106 sampleRate = Format_sampleRate(format);
107 unsigned channelCount = Format_channelCount(format);
108 ALOG_ASSERT(channelCount == 1 || channelCount == 2);
109 }
110 dumpState->mSampleRate = sampleRate;
111 eitherChanged = true;
112 }
113
114 // check for change in pipe
115 if (current->mPipeSinkGen != pipeSinkGen) {
116 pipeSink = current->mPipeSink;
117 pipeSinkGen = current->mPipeSinkGen;
118 eitherChanged = true;
119 }
120
121 // input source and pipe sink must be compatible
122 if (eitherChanged && inputSource != NULL && pipeSink != NULL) {
123 ALOG_ASSERT(Format_isEqual(format, pipeSink->format()));
124 }
125
126 if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
127 // FIXME to avoid priority inversion, don't delete here
128 delete[] readBuffer;
129 readBuffer = NULL;
130 if (frameCount > 0 && sampleRate > 0) {
131 // FIXME new may block for unbounded time at internal mutex of the heap
132 // implementation; it would be better to have normal capture thread allocate for
133 // us to avoid blocking here and to prevent possible priority inversion
134 unsigned channelCount = Format_channelCount(format);
135 // FIXME frameSize
136 readBuffer = new short[frameCount * channelCount];
137 periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
138 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
139 overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50
140 forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95
Glenn Kastend2123e62015-01-29 10:02:44 -0800141 warmupNsMin = (frameCount * 750000000LL) / sampleRate; // 0.75
142 warmupNsMax = (frameCount * 1250000000LL) / sampleRate; // 1.25
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700143 } else {
144 periodNs = 0;
145 underrunNs = 0;
146 overrunNs = 0;
147 forceNs = 0;
Glenn Kastend2123e62015-01-29 10:02:44 -0800148 warmupNsMin = 0;
149 warmupNsMax = LONG_MAX;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700150 }
151 readBufferState = -1;
152 dumpState->mFrameCount = frameCount;
153 }
154
155}
156
157void FastCapture::onWork()
158{
159 const FastCaptureState * const current = (const FastCaptureState *) this->current;
160 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
161 const FastCaptureState::Command command = this->command;
162 const size_t frameCount = current->mFrameCount;
163
164 if ((command & FastCaptureState::READ) /*&& isWarm*/) {
165 ALOG_ASSERT(inputSource != NULL);
166 ALOG_ASSERT(readBuffer != NULL);
167 dumpState->mReadSequence++;
168 ATRACE_BEGIN("read");
169 ssize_t framesRead = inputSource->read(readBuffer, frameCount,
170 AudioBufferProvider::kInvalidPTS);
171 ATRACE_END();
172 dumpState->mReadSequence++;
173 if (framesRead >= 0) {
174 LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
175 totalNativeFramesRead += framesRead;
176 dumpState->mFramesRead = totalNativeFramesRead;
177 readBufferState = framesRead;
178 } else {
179 dumpState->mReadErrors++;
180 readBufferState = 0;
181 }
182 // FIXME rename to attemptedIO
183 attemptedWrite = true;
184 }
185
186 if (command & FastCaptureState::WRITE) {
187 ALOG_ASSERT(pipeSink != NULL);
188 ALOG_ASSERT(readBuffer != NULL);
189 if (readBufferState < 0) {
190 unsigned channelCount = Format_channelCount(format);
191 // FIXME frameSize
192 memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
193 readBufferState = frameCount;
194 }
195 if (readBufferState > 0) {
196 ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
197 // FIXME This supports at most one fast capture client.
198 // To handle multiple clients this could be converted to an array,
199 // or with a lot more work the control block could be shared by all clients.
200 audio_track_cblk_t* cblk = current->mCblk;
201 if (cblk != NULL && framesWritten > 0) {
202 int32_t rear = cblk->u.mStreaming.mRear;
203 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
204 cblk->mServer += framesWritten;
205 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
206 if (!(old & CBLK_FUTEX_WAKE)) {
207 // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
208 (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
209 }
210 }
211 }
212 }
213}
214
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700215} // namespace android