AudioStreamTrack.cpp revision 30a707773a043e5eebd552d369c0882f886b67e5
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 "AudioStreamTrack" 18//#define LOG_NDEBUG 0 19#include <utils/Log.h> 20 21#include <stdint.h> 22#include <media/AudioTrack.h> 23 24#include <aaudio/AAudio.h> 25#include "utility/AudioClock.h" 26#include "legacy/AudioStreamLegacy.h" 27#include "legacy/AudioStreamTrack.h" 28#include "utility/FixedBlockReader.h" 29 30using namespace android; 31using namespace aaudio; 32 33// Arbitrary and somewhat generous number of bursts. 34#define DEFAULT_BURSTS_PER_BUFFER_CAPACITY 8 35 36/* 37 * Create a stream that uses the AudioTrack. 38 */ 39AudioStreamTrack::AudioStreamTrack() 40 : AudioStreamLegacy() 41 , mFixedBlockReader(*this) 42{ 43} 44 45AudioStreamTrack::~AudioStreamTrack() 46{ 47 const aaudio_stream_state_t state = getState(); 48 bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED); 49 ALOGE_IF(bad, "stream not closed, in state %d", state); 50} 51 52aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder) 53{ 54 aaudio_result_t result = AAUDIO_OK; 55 56 result = AudioStream::open(builder); 57 if (result != OK) { 58 return result; 59 } 60 61 ALOGD("AudioStreamTrack::open = %p", this); 62 63 // Try to create an AudioTrack 64 // Use stereo if unspecified. 65 int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) 66 ? 2 : getSamplesPerFrame(); 67 audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame); 68 ALOGD("AudioStreamTrack::open(), samplesPerFrame = %d, channelMask = 0x%08x", 69 samplesPerFrame, channelMask); 70 71 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE; 72 aaudio_performance_mode_t perfMode = getPerformanceMode(); 73 switch(perfMode) { 74 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: 75 // Bypass the normal mixer and go straight to the FAST mixer. 76 flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW); 77 break; 78 79 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: 80 // This uses a mixer that wakes up less often than the FAST mixer. 81 flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 82 break; 83 84 case AAUDIO_PERFORMANCE_MODE_NONE: 85 default: 86 // No flags. Use a normal mixer in front of the FAST mixer. 87 break; 88 } 89 90 int32_t frameCount = builder.getBufferCapacity(); 91 ALOGD("AudioStreamTrack::open(), requested buffer capacity %d", frameCount); 92 93 int32_t notificationFrames = 0; 94 95 audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) 96 ? AUDIO_FORMAT_PCM_FLOAT 97 : AAudioConvert_aaudioToAndroidDataFormat(getFormat()); 98 99 // Setup the callback if there is one. 100 AudioTrack::callback_t callback = nullptr; 101 void *callbackData = nullptr; 102 // Note that TRANSFER_SYNC does not allow FAST track 103 AudioTrack::transfer_type streamTransferType = AudioTrack::transfer_type::TRANSFER_SYNC; 104 if (builder.getDataCallbackProc() != nullptr) { 105 streamTransferType = AudioTrack::transfer_type::TRANSFER_CALLBACK; 106 callback = getLegacyCallback(); 107 callbackData = this; 108 109 // If the total buffer size is unspecified then base the size on the burst size. 110 if (frameCount == 0 111 && ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0)) { 112 // Take advantage of a special trick that allows us to create a buffer 113 // that is some multiple of the burst size. 114 notificationFrames = 0 - DEFAULT_BURSTS_PER_BUFFER_CAPACITY; 115 } else { 116 notificationFrames = builder.getFramesPerDataCallback(); 117 } 118 } 119 mCallbackBufferSize = builder.getFramesPerDataCallback(); 120 121 ALOGD("AudioStreamTrack::open(), notificationFrames = %d", notificationFrames); 122 mAudioTrack = new AudioTrack( 123 (audio_stream_type_t) AUDIO_STREAM_MUSIC, 124 getSampleRate(), 125 format, 126 channelMask, 127 frameCount, 128 flags, 129 callback, 130 callbackData, 131 notificationFrames, 132 AUDIO_SESSION_ALLOCATE, 133 streamTransferType 134 ); 135 136 // Did we get a valid track? 137 status_t status = mAudioTrack->initCheck(); 138 ALOGD("AudioStreamTrack::open(), initCheck() returned %d", status); 139 if (status != NO_ERROR) { 140 close(); 141 ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status); 142 return AAudioConvert_androidToAAudioResult(status); 143 } 144 145 // Get the actual values from the AudioTrack. 146 setSamplesPerFrame(mAudioTrack->channelCount()); 147 setSampleRate(mAudioTrack->getSampleRate()); 148 aaudio_audio_format_t aaudioFormat = 149 AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format()); 150 setFormat(aaudioFormat); 151 152 // We may need to pass the data through a block size adapter to guarantee constant size. 153 if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) { 154 int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize; 155 mFixedBlockReader.open(callbackSizeBytes); 156 mBlockAdapter = &mFixedBlockReader; 157 } else { 158 mBlockAdapter = nullptr; 159 } 160 161 setState(AAUDIO_STREAM_STATE_OPEN); 162 setDeviceId(mAudioTrack->getRoutedDeviceId()); 163 164 // Update performance mode based on the actual stream. 165 // For example, if the sample rate is not allowed then you won't get a FAST track. 166 audio_output_flags_t actualFlags = mAudioTrack->getFlags(); 167 aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; 168 if ((actualFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)) 169 == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)) { 170 actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; 171 172 } else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) { 173 actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; 174 } 175 setPerformanceMode(actualPerformanceMode); 176 // Log warning if we did not get what we asked for. 177 ALOGW_IF(actualFlags != flags, 178 "AudioStreamTrack::open() flags changed from 0x%08X to 0x%08X", 179 flags, actualFlags); 180 ALOGW_IF(actualPerformanceMode != perfMode, 181 "AudioStreamTrack::open() perfMode changed from %d to %d", 182 perfMode, actualPerformanceMode); 183 184 return AAUDIO_OK; 185} 186 187aaudio_result_t AudioStreamTrack::close() 188{ 189 if (getState() != AAUDIO_STREAM_STATE_CLOSED) { 190 mAudioTrack.clear(); 191 setState(AAUDIO_STREAM_STATE_CLOSED); 192 } 193 mFixedBlockReader.close(); 194 return AAUDIO_OK; 195} 196 197void AudioStreamTrack::processCallback(int event, void *info) { 198 199 switch (event) { 200 case AudioTrack::EVENT_MORE_DATA: 201 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info); 202 break; 203 204 // Stream got rerouted so we disconnect. 205 case AudioTrack::EVENT_NEW_IAUDIOTRACK: 206 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info); 207 break; 208 209 default: 210 break; 211 } 212 return; 213} 214 215aaudio_result_t AudioStreamTrack::requestStart() 216{ 217 std::lock_guard<std::mutex> lock(mStreamMutex); 218 219 if (mAudioTrack.get() == nullptr) { 220 return AAUDIO_ERROR_INVALID_STATE; 221 } 222 // Get current position so we can detect when the track is playing. 223 status_t err = mAudioTrack->getPosition(&mPositionWhenStarting); 224 if (err != OK) { 225 return AAudioConvert_androidToAAudioResult(err); 226 } 227 228 err = mAudioTrack->start(); 229 if (err != OK) { 230 return AAudioConvert_androidToAAudioResult(err); 231 } else { 232 setState(AAUDIO_STREAM_STATE_STARTING); 233 } 234 return AAUDIO_OK; 235} 236 237aaudio_result_t AudioStreamTrack::requestPause() 238{ 239 std::lock_guard<std::mutex> lock(mStreamMutex); 240 241 if (mAudioTrack.get() == nullptr) { 242 return AAUDIO_ERROR_INVALID_STATE; 243 } else if (getState() != AAUDIO_STREAM_STATE_STARTING 244 && getState() != AAUDIO_STREAM_STATE_STARTED) { 245 ALOGE("requestPause(), called when state is %s", 246 AAudio_convertStreamStateToText(getState())); 247 return AAUDIO_ERROR_INVALID_STATE; 248 } 249 setState(AAUDIO_STREAM_STATE_PAUSING); 250 mAudioTrack->pause(); 251 status_t err = mAudioTrack->getPosition(&mPositionWhenPausing); 252 if (err != OK) { 253 return AAudioConvert_androidToAAudioResult(err); 254 } 255 return AAUDIO_OK; 256} 257 258aaudio_result_t AudioStreamTrack::requestFlush() { 259 std::lock_guard<std::mutex> lock(mStreamMutex); 260 261 if (mAudioTrack.get() == nullptr) { 262 return AAUDIO_ERROR_INVALID_STATE; 263 } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) { 264 return AAUDIO_ERROR_INVALID_STATE; 265 } 266 setState(AAUDIO_STREAM_STATE_FLUSHING); 267 incrementFramesRead(getFramesWritten() - getFramesRead()); 268 mAudioTrack->flush(); 269 mFramesWritten.reset32(); 270 return AAUDIO_OK; 271} 272 273aaudio_result_t AudioStreamTrack::requestStop() { 274 std::lock_guard<std::mutex> lock(mStreamMutex); 275 276 if (mAudioTrack.get() == nullptr) { 277 return AAUDIO_ERROR_INVALID_STATE; 278 } 279 setState(AAUDIO_STREAM_STATE_STOPPING); 280 incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review 281 mAudioTrack->stop(); 282 mFramesWritten.reset32(); 283 return AAUDIO_OK; 284} 285 286aaudio_result_t AudioStreamTrack::updateStateWhileWaiting() 287{ 288 status_t err; 289 aaudio_wrapping_frames_t position; 290 switch (getState()) { 291 // TODO add better state visibility to AudioTrack 292 case AAUDIO_STREAM_STATE_STARTING: 293 if (mAudioTrack->hasStarted()) { 294 setState(AAUDIO_STREAM_STATE_STARTED); 295 } 296 break; 297 case AAUDIO_STREAM_STATE_PAUSING: 298 if (mAudioTrack->stopped()) { 299 err = mAudioTrack->getPosition(&position); 300 if (err != OK) { 301 return AAudioConvert_androidToAAudioResult(err); 302 } else if (position == mPositionWhenPausing) { 303 // Has stream really stopped advancing? 304 setState(AAUDIO_STREAM_STATE_PAUSED); 305 } 306 mPositionWhenPausing = position; 307 } 308 break; 309 case AAUDIO_STREAM_STATE_FLUSHING: 310 { 311 err = mAudioTrack->getPosition(&position); 312 if (err != OK) { 313 return AAudioConvert_androidToAAudioResult(err); 314 } else if (position == 0) { 315 // TODO Advance frames read to match written. 316 setState(AAUDIO_STREAM_STATE_FLUSHED); 317 } 318 } 319 break; 320 case AAUDIO_STREAM_STATE_STOPPING: 321 if (mAudioTrack->stopped()) { 322 setState(AAUDIO_STREAM_STATE_STOPPED); 323 } 324 break; 325 default: 326 break; 327 } 328 return AAUDIO_OK; 329} 330 331aaudio_result_t AudioStreamTrack::write(const void *buffer, 332 int32_t numFrames, 333 int64_t timeoutNanoseconds) 334{ 335 int32_t bytesPerFrame = getBytesPerFrame(); 336 int32_t numBytes; 337 aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes); 338 if (result != AAUDIO_OK) { 339 return result; 340 } 341 342 // TODO add timeout to AudioTrack 343 bool blocking = timeoutNanoseconds > 0; 344 ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking); 345 if (bytesWritten == WOULD_BLOCK) { 346 return 0; 347 } else if (bytesWritten < 0) { 348 ALOGE("invalid write, returned %d", (int)bytesWritten); 349 return AAudioConvert_androidToAAudioResult(bytesWritten); 350 } 351 int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame); 352 incrementFramesWritten(framesWritten); 353 return framesWritten; 354} 355 356aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames) 357{ 358 ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames); 359 if (result < 0) { 360 return AAudioConvert_androidToAAudioResult(result); 361 } else { 362 return result; 363 } 364} 365 366int32_t AudioStreamTrack::getBufferSize() const 367{ 368 return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames()); 369} 370 371int32_t AudioStreamTrack::getBufferCapacity() const 372{ 373 return static_cast<int32_t>(mAudioTrack->frameCount()); 374} 375 376int32_t AudioStreamTrack::getXRunCount() const 377{ 378 return static_cast<int32_t>(mAudioTrack->getUnderrunCount()); 379} 380 381int32_t AudioStreamTrack::getFramesPerBurst() const 382{ 383 return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames()); 384} 385 386int64_t AudioStreamTrack::getFramesRead() { 387 aaudio_wrapping_frames_t position; 388 status_t result; 389 switch (getState()) { 390 case AAUDIO_STREAM_STATE_STARTING: 391 case AAUDIO_STREAM_STATE_STARTED: 392 case AAUDIO_STREAM_STATE_STOPPING: 393 case AAUDIO_STREAM_STATE_PAUSING: 394 case AAUDIO_STREAM_STATE_PAUSED: 395 result = mAudioTrack->getPosition(&position); 396 if (result == OK) { 397 mFramesRead.update32(position); 398 } 399 break; 400 default: 401 break; 402 } 403 return AudioStream::getFramesRead(); 404} 405 406aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId, 407 int64_t *framePosition, 408 int64_t *timeNanoseconds) { 409 ExtendedTimestamp extendedTimestamp; 410 status_t status = mAudioTrack->getTimestamp(&extendedTimestamp); 411 if (status != NO_ERROR) { 412 return AAudioConvert_androidToAAudioResult(status); 413 } 414 return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp); 415} 416