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