• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 "AAudio"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <aaudio/AAudio.h>
22 
23 #include "client/AudioStreamInternalCapture.h"
24 #include "utility/AudioClock.h"
25 
26 using android::WrappingBuffer;
27 
28 using namespace aaudio;
29 
AudioStreamInternalCapture(AAudioServiceInterface & serviceInterface,bool inService)30 AudioStreamInternalCapture::AudioStreamInternalCapture(AAudioServiceInterface  &serviceInterface,
31                                                  bool inService)
32     : AudioStreamInternal(serviceInterface, inService) {
33 
34 }
35 
~AudioStreamInternalCapture()36 AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
37 
38 
39 // Write the data, block if needed and timeoutMillis > 0
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)40 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
41                                                int64_t timeoutNanoseconds)
42 {
43     return processData(buffer, numFrames, timeoutNanoseconds);
44 }
45 
46 // Read as much data as we can without blocking.
processDataNow(void * buffer,int32_t numFrames,int64_t currentNanoTime,int64_t * wakeTimePtr)47 aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t numFrames,
48                                                   int64_t currentNanoTime, int64_t *wakeTimePtr) {
49     aaudio_result_t result = processCommands();
50     if (result != AAUDIO_OK) {
51         return result;
52     }
53 
54     if (mAudioEndpoint.isFreeRunning()) {
55         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
56         // Update data queue based on the timing model.
57         int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime);
58         // TODO refactor, maybe use setRemoteCounter()
59         mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
60     }
61 
62     // If the write index passed the read index then consider it an overrun.
63     if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
64         mXRunCount++;
65     }
66 
67     // Read some data from the buffer.
68     //ALOGD("AudioStreamInternalCapture::processDataNow() - readNowWithConversion(%d)", numFrames);
69     int32_t framesProcessed = readNowWithConversion(buffer, numFrames);
70     //ALOGD("AudioStreamInternalCapture::processDataNow() - tried to read %d frames, read %d",
71     //    numFrames, framesProcessed);
72 
73     // Calculate an ideal time to wake up.
74     if (wakeTimePtr != nullptr && framesProcessed >= 0) {
75         // By default wake up a few milliseconds from now.  // TODO review
76         int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
77         aaudio_stream_state_t state = getState();
78         //ALOGD("AudioStreamInternalCapture::processDataNow() - wakeTime based on %s",
79         //      AAudio_convertStreamStateToText(state));
80         switch (state) {
81             case AAUDIO_STREAM_STATE_OPEN:
82             case AAUDIO_STREAM_STATE_STARTING:
83                 break;
84             case AAUDIO_STREAM_STATE_STARTED:   // When do we expect the next read burst to occur?
85             {
86                 uint32_t burstSize = mFramesPerBurst;
87                 if (burstSize < 32) {
88                     burstSize = 32; // TODO review
89                 }
90 
91                 uint64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + burstSize;
92                 wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
93             }
94                 break;
95             default:
96                 break;
97         }
98         *wakeTimePtr = wakeTime;
99 
100     }
101 //    ALOGD("AudioStreamInternalCapture::readNow finished: now = %llu, read# = %llu, wrote# = %llu",
102 //         (unsigned long long)currentNanoTime,
103 //         (unsigned long long)mAudioEndpoint.getDataReadCounter(),
104 //         (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
105     return framesProcessed;
106 }
107 
readNowWithConversion(void * buffer,int32_t numFrames)108 aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer,
109                                                                 int32_t numFrames) {
110     // ALOGD("AudioStreamInternalCapture::readNowWithConversion(%p, %d)",
111     //              buffer, numFrames);
112     WrappingBuffer wrappingBuffer;
113     uint8_t *destination = (uint8_t *) buffer;
114     int32_t framesLeft = numFrames;
115 
116     mAudioEndpoint.getFullFramesAvailable(&wrappingBuffer);
117 
118     // Read data in one or two parts.
119     for (int partIndex = 0; framesLeft > 0 && partIndex < WrappingBuffer::SIZE; partIndex++) {
120         int32_t framesToProcess = framesLeft;
121         int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
122         if (framesAvailable <= 0) break;
123 
124         if (framesToProcess > framesAvailable) {
125             framesToProcess = framesAvailable;
126         }
127 
128         int32_t numBytes = getBytesPerFrame() * framesToProcess;
129         int32_t numSamples = framesToProcess * getSamplesPerFrame();
130 
131         // TODO factor this out into a utility function
132         if (mDeviceFormat == getFormat()) {
133             memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
134         } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16
135                    && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
136             AAudioConvert_pcm16ToFloat(
137                     (const int16_t *) wrappingBuffer.data[partIndex],
138                     (float *) destination,
139                     numSamples,
140                     1.0f);
141         } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT
142                    && getFormat() == AAUDIO_FORMAT_PCM_I16) {
143             AAudioConvert_floatToPcm16(
144                     (const float *) wrappingBuffer.data[partIndex],
145                     (int16_t *) destination,
146                     numSamples,
147                     1.0f);
148         } else {
149             ALOGE("Format conversion not supported!");
150             return AAUDIO_ERROR_INVALID_FORMAT;
151         }
152         destination += numBytes;
153         framesLeft -= framesToProcess;
154     }
155 
156     int32_t framesProcessed = numFrames - framesLeft;
157     mAudioEndpoint.advanceReadIndex(framesProcessed);
158     incrementFramesRead(framesProcessed);
159 
160     //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed);
161     return framesProcessed;
162 }
163 
getFramesWritten()164 int64_t AudioStreamInternalCapture::getFramesWritten()
165 {
166     int64_t frames =
167             mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
168             + mFramesOffsetFromService;
169     // Prevent retrograde motion.
170     if (frames < mLastFramesWritten) {
171         frames = mLastFramesWritten;
172     } else {
173         mLastFramesWritten = frames;
174     }
175     //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld", (long long)frames);
176     return frames;
177 }
178 
getFramesRead()179 int64_t AudioStreamInternalCapture::getFramesRead()
180 {
181     int64_t frames = mAudioEndpoint.getDataWriteCounter()
182                                + mFramesOffsetFromService;
183     //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
184     return frames;
185 }
186 
187 // Read data from the stream and pass it to the callback for processing.
callbackLoop()188 void *AudioStreamInternalCapture::callbackLoop() {
189     aaudio_result_t result = AAUDIO_OK;
190     aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
191     AAudioStream_dataCallback appCallback = getDataCallbackProc();
192     if (appCallback == nullptr) return NULL;
193 
194     // result might be a frame count
195     while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
196 
197         // Read audio data from stream.
198         int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
199 
200         // This is a BLOCKING READ!
201         result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
202         if ((result != mCallbackFrames)) {
203             ALOGE("AudioStreamInternalCapture(): callbackLoop: read() returned %d", result);
204             if (result >= 0) {
205                 // Only read some of the frames requested. Must have timed out.
206                 result = AAUDIO_ERROR_TIMEOUT;
207             }
208             AAudioStream_errorCallback errorCallback = getErrorCallbackProc();
209             if (errorCallback != nullptr) {
210                 (*errorCallback)(
211                         (AAudioStream *) this,
212                         getErrorCallbackUserData(),
213                         result);
214             }
215             break;
216         }
217 
218         // Call application using the AAudio callback interface.
219         callbackResult = (*appCallback)(
220                 (AAudioStream *) this,
221                 getDataCallbackUserData(),
222                 mCallbackBuffer,
223                 mCallbackFrames);
224 
225         if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
226             ALOGD("AudioStreamInternalCapture(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
227             break;
228         }
229     }
230 
231     ALOGD("AudioStreamInternalCapture(): callbackLoop() exiting, result = %d, isActive() = %d",
232           result, (int) isActive());
233     return NULL;
234 }
235