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