• 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 "AudioStreamRecord"
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 AudioRecord. 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 values from the AudioRecord.
134     setSamplesPerFrame(mAudioRecord->channelCount());
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 
163     setSharingMode(AAUDIO_SHARING_MODE_SHARED); // EXCLUSIVE mode not supported in legacy
164 
165     // Log warning if we did not get what we asked for.
166     ALOGW_IF(actualFlags != flags,
167              "AudioStreamRecord::open() flags changed from 0x%08X to 0x%08X",
168              flags, actualFlags);
169     ALOGW_IF(actualPerformanceMode != perfMode,
170              "AudioStreamRecord::open() perfMode changed from %d to %d",
171              perfMode, actualPerformanceMode);
172 
173     setState(AAUDIO_STREAM_STATE_OPEN);
174     setDeviceId(mAudioRecord->getRoutedDeviceId());
175     mAudioRecord->addAudioDeviceCallback(mDeviceCallback);
176 
177     return AAUDIO_OK;
178 }
179 
close()180 aaudio_result_t AudioStreamRecord::close()
181 {
182     // TODO add close() or release() to AudioRecord API then call it from here
183     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
184         mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
185         mAudioRecord.clear();
186         setState(AAUDIO_STREAM_STATE_CLOSED);
187     }
188     mFixedBlockWriter.close();
189     return AudioStream::close();
190 }
191 
processCallback(int event,void * info)192 void AudioStreamRecord::processCallback(int event, void *info) {
193     switch (event) {
194         case AudioRecord::EVENT_MORE_DATA:
195             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info);
196             break;
197 
198             // Stream got rerouted so we disconnect.
199         case AudioRecord::EVENT_NEW_IAUDIORECORD:
200             processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info);
201             break;
202 
203         default:
204             break;
205     }
206     return;
207 }
208 
requestStart()209 aaudio_result_t AudioStreamRecord::requestStart()
210 {
211     if (mAudioRecord.get() == nullptr) {
212         return AAUDIO_ERROR_INVALID_STATE;
213     }
214     // Get current position so we can detect when the track is recording.
215     status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
216     if (err != OK) {
217         return AAudioConvert_androidToAAudioResult(err);
218     }
219 
220     err = mAudioRecord->start();
221     if (err != OK) {
222         return AAudioConvert_androidToAAudioResult(err);
223     } else {
224         onStart();
225         setState(AAUDIO_STREAM_STATE_STARTING);
226     }
227     return AAUDIO_OK;
228 }
229 
requestStop()230 aaudio_result_t AudioStreamRecord::requestStop() {
231     if (mAudioRecord.get() == nullptr) {
232         return AAUDIO_ERROR_INVALID_STATE;
233     }
234     onStop();
235     setState(AAUDIO_STREAM_STATE_STOPPING);
236     incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
237     mTimestampPosition.set(getFramesRead());
238     mAudioRecord->stop();
239     mFramesRead.reset32();
240     mTimestampPosition.reset32();
241     checkForDisconnectRequest();
242     return AAUDIO_OK;
243 }
244 
updateStateMachine()245 aaudio_result_t AudioStreamRecord::updateStateMachine()
246 {
247     aaudio_result_t result = AAUDIO_OK;
248     aaudio_wrapping_frames_t position;
249     status_t err;
250     switch (getState()) {
251     // TODO add better state visibility to AudioRecord
252     case AAUDIO_STREAM_STATE_STARTING:
253         err = mAudioRecord->getPosition(&position);
254         if (err != OK) {
255             result = AAudioConvert_androidToAAudioResult(err);
256         } else if (position != mPositionWhenStarting) {
257             setState(AAUDIO_STREAM_STATE_STARTED);
258         }
259         break;
260     case AAUDIO_STREAM_STATE_STOPPING:
261         if (mAudioRecord->stopped()) {
262             setState(AAUDIO_STREAM_STATE_STOPPED);
263         }
264         break;
265     default:
266         break;
267     }
268     return result;
269 }
270 
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)271 aaudio_result_t AudioStreamRecord::read(void *buffer,
272                                       int32_t numFrames,
273                                       int64_t timeoutNanoseconds)
274 {
275     int32_t bytesPerFrame = getBytesPerFrame();
276     int32_t numBytes;
277     aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
278     if (result != AAUDIO_OK) {
279         return result;
280     }
281 
282     if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
283         return AAUDIO_ERROR_DISCONNECTED;
284     }
285 
286     // TODO add timeout to AudioRecord
287     bool blocking = (timeoutNanoseconds > 0);
288     ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking);
289     if (bytesRead == WOULD_BLOCK) {
290         return 0;
291     } else if (bytesRead < 0) {
292         // in this context, a DEAD_OBJECT is more likely to be a disconnect notification due to
293         // AudioRecord invalidation
294         if (bytesRead == DEAD_OBJECT) {
295             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
296             return AAUDIO_ERROR_DISCONNECTED;
297         }
298         return AAudioConvert_androidToAAudioResult(bytesRead);
299     }
300     int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame);
301     incrementFramesRead(framesRead);
302 
303     result = updateStateMachine();
304     if (result != AAUDIO_OK) {
305         return result;
306     }
307 
308     return (aaudio_result_t) framesRead;
309 }
310 
setBufferSize(int32_t requestedFrames)311 aaudio_result_t AudioStreamRecord::setBufferSize(int32_t requestedFrames)
312 {
313     return getBufferSize();
314 }
315 
getBufferSize() const316 int32_t AudioStreamRecord::getBufferSize() const
317 {
318     return getBufferCapacity(); // TODO implement in AudioRecord?
319 }
320 
getBufferCapacity() const321 int32_t AudioStreamRecord::getBufferCapacity() const
322 {
323     return static_cast<int32_t>(mAudioRecord->frameCount());
324 }
325 
getXRunCount() const326 int32_t AudioStreamRecord::getXRunCount() const
327 {
328     return 0; // TODO implement when AudioRecord supports it
329 }
330 
getFramesPerBurst() const331 int32_t AudioStreamRecord::getFramesPerBurst() const
332 {
333     return static_cast<int32_t>(mAudioRecord->getNotificationPeriodInFrames());
334 }
335 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)336 aaudio_result_t AudioStreamRecord::getTimestamp(clockid_t clockId,
337                                                int64_t *framePosition,
338                                                int64_t *timeNanoseconds) {
339     ExtendedTimestamp extendedTimestamp;
340     status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
341     if (status == WOULD_BLOCK) {
342         return AAUDIO_ERROR_INVALID_STATE;
343     } else if (status != NO_ERROR) {
344         return AAudioConvert_androidToAAudioResult(status);
345     }
346     return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
347 }
348 
getFramesWritten()349 int64_t AudioStreamRecord::getFramesWritten() {
350     aaudio_wrapping_frames_t position;
351     status_t result;
352     switch (getState()) {
353         case AAUDIO_STREAM_STATE_STARTING:
354         case AAUDIO_STREAM_STATE_STARTED:
355         case AAUDIO_STREAM_STATE_STOPPING:
356             result = mAudioRecord->getPosition(&position);
357             if (result == OK) {
358                 mFramesWritten.update32(position);
359             }
360             break;
361         default:
362             break;
363     }
364     return AudioStreamLegacy::getFramesWritten();
365 }
366