1 /*
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 
30 namespace android {
31 
32 /*static*/ const FastCaptureState FastCapture::initial;
33 
FastCapture()34 FastCapture::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 
~FastCapture()46 FastCapture::~FastCapture()
47 {
48 }
49 
sq()50 FastCaptureStateQueue* FastCapture::sq()
51 {
52     return &mSQ;
53 }
54 
poll()55 const FastThreadState *FastCapture::poll()
56 {
57     return mSQ.poll();
58 }
59 
setLog(NBLog::Writer * logWriter __unused)60 void FastCapture::setLog(NBLog::Writer *logWriter __unused)
61 {
62 }
63 
onIdle()64 void FastCapture::onIdle()
65 {
66     preIdle = *(const FastCaptureState *)current;
67     current = &preIdle;
68 }
69 
onExit()70 void FastCapture::onExit()
71 {
72     delete[] readBuffer;
73 }
74 
isSubClassCommand(FastThreadState::Command command)75 bool 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 
onStateChange()87 void 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
141             warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
142         } else {
143             periodNs = 0;
144             underrunNs = 0;
145             overrunNs = 0;
146             forceNs = 0;
147             warmupNs = 0;
148         }
149         readBufferState = -1;
150         dumpState->mFrameCount = frameCount;
151     }
152 
153 }
154 
onWork()155 void FastCapture::onWork()
156 {
157     const FastCaptureState * const current = (const FastCaptureState *) this->current;
158     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
159     const FastCaptureState::Command command = this->command;
160     const size_t frameCount = current->mFrameCount;
161 
162     if ((command & FastCaptureState::READ) /*&& isWarm*/) {
163         ALOG_ASSERT(inputSource != NULL);
164         ALOG_ASSERT(readBuffer != NULL);
165         dumpState->mReadSequence++;
166         ATRACE_BEGIN("read");
167         ssize_t framesRead = inputSource->read(readBuffer, frameCount,
168                 AudioBufferProvider::kInvalidPTS);
169         ATRACE_END();
170         dumpState->mReadSequence++;
171         if (framesRead >= 0) {
172             LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
173             totalNativeFramesRead += framesRead;
174             dumpState->mFramesRead = totalNativeFramesRead;
175             readBufferState = framesRead;
176         } else {
177             dumpState->mReadErrors++;
178             readBufferState = 0;
179         }
180         // FIXME rename to attemptedIO
181         attemptedWrite = true;
182     }
183 
184     if (command & FastCaptureState::WRITE) {
185         ALOG_ASSERT(pipeSink != NULL);
186         ALOG_ASSERT(readBuffer != NULL);
187         if (readBufferState < 0) {
188             unsigned channelCount = Format_channelCount(format);
189             // FIXME frameSize
190             memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
191             readBufferState = frameCount;
192         }
193         if (readBufferState > 0) {
194             ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
195             // FIXME This supports at most one fast capture client.
196             //       To handle multiple clients this could be converted to an array,
197             //       or with a lot more work the control block could be shared by all clients.
198             audio_track_cblk_t* cblk = current->mCblk;
199             if (cblk != NULL && framesWritten > 0) {
200                 int32_t rear = cblk->u.mStreaming.mRear;
201                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
202                 cblk->mServer += framesWritten;
203                 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
204                 if (!(old & CBLK_FUTEX_WAKE)) {
205                     // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
206                     (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
207                 }
208             }
209         }
210     }
211 }
212 
FastCaptureDumpState()213 FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
214     mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
215 {
216 }
217 
~FastCaptureDumpState()218 FastCaptureDumpState::~FastCaptureDumpState()
219 {
220 }
221 
222 }   // namespace android
223