• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 "AAudio"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <stdint.h>
22 #include <utils/String16.h>
23 #include <media/AudioRecord.h>
24 #include <aaudio/AAudio.h>
25 
26 #include "AudioClock.h"
27 #include "legacy/AudioStreamLegacy.h"
28 #include "legacy/AudioStreamRecord.h"
29 #include "utility/FixedBlockWriter.h"
30 
31 using namespace android;
32 using namespace aaudio;
33 
AudioStreamRecord()34 AudioStreamRecord::AudioStreamRecord()
35     : AudioStreamLegacy()
36     , mFixedBlockWriter(*this)
37 {
38 }
39 
~AudioStreamRecord()40 AudioStreamRecord::~AudioStreamRecord()
41 {
42     const aaudio_stream_state_t state = getState();
43     bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED);
44     ALOGE_IF(bad, "stream not closed, in state %d", state);
45 }
46 
open(const AudioStreamBuilder & builder)47 aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder)
48 {
49     aaudio_result_t result = AAUDIO_OK;
50 
51     result = AudioStream::open(builder);
52     if (result != AAUDIO_OK) {
53         return result;
54     }
55 
56     // Try to create an AudioRecord
57 
58     // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
59     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
60                               ? 2 : getSamplesPerFrame();
61     audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
62 
63     size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
64                         : builder.getBufferCapacity();
65 
66     // TODO implement an unspecified Android format then use that.
67     audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED)
68             ? AUDIO_FORMAT_PCM_FLOAT
69             : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
70 
71     audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
72     aaudio_performance_mode_t perfMode = getPerformanceMode();
73     switch (perfMode) {
74         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
75             flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
76             break;
77 
78         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
79         case AAUDIO_PERFORMANCE_MODE_NONE:
80         default:
81             // No flags.
82             break;
83     }
84 
85     uint32_t notificationFrames = 0;
86 
87     // Setup the callback if there is one.
88     AudioRecord::callback_t callback = nullptr;
89     void *callbackData = nullptr;
90     AudioRecord::transfer_type streamTransferType = AudioRecord::transfer_type::TRANSFER_SYNC;
91     if (builder.getDataCallbackProc() != nullptr) {
92         streamTransferType = AudioRecord::transfer_type::TRANSFER_CALLBACK;
93         callback = getLegacyCallback();
94         callbackData = this;
95         notificationFrames = builder.getFramesPerDataCallback();
96     }
97     mCallbackBufferSize = builder.getFramesPerDataCallback();
98 
99     ALOGD("AudioStreamRecord::open(), request notificationFrames = %u, frameCount = %u",
100           notificationFrames, (uint)frameCount);
101     mAudioRecord = new AudioRecord(
102             mOpPackageName // const String16& opPackageName TODO does not compile
103             );
104     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
105         mAudioRecord->setInputDevice(getDeviceId());
106     }
107     mAudioRecord->set(
108             AUDIO_SOURCE_VOICE_RECOGNITION,
109             getSampleRate(),
110             format,
111             channelMask,
112             frameCount,
113             callback,
114             callbackData,
115             notificationFrames,
116             false /*threadCanCallJava*/,
117             AUDIO_SESSION_ALLOCATE,
118             streamTransferType,
119             flags
120             //   int uid = -1,
121             //   pid_t pid = -1,
122             //   const audio_attributes_t* pAttributes = nullptr
123             );
124 
125     // Did we get a valid track?
126     status_t status = mAudioRecord->initCheck();
127     if (status != OK) {
128         close();
129         ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
130         return AAudioConvert_androidToAAudioResult(status);
131     }
132 
133     // Get the actual rate.
134     setSampleRate(mAudioRecord->getSampleRate());
135     setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format()));
136 
137     int32_t actualSampleRate = mAudioRecord->getSampleRate();
138     ALOGW_IF(actualSampleRate != getSampleRate(),
139              "AudioStreamRecord::open() sampleRate changed from %d to %d",
140              getSampleRate(), actualSampleRate);
141     setSampleRate(actualSampleRate);
142 
143     // We may need to pass the data through a block size adapter to guarantee constant size.
144     if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
145         int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize;
146         mFixedBlockWriter.open(callbackSizeBytes);
147         mBlockAdapter = &mFixedBlockWriter;
148     } else {
149         mBlockAdapter = nullptr;
150     }
151 
152     // Update performance mode based on the actual stream.
153     // For example, if the sample rate does not match native then you won't get a FAST track.
154     audio_input_flags_t actualFlags = mAudioRecord->getFlags();
155     aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
156     // FIXME Some platforms do not advertise RAW mode for low latency inputs.
157     if ((actualFlags & (AUDIO_INPUT_FLAG_FAST))
158         == (AUDIO_INPUT_FLAG_FAST)) {
159         actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
160     }
161     setPerformanceMode(actualPerformanceMode);
162     // Log warning if we did not get what we asked for.
163     ALOGW_IF(actualFlags != flags,
164              "AudioStreamRecord::open() flags changed from 0x%08X to 0x%08X",
165              flags, actualFlags);
166     ALOGW_IF(actualPerformanceMode != perfMode,
167              "AudioStreamRecord::open() perfMode changed from %d to %d",
168              perfMode, actualPerformanceMode);
169 
170     setState(AAUDIO_STREAM_STATE_OPEN);
171     setDeviceId(mAudioRecord->getRoutedDeviceId());
172     mAudioRecord->addAudioDeviceCallback(mDeviceCallback);
173 
174     return AAUDIO_OK;
175 }
176 
close()177 aaudio_result_t AudioStreamRecord::close()
178 {
179     // TODO add close() or release() to AudioRecord API then call it from here
180     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
181         mAudioRecord.clear();
182         setState(AAUDIO_STREAM_STATE_CLOSED);
183     }
184     mFixedBlockWriter.close();
185     return AAUDIO_OK;
186 }
187 
processCallback(int event,void * info)188 void AudioStreamRecord::processCallback(int event, void *info) {
189     switch (event) {
190         case AudioRecord::EVENT_MORE_DATA:
191             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info);
192             break;
193 
194             // Stream got rerouted so we disconnect.
195         case AudioRecord::EVENT_NEW_IAUDIORECORD:
196             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info);
197             break;
198 
199         default:
200             break;
201     }
202     return;
203 }
204 
requestStart()205 aaudio_result_t AudioStreamRecord::requestStart()
206 {
207     if (mAudioRecord.get() == nullptr) {
208         return AAUDIO_ERROR_INVALID_STATE;
209     }
210     // Get current position so we can detect when the track is playing.
211     status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
212     if (err != OK) {
213         return AAudioConvert_androidToAAudioResult(err);
214     }
215 
216     err = mAudioRecord->start();
217     if (err != OK) {
218         return AAudioConvert_androidToAAudioResult(err);
219     } else {
220         onStart();
221         setState(AAUDIO_STREAM_STATE_STARTING);
222     }
223     return AAUDIO_OK;
224 }
225 
requestPause()226 aaudio_result_t AudioStreamRecord::requestPause()
227 {
228     // This does not make sense for an input stream.
229     // There is no real difference between pause() and stop().
230     return AAUDIO_ERROR_UNIMPLEMENTED;
231 }
232 
requestFlush()233 aaudio_result_t AudioStreamRecord::requestFlush() {
234     // This does not make sense for an input stream.
235     return AAUDIO_ERROR_UNIMPLEMENTED;
236 }
237 
requestStop()238 aaudio_result_t AudioStreamRecord::requestStop() {
239     if (mAudioRecord.get() == nullptr) {
240         return AAUDIO_ERROR_INVALID_STATE;
241     }
242     onStop();
243     setState(AAUDIO_STREAM_STATE_STOPPING);
244     incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
245     mAudioRecord->stop();
246     mFramesRead.reset32();
247     return AAUDIO_OK;
248 }
249 
updateStateWhileWaiting()250 aaudio_result_t AudioStreamRecord::updateStateWhileWaiting()
251 {
252     aaudio_result_t result = AAUDIO_OK;
253     aaudio_wrapping_frames_t position;
254     status_t err;
255     switch (getState()) {
256     // TODO add better state visibility to AudioRecord
257     case AAUDIO_STREAM_STATE_STARTING:
258         err = mAudioRecord->getPosition(&position);
259         if (err != OK) {
260             result = AAudioConvert_androidToAAudioResult(err);
261         } else if (position != mPositionWhenStarting) {
262             setState(AAUDIO_STREAM_STATE_STARTED);
263         }
264         break;
265     case AAUDIO_STREAM_STATE_STOPPING:
266         if (mAudioRecord->stopped()) {
267             setState(AAUDIO_STREAM_STATE_STOPPED);
268         }
269         break;
270     default:
271         break;
272     }
273     return result;
274 }
275 
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)276 aaudio_result_t AudioStreamRecord::read(void *buffer,
277                                       int32_t numFrames,
278                                       int64_t timeoutNanoseconds)
279 {
280     int32_t bytesPerFrame = getBytesPerFrame();
281     int32_t numBytes;
282     aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
283     if (result != AAUDIO_OK) {
284         return result;
285     }
286 
287     if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
288         return AAUDIO_ERROR_DISCONNECTED;
289     }
290 
291     // TODO add timeout to AudioRecord
292     bool blocking = (timeoutNanoseconds > 0);
293     ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking);
294     if (bytesRead == WOULD_BLOCK) {
295         return 0;
296     } else if (bytesRead < 0) {
297         // in this context, a DEAD_OBJECT is more likely to be a disconnect notification due to
298         // AudioRecord invalidation
299         if (bytesRead == DEAD_OBJECT) {
300             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
301             return AAUDIO_ERROR_DISCONNECTED;
302         }
303         return AAudioConvert_androidToAAudioResult(bytesRead);
304     }
305     int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame);
306     incrementFramesRead(framesRead);
307     return (aaudio_result_t) framesRead;
308 }
309 
setBufferSize(int32_t requestedFrames)310 aaudio_result_t AudioStreamRecord::setBufferSize(int32_t requestedFrames)
311 {
312     return getBufferSize();
313 }
314 
getBufferSize() const315 int32_t AudioStreamRecord::getBufferSize() const
316 {
317     return getBufferCapacity(); // TODO implement in AudioRecord?
318 }
319 
getBufferCapacity() const320 int32_t AudioStreamRecord::getBufferCapacity() const
321 {
322     return static_cast<int32_t>(mAudioRecord->frameCount());
323 }
324 
getXRunCount() const325 int32_t AudioStreamRecord::getXRunCount() const
326 {
327     return 0; // TODO implement when AudioRecord supports it
328 }
329 
getFramesPerBurst() const330 int32_t AudioStreamRecord::getFramesPerBurst() const
331 {
332     return static_cast<int32_t>(mAudioRecord->getNotificationPeriodInFrames());
333 }
334 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)335 aaudio_result_t AudioStreamRecord::getTimestamp(clockid_t clockId,
336                                                int64_t *framePosition,
337                                                int64_t *timeNanoseconds) {
338     ExtendedTimestamp extendedTimestamp;
339     status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
340     if (status != NO_ERROR) {
341         return AAudioConvert_androidToAAudioResult(status);
342     }
343     return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
344 }
345