AudioStreamRecord.cpp revision d873a5506149ed47164cf9c11add82eaceba24c3
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 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 switch(getPerformanceMode()) { 73 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: 74 flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW); 75 break; 76 77 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: 78 case AAUDIO_PERFORMANCE_MODE_NONE: 79 default: 80 // No flags. 81 break; 82 } 83 84 uint32_t notificationFrames = 0; 85 86 // Setup the callback if there is one. 87 AudioRecord::callback_t callback = nullptr; 88 void *callbackData = nullptr; 89 AudioRecord::transfer_type streamTransferType = AudioRecord::transfer_type::TRANSFER_SYNC; 90 if (builder.getDataCallbackProc() != nullptr) { 91 streamTransferType = AudioRecord::transfer_type::TRANSFER_CALLBACK; 92 callback = getLegacyCallback(); 93 callbackData = this; 94 notificationFrames = builder.getFramesPerDataCallback(); 95 } 96 mCallbackBufferSize = builder.getFramesPerDataCallback(); 97 98 mAudioRecord = new AudioRecord( 99 AUDIO_SOURCE_VOICE_RECOGNITION, 100 getSampleRate(), 101 format, 102 channelMask, 103 mOpPackageName, // const String16& opPackageName TODO does not compile 104 frameCount, 105 callback, 106 callbackData, 107 notificationFrames, 108 AUDIO_SESSION_ALLOCATE, 109 streamTransferType, 110 flags 111 // int uid = -1, 112 // pid_t pid = -1, 113 // const audio_attributes_t* pAttributes = nullptr 114 ); 115 116 // Did we get a valid track? 117 status_t status = mAudioRecord->initCheck(); 118 if (status != OK) { 119 close(); 120 ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status); 121 return AAudioConvert_androidToAAudioResult(status); 122 } 123 124 // Get the actual rate. 125 setSampleRate(mAudioRecord->getSampleRate()); 126 setSamplesPerFrame(mAudioRecord->channelCount()); 127 setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format())); 128 129 // We may need to pass the data through a block size adapter to guarantee constant size. 130 if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) { 131 int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize; 132 mFixedBlockWriter.open(callbackSizeBytes); 133 mBlockAdapter = &mFixedBlockWriter; 134 } else { 135 mBlockAdapter = nullptr; 136 } 137 138 setState(AAUDIO_STREAM_STATE_OPEN); 139 140 return AAUDIO_OK; 141} 142 143aaudio_result_t AudioStreamRecord::close() 144{ 145 // TODO add close() or release() to AudioRecord API then call it from here 146 if (getState() != AAUDIO_STREAM_STATE_CLOSED) { 147 mAudioRecord.clear(); 148 setState(AAUDIO_STREAM_STATE_CLOSED); 149 } 150 mFixedBlockWriter.close(); 151 return AAUDIO_OK; 152} 153 154void AudioStreamRecord::processCallback(int event, void *info) { 155 156 ALOGD("AudioStreamRecord::processCallback(), event %d", event); 157 switch (event) { 158 case AudioRecord::EVENT_MORE_DATA: 159 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info); 160 break; 161 162 // Stream got rerouted so we disconnect. 163 case AudioRecord::EVENT_NEW_IAUDIORECORD: 164 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info); 165 break; 166 167 default: 168 break; 169 } 170 return; 171} 172 173aaudio_result_t AudioStreamRecord::requestStart() 174{ 175 if (mAudioRecord.get() == nullptr) { 176 return AAUDIO_ERROR_INVALID_STATE; 177 } 178 // Get current position so we can detect when the track is playing. 179 status_t err = mAudioRecord->getPosition(&mPositionWhenStarting); 180 if (err != OK) { 181 return AAudioConvert_androidToAAudioResult(err); 182 } 183 184 err = mAudioRecord->start(); 185 if (err != OK) { 186 return AAudioConvert_androidToAAudioResult(err); 187 } else { 188 setState(AAUDIO_STREAM_STATE_STARTING); 189 } 190 return AAUDIO_OK; 191} 192 193aaudio_result_t AudioStreamRecord::requestPause() 194{ 195 // This does not make sense for an input stream. 196 // There is no real difference between pause() and stop(). 197 return AAUDIO_ERROR_UNIMPLEMENTED; 198} 199 200aaudio_result_t AudioStreamRecord::requestFlush() { 201 // This does not make sense for an input stream. 202 return AAUDIO_ERROR_UNIMPLEMENTED; 203} 204 205aaudio_result_t AudioStreamRecord::requestStop() { 206 if (mAudioRecord.get() == nullptr) { 207 return AAUDIO_ERROR_INVALID_STATE; 208 } 209 setState(AAUDIO_STREAM_STATE_STOPPING); 210 incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review 211 mAudioRecord->stop(); 212 mFramesRead.reset32(); 213 return AAUDIO_OK; 214} 215 216aaudio_result_t AudioStreamRecord::updateStateWhileWaiting() 217{ 218 aaudio_result_t result = AAUDIO_OK; 219 aaudio_wrapping_frames_t position; 220 status_t err; 221 switch (getState()) { 222 // TODO add better state visibility to AudioRecord 223 case AAUDIO_STREAM_STATE_STARTING: 224 err = mAudioRecord->getPosition(&position); 225 if (err != OK) { 226 result = AAudioConvert_androidToAAudioResult(err); 227 } else if (position != mPositionWhenStarting) { 228 setState(AAUDIO_STREAM_STATE_STARTED); 229 } 230 break; 231 case AAUDIO_STREAM_STATE_STOPPING: 232 if (mAudioRecord->stopped()) { 233 setState(AAUDIO_STREAM_STATE_STOPPED); 234 } 235 break; 236 default: 237 break; 238 } 239 return result; 240} 241 242aaudio_result_t AudioStreamRecord::read(void *buffer, 243 int32_t numFrames, 244 int64_t timeoutNanoseconds) 245{ 246 int32_t bytesPerFrame = getBytesPerFrame(); 247 int32_t numBytes; 248 aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes); 249 if (result != AAUDIO_OK) { 250 return result; 251 } 252 253 // TODO add timeout to AudioRecord 254 bool blocking = (timeoutNanoseconds > 0); 255 ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking); 256 if (bytesRead == WOULD_BLOCK) { 257 return 0; 258 } else if (bytesRead < 0) { 259 return AAudioConvert_androidToAAudioResult(bytesRead); 260 } 261 int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame); 262 incrementFramesRead(framesRead); 263 return (aaudio_result_t) framesRead; 264} 265 266aaudio_result_t AudioStreamRecord::setBufferSize(int32_t requestedFrames) 267{ 268 return getBufferSize(); 269} 270 271int32_t AudioStreamRecord::getBufferSize() const 272{ 273 return getBufferCapacity(); // TODO implement in AudioRecord? 274} 275 276int32_t AudioStreamRecord::getBufferCapacity() const 277{ 278 return static_cast<int32_t>(mAudioRecord->frameCount()); 279} 280 281int32_t AudioStreamRecord::getXRunCount() const 282{ 283 return 0; // TODO implement when AudioRecord supports it 284} 285 286int32_t AudioStreamRecord::getFramesPerBurst() const 287{ 288 return static_cast<int32_t>(mAudioRecord->getNotificationPeriodInFrames()); 289} 290 291aaudio_result_t AudioStreamRecord::getTimestamp(clockid_t clockId, 292 int64_t *framePosition, 293 int64_t *timeNanoseconds) { 294 ExtendedTimestamp extendedTimestamp; 295 status_t status = mAudioRecord->getTimestamp(&extendedTimestamp); 296 if (status != NO_ERROR) { 297 return AAudioConvert_androidToAAudioResult(status); 298 } 299 return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp); 300} 301