AudioStreamRecord.cpp revision fb00fc77f59ed5ebec4d38bac666e6521b6c1de0
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 31using namespace android; 32using namespace aaudio; 33 34AudioStreamRecord::AudioStreamRecord() 35 : AudioStreamLegacy() 36 , mFixedBlockWriter(*this) 37{ 38} 39 40AudioStreamRecord::~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 47aaudio_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_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 177aaudio_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 188void 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 205aaudio_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 226aaudio_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 233aaudio_result_t AudioStreamRecord::requestFlush() { 234 // This does not make sense for an input stream. 235 return AAUDIO_ERROR_UNIMPLEMENTED; 236} 237 238aaudio_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 250aaudio_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 276aaudio_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 310aaudio_result_t AudioStreamRecord::setBufferSize(int32_t requestedFrames) 311{ 312 return getBufferSize(); 313} 314 315int32_t AudioStreamRecord::getBufferSize() const 316{ 317 return getBufferCapacity(); // TODO implement in AudioRecord? 318} 319 320int32_t AudioStreamRecord::getBufferCapacity() const 321{ 322 return static_cast<int32_t>(mAudioRecord->frameCount()); 323} 324 325int32_t AudioStreamRecord::getXRunCount() const 326{ 327 return 0; // TODO implement when AudioRecord supports it 328} 329 330int32_t AudioStreamRecord::getFramesPerBurst() const 331{ 332 return static_cast<int32_t>(mAudioRecord->getNotificationPeriodInFrames()); 333} 334 335aaudio_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