AudioSource.cpp revision 47204e1806da9f849464d0cef936851d7e561607
1/* 2 * Copyright (C) 2010 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_NDEBUG 0 18#define LOG_TAG "AudioSource" 19#include <utils/Log.h> 20 21#include <media/stagefright/AudioSource.h> 22 23#include <media/AudioRecord.h> 24#include <media/stagefright/MediaBufferGroup.h> 25#include <media/stagefright/MediaDebug.h> 26#include <media/stagefright/MediaDefs.h> 27#include <media/stagefright/MetaData.h> 28#include <cutils/properties.h> 29#include <stdlib.h> 30 31namespace android { 32 33AudioSource::AudioSource( 34 int inputSource, uint32_t sampleRate, uint32_t channels) 35 : mStarted(false), 36 mCollectStats(false), 37 mPrevSampleTimeUs(0), 38 mTotalLostFrames(0), 39 mPrevLostBytes(0), 40 mGroup(NULL) { 41 42 LOGV("sampleRate: %d, channels: %d", sampleRate, channels); 43 uint32_t flags = AudioRecord::RECORD_AGC_ENABLE | 44 AudioRecord::RECORD_NS_ENABLE | 45 AudioRecord::RECORD_IIR_ENABLE; 46 47 mRecord = new AudioRecord( 48 inputSource, sampleRate, AudioSystem::PCM_16_BIT, 49 channels > 1? AudioSystem::CHANNEL_IN_STEREO: AudioSystem::CHANNEL_IN_MONO, 50 4 * kMaxBufferSize / sizeof(int16_t), /* Enable ping-pong buffers */ 51 flags); 52 53 mInitCheck = mRecord->initCheck(); 54} 55 56AudioSource::~AudioSource() { 57 if (mStarted) { 58 stop(); 59 } 60 61 delete mRecord; 62 mRecord = NULL; 63} 64 65status_t AudioSource::initCheck() const { 66 return mInitCheck; 67} 68 69status_t AudioSource::start(MetaData *params) { 70 if (mStarted) { 71 return UNKNOWN_ERROR; 72 } 73 74 char value[PROPERTY_VALUE_MAX]; 75 if (property_get("media.stagefright.record-stats", value, NULL) 76 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 77 mCollectStats = true; 78 } 79 80 mTrackMaxAmplitude = false; 81 mMaxAmplitude = 0; 82 mStartTimeUs = 0; 83 int64_t startTimeUs; 84 if (params && params->findInt64(kKeyTime, &startTimeUs)) { 85 mStartTimeUs = startTimeUs; 86 } 87 status_t err = mRecord->start(); 88 89 if (err == OK) { 90 mGroup = new MediaBufferGroup; 91 mGroup->add_buffer(new MediaBuffer(kMaxBufferSize)); 92 93 mStarted = true; 94 } 95 96 return err; 97} 98 99status_t AudioSource::stop() { 100 if (!mStarted) { 101 return UNKNOWN_ERROR; 102 } 103 104 mRecord->stop(); 105 106 delete mGroup; 107 mGroup = NULL; 108 109 mStarted = false; 110 111 if (mCollectStats) { 112 LOGI("Total lost audio frames: %lld", 113 mTotalLostFrames + (mPrevLostBytes >> 1)); 114 } 115 116 return OK; 117} 118 119sp<MetaData> AudioSource::getFormat() { 120 sp<MetaData> meta = new MetaData; 121 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); 122 meta->setInt32(kKeySampleRate, mRecord->getSampleRate()); 123 meta->setInt32(kKeyChannelCount, mRecord->channelCount()); 124 meta->setInt32(kKeyMaxInputSize, kMaxBufferSize); 125 126 return meta; 127} 128 129/* 130 * Returns -1 if frame skipping request is too long. 131 * Returns 0 if there is no need to skip frames. 132 * Returns 1 if we need to skip frames. 133 */ 134static int skipFrame(int64_t timestampUs, 135 const MediaSource::ReadOptions *options) { 136 137 int64_t skipFrameUs; 138 if (!options || !options->getSkipFrame(&skipFrameUs)) { 139 return 0; 140 } 141 142 if (skipFrameUs <= timestampUs) { 143 return 0; 144 } 145 146 // Safe guard against the abuse of the kSkipFrame_Option. 147 if (skipFrameUs - timestampUs >= 1E6) { 148 LOGE("Frame skipping requested is way too long: %lld us", 149 skipFrameUs - timestampUs); 150 151 return -1; 152 } 153 154 LOGV("skipFrame: %lld us > timestamp: %lld us", 155 skipFrameUs, timestampUs); 156 157 return 1; 158 159} 160 161status_t AudioSource::read( 162 MediaBuffer **out, const ReadOptions *options) { 163 *out = NULL; 164 165 MediaBuffer *buffer; 166 CHECK_EQ(mGroup->acquire_buffer(&buffer), OK); 167 168 int err = 0; 169 while (mStarted) { 170 171 uint32_t numFramesRecorded; 172 mRecord->getPosition(&numFramesRecorded); 173 174 175 if (numFramesRecorded == 0 && mPrevSampleTimeUs == 0) { 176 // Initial delay 177 if (mStartTimeUs > 0) { 178 mStartTimeUs = systemTime() / 1000 - mStartTimeUs; 179 } else { 180 // Assume latency is constant. 181 mStartTimeUs += mRecord->latency() * 1000; 182 } 183 mPrevSampleTimeUs = mStartTimeUs; 184 } 185 186 uint32_t sampleRate = mRecord->getSampleRate(); 187 188 // Insert null frames when lost frames are detected. 189 int64_t timestampUs = mPrevSampleTimeUs; 190 uint32_t numLostBytes = mRecord->getInputFramesLost() << 1; 191 numLostBytes += mPrevLostBytes; 192#if 0 193 // Simulate lost frames 194 numLostBytes = ((rand() * 1.0 / RAND_MAX)) * 2 * kMaxBufferSize; 195 numLostBytes &= 0xFFFFFFFE; // Alignment requirement 196 197 // Reduce the chance to lose 198 if (rand() * 1.0 / RAND_MAX >= 0.05) { 199 numLostBytes = 0; 200 } 201#endif 202 if (numLostBytes > 0) { 203 if (numLostBytes > kMaxBufferSize) { 204 mPrevLostBytes = numLostBytes - kMaxBufferSize; 205 numLostBytes = kMaxBufferSize; 206 } 207 208 CHECK_EQ(numLostBytes & 1, 0); 209 timestampUs += ((1000000LL * (numLostBytes >> 1)) + 210 (sampleRate >> 1)) / sampleRate; 211 212 CHECK(timestampUs > mPrevSampleTimeUs); 213 if (mCollectStats) { 214 mTotalLostFrames += (numLostBytes >> 1); 215 } 216 if ((err = skipFrame(timestampUs, options)) == -1) { 217 buffer->release(); 218 return UNKNOWN_ERROR; 219 } else if (err != 0) { 220 continue; 221 } 222 memset(buffer->data(), 0, numLostBytes); 223 buffer->set_range(0, numLostBytes); 224 buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); 225 mPrevSampleTimeUs = timestampUs; 226 *out = buffer; 227 return OK; 228 } 229 230 ssize_t n = mRecord->read(buffer->data(), buffer->size()); 231 if (n < 0) { 232 buffer->release(); 233 return (status_t)n; 234 } 235 236 int64_t recordDurationUs = (1000000LL * n >> 1) / sampleRate; 237 timestampUs += recordDurationUs; 238 if ((err = skipFrame(timestampUs, options)) == -1) { 239 buffer->release(); 240 return UNKNOWN_ERROR; 241 } else if (err != 0) { 242 continue; 243 } 244 245 if (mTrackMaxAmplitude) { 246 trackMaxAmplitude((int16_t *) buffer->data(), n >> 1); 247 } 248 249 buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); 250 CHECK(timestampUs > mPrevSampleTimeUs); 251 if (mTotalLostFrames == 0) { 252 CHECK_EQ(mPrevSampleTimeUs, 253 mStartTimeUs + (1000000LL * numFramesRecorded) / sampleRate); 254 } 255 mPrevSampleTimeUs = timestampUs; 256 LOGV("initial delay: %lld, sample rate: %d, timestamp: %lld", 257 mStartTimeUs, sampleRate, timestampUs); 258 259 buffer->set_range(0, n); 260 261 *out = buffer; 262 return OK; 263 } 264 265 return OK; 266} 267 268void AudioSource::trackMaxAmplitude(int16_t *data, int nSamples) { 269 for (int i = nSamples; i > 0; --i) { 270 int16_t value = *data++; 271 if (value < 0) { 272 value = -value; 273 } 274 if (mMaxAmplitude < value) { 275 mMaxAmplitude = value; 276 } 277 } 278} 279 280int16_t AudioSource::getMaxAmplitude() { 281 // First call activates the tracking. 282 if (!mTrackMaxAmplitude) { 283 mTrackMaxAmplitude = true; 284 } 285 int16_t value = mMaxAmplitude; 286 mMaxAmplitude = 0; 287 LOGV("max amplitude since last call: %d", value); 288 return value; 289} 290 291} // namespace android 292