AudioStreamRecord.cpp revision 35e80f34a9649752fceafa53e2094cd8eda50a0a
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 "AudioStreamRecord.h" 28#include "utility/AAudioUtilities.h" 29 30using namespace android; 31using namespace aaudio; 32 33AudioStreamRecord::AudioStreamRecord() 34 : AudioStream() 35{ 36} 37 38AudioStreamRecord::~AudioStreamRecord() 39{ 40 const aaudio_stream_state_t state = getState(); 41 bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED); 42 ALOGE_IF(bad, "stream not closed, in state %d", state); 43} 44 45aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder) 46{ 47 aaudio_result_t result = AAUDIO_OK; 48 49 result = AudioStream::open(builder); 50 if (result != AAUDIO_OK) { 51 return result; 52 } 53 54 // Try to create an AudioRecord 55 56 // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified. 57 int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) 58 ? 2 : getSamplesPerFrame(); 59 audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame); 60 61 AudioRecord::callback_t callback = nullptr; 62 audio_input_flags_t flags = (audio_input_flags_t) AUDIO_INPUT_FLAG_NONE; 63 64 size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0 65 : builder.getBufferCapacity(); 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 mAudioRecord = new AudioRecord( 72 AUDIO_SOURCE_DEFAULT, 73 getSampleRate(), 74 format, 75 channelMask, 76 mOpPackageName, // const String16& opPackageName TODO does not compile 77 frameCount, 78 callback, 79 nullptr, // void* user = nullptr, 80 0, // uint32_t notificationFrames = 0, 81 AUDIO_SESSION_ALLOCATE, 82 AudioRecord::TRANSFER_DEFAULT, 83 flags 84 // int uid = -1, 85 // pid_t pid = -1, 86 // const audio_attributes_t* pAttributes = nullptr 87 ); 88 89 // Did we get a valid track? 90 status_t status = mAudioRecord->initCheck(); 91 if (status != OK) { 92 close(); 93 ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status); 94 return AAudioConvert_androidToAAudioResult(status); 95 } 96 97 // Get the actual rate. 98 setSampleRate(mAudioRecord->getSampleRate()); 99 setSamplesPerFrame(mAudioRecord->channelCount()); 100 setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format())); 101 102 setState(AAUDIO_STREAM_STATE_OPEN); 103 104 return AAUDIO_OK; 105} 106 107aaudio_result_t AudioStreamRecord::close() 108{ 109 // TODO add close() or release() to AudioRecord API then call it from here 110 if (getState() != AAUDIO_STREAM_STATE_CLOSED) { 111 mAudioRecord.clear(); 112 setState(AAUDIO_STREAM_STATE_CLOSED); 113 } 114 return AAUDIO_OK; 115} 116 117aaudio_result_t AudioStreamRecord::requestStart() 118{ 119 if (mAudioRecord.get() == nullptr) { 120 return AAUDIO_ERROR_INVALID_STATE; 121 } 122 // Get current position so we can detect when the track is playing. 123 status_t err = mAudioRecord->getPosition(&mPositionWhenStarting); 124 if (err != OK) { 125 return AAudioConvert_androidToAAudioResult(err); 126 } 127 err = mAudioRecord->start(); 128 if (err != OK) { 129 return AAudioConvert_androidToAAudioResult(err); 130 } else { 131 setState(AAUDIO_STREAM_STATE_STARTING); 132 } 133 return AAUDIO_OK; 134} 135 136aaudio_result_t AudioStreamRecord::requestPause() 137{ 138 return AAUDIO_ERROR_UNIMPLEMENTED; 139} 140 141aaudio_result_t AudioStreamRecord::requestFlush() { 142 return AAUDIO_ERROR_UNIMPLEMENTED; 143} 144 145aaudio_result_t AudioStreamRecord::requestStop() { 146 if (mAudioRecord.get() == nullptr) { 147 return AAUDIO_ERROR_INVALID_STATE; 148 } 149 setState(AAUDIO_STREAM_STATE_STOPPING); 150 mAudioRecord->stop(); 151 return AAUDIO_OK; 152} 153 154aaudio_result_t AudioStreamRecord::updateState() 155{ 156 aaudio_result_t result = AAUDIO_OK; 157 aaudio_wrapping_frames_t position; 158 status_t err; 159 switch (getState()) { 160 // TODO add better state visibility to AudioRecord 161 case AAUDIO_STREAM_STATE_STARTING: 162 err = mAudioRecord->getPosition(&position); 163 if (err != OK) { 164 result = AAudioConvert_androidToAAudioResult(err); 165 } else if (position != mPositionWhenStarting) { 166 setState(AAUDIO_STREAM_STATE_STARTED); 167 } 168 break; 169 case AAUDIO_STREAM_STATE_STOPPING: 170 if (mAudioRecord->stopped()) { 171 setState(AAUDIO_STREAM_STATE_STOPPED); 172 } 173 break; 174 default: 175 break; 176 } 177 return result; 178} 179 180aaudio_result_t AudioStreamRecord::read(void *buffer, 181 int32_t numFrames, 182 int64_t timeoutNanoseconds) 183{ 184 int32_t bytesPerFrame = getBytesPerFrame(); 185 int32_t numBytes; 186 aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes); 187 if (result != AAUDIO_OK) { 188 return result; 189 } 190 191 // TODO add timeout to AudioRecord 192 bool blocking = (timeoutNanoseconds > 0); 193 ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking); 194 if (bytesRead == WOULD_BLOCK) { 195 return 0; 196 } else if (bytesRead < 0) { 197 return AAudioConvert_androidToAAudioResult(bytesRead); 198 } 199 int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame); 200 return (aaudio_result_t) framesRead; 201} 202 203aaudio_result_t AudioStreamRecord::setBufferSize(int32_t requestedFrames) 204{ 205 return getBufferSize(); 206} 207 208int32_t AudioStreamRecord::getBufferSize() const 209{ 210 return getBufferCapacity(); // TODO implement in AudioRecord? 211} 212 213int32_t AudioStreamRecord::getBufferCapacity() const 214{ 215 return static_cast<int32_t>(mAudioRecord->frameCount()); 216} 217 218int32_t AudioStreamRecord::getXRunCount() const 219{ 220 return AAUDIO_ERROR_UNIMPLEMENTED; // TODO implement when AudioRecord supports it 221} 222 223int32_t AudioStreamRecord::getFramesPerBurst() const 224{ 225 return 192; // TODO add query to AudioRecord.cpp 226} 227 228aaudio_result_t AudioStreamRecord::getTimestamp(clockid_t clockId, 229 int64_t *framePosition, 230 int64_t *timeNanoseconds) { 231 ExtendedTimestamp extendedTimestamp; 232 status_t status = mAudioRecord->getTimestamp(&extendedTimestamp); 233 if (status != NO_ERROR) { 234 return AAudioConvert_androidToAAudioResult(status); 235 } 236 // TODO Merge common code into AudioStreamLegacy after rebasing. 237 int timebase; 238 switch(clockId) { 239 case CLOCK_BOOTTIME: 240 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME; 241 break; 242 case CLOCK_MONOTONIC: 243 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC; 244 break; 245 default: 246 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId); 247 return AAUDIO_ERROR_UNEXPECTED_VALUE; 248 break; 249 } 250 status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase); 251 return AAudioConvert_androidToAAudioResult(status); 252} 253