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 <system/audio.h> 26#include "utility/AudioClock.h" 27#include "legacy/AudioStreamLegacy.h" 28#include "legacy/AudioStreamTrack.h" 29#include "utility/FixedBlockReader.h" 30 31using namespace android; 32using namespace aaudio; 33 34// Arbitrary and somewhat generous number of bursts. 35#define DEFAULT_BURSTS_PER_BUFFER_CAPACITY 8 36 37/* 38 * Create a stream that uses the AudioTrack. 39 */ 40AudioStreamTrack::AudioStreamTrack() 41 : AudioStreamLegacy() 42 , mFixedBlockReader(*this) 43{ 44} 45 46AudioStreamTrack::~AudioStreamTrack() 47{ 48 const aaudio_stream_state_t state = getState(); 49 bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED); 50 ALOGE_IF(bad, "stream not closed, in state %d", state); 51} 52 53aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder) 54{ 55 aaudio_result_t result = AAUDIO_OK; 56 57 result = AudioStream::open(builder); 58 if (result != OK) { 59 return result; 60 } 61 62 // Try to create an AudioTrack 63 // Use stereo if unspecified. 64 int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) 65 ? 2 : getSamplesPerFrame(); 66 audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame); 67 68 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE; 69 aaudio_performance_mode_t perfMode = getPerformanceMode(); 70 switch(perfMode) { 71 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: 72 // Bypass the normal mixer and go straight to the FAST mixer. 73 flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW); 74 break; 75 76 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: 77 // This uses a mixer that wakes up less often than the FAST mixer. 78 flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 79 break; 80 81 case AAUDIO_PERFORMANCE_MODE_NONE: 82 default: 83 // No flags. Use a normal mixer in front of the FAST mixer. 84 break; 85 } 86 87 size_t frameCount = (size_t)builder.getBufferCapacity(); 88 89 int32_t notificationFrames = 0; 90 91 audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) 92 ? AUDIO_FORMAT_PCM_FLOAT 93 : AAudioConvert_aaudioToAndroidDataFormat(getFormat()); 94 95 // Setup the callback if there is one. 96 AudioTrack::callback_t callback = nullptr; 97 void *callbackData = nullptr; 98 // Note that TRANSFER_SYNC does not allow FAST track 99 AudioTrack::transfer_type streamTransferType = AudioTrack::transfer_type::TRANSFER_SYNC; 100 if (builder.getDataCallbackProc() != nullptr) { 101 streamTransferType = AudioTrack::transfer_type::TRANSFER_CALLBACK; 102 callback = getLegacyCallback(); 103 callbackData = this; 104 105 // If the total buffer size is unspecified then base the size on the burst size. 106 if (frameCount == 0 107 && ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0)) { 108 // Take advantage of a special trick that allows us to create a buffer 109 // that is some multiple of the burst size. 110 notificationFrames = 0 - DEFAULT_BURSTS_PER_BUFFER_CAPACITY; 111 } else { 112 notificationFrames = builder.getFramesPerDataCallback(); 113 } 114 } 115 mCallbackBufferSize = builder.getFramesPerDataCallback(); 116 117 ALOGD("open(), request notificationFrames = %d, frameCount = %u", 118 notificationFrames, (uint)frameCount); 119 120 // Don't call mAudioTrack->setDeviceId() because it will be overwritten by set()! 121 audio_port_handle_t selectedDeviceId = (getDeviceId() == AAUDIO_UNSPECIFIED) 122 ? AUDIO_PORT_HANDLE_NONE 123 : getDeviceId(); 124 125 const audio_content_type_t contentType = 126 AAudioConvert_contentTypeToInternal(builder.getContentType()); 127 const audio_usage_t usage = 128 AAudioConvert_usageToInternal(builder.getUsage()); 129 130 const audio_attributes_t attributes = { 131 .content_type = contentType, 132 .usage = usage, 133 .source = AUDIO_SOURCE_DEFAULT, // only used for recording 134 .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_OUTPUT_FLAGS 135 .tags = "" 136 }; 137 138 static_assert(AAUDIO_UNSPECIFIED == AUDIO_SESSION_ALLOCATE, "Session IDs should match"); 139 140 aaudio_session_id_t requestedSessionId = builder.getSessionId(); 141 audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId); 142 143 mAudioTrack = new AudioTrack(); 144 mAudioTrack->set( 145 AUDIO_STREAM_DEFAULT, // ignored because we pass attributes below 146 getSampleRate(), 147 format, 148 channelMask, 149 frameCount, 150 flags, 151 callback, 152 callbackData, 153 notificationFrames, 154 0, // DEFAULT sharedBuffer*/, 155 false, // DEFAULT threadCanCallJava 156 sessionId, 157 streamTransferType, 158 NULL, // DEFAULT audio_offload_info_t 159 AUDIO_UID_INVALID, // DEFAULT uid 160 -1, // DEFAULT pid 161 &attributes, 162 // WARNING - If doNotReconnect set true then audio stops after plugging and unplugging 163 // headphones a few times. 164 false, // DEFAULT doNotReconnect, 165 1.0f, // DEFAULT maxRequiredSpeed 166 selectedDeviceId 167 ); 168 169 // Did we get a valid track? 170 status_t status = mAudioTrack->initCheck(); 171 if (status != NO_ERROR) { 172 close(); 173 ALOGE("open(), initCheck() returned %d", status); 174 return AAudioConvert_androidToAAudioResult(status); 175 } 176 177 doSetVolume(); 178 179 // Get the actual values from the AudioTrack. 180 setSamplesPerFrame(mAudioTrack->channelCount()); 181 aaudio_format_t aaudioFormat = 182 AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format()); 183 setFormat(aaudioFormat); 184 setDeviceFormat(aaudioFormat); 185 186 int32_t actualSampleRate = mAudioTrack->getSampleRate(); 187 ALOGW_IF(actualSampleRate != getSampleRate(), 188 "open() sampleRate changed from %d to %d", 189 getSampleRate(), actualSampleRate); 190 setSampleRate(actualSampleRate); 191 192 // We may need to pass the data through a block size adapter to guarantee constant size. 193 if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) { 194 int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize; 195 mFixedBlockReader.open(callbackSizeBytes); 196 mBlockAdapter = &mFixedBlockReader; 197 } else { 198 mBlockAdapter = nullptr; 199 } 200 201 setState(AAUDIO_STREAM_STATE_OPEN); 202 setDeviceId(mAudioTrack->getRoutedDeviceId()); 203 204 aaudio_session_id_t actualSessionId = 205 (requestedSessionId == AAUDIO_SESSION_ID_NONE) 206 ? AAUDIO_SESSION_ID_NONE 207 : (aaudio_session_id_t) mAudioTrack->getSessionId(); 208 setSessionId(actualSessionId); 209 210 mAudioTrack->addAudioDeviceCallback(mDeviceCallback); 211 212 // Update performance mode based on the actual stream flags. 213 // For example, if the sample rate is not allowed then you won't get a FAST track. 214 audio_output_flags_t actualFlags = mAudioTrack->getFlags(); 215 aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; 216 // We may not get the RAW flag. But as long as we get the FAST flag we can call it LOW_LATENCY. 217 if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) { 218 actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; 219 } else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) { 220 actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; 221 } 222 setPerformanceMode(actualPerformanceMode); 223 224 setSharingMode(AAUDIO_SHARING_MODE_SHARED); // EXCLUSIVE mode not supported in legacy 225 226 // Log warning if we did not get what we asked for. 227 ALOGW_IF(actualFlags != flags, 228 "open() flags changed from 0x%08X to 0x%08X", 229 flags, actualFlags); 230 ALOGW_IF(actualPerformanceMode != perfMode, 231 "open() perfMode changed from %d to %d", 232 perfMode, actualPerformanceMode); 233 234 return AAUDIO_OK; 235} 236 237aaudio_result_t AudioStreamTrack::close() 238{ 239 if (getState() != AAUDIO_STREAM_STATE_CLOSED) { 240 mAudioTrack->removeAudioDeviceCallback(mDeviceCallback); 241 setState(AAUDIO_STREAM_STATE_CLOSED); 242 } 243 mFixedBlockReader.close(); 244 return AAUDIO_OK; 245} 246 247void AudioStreamTrack::processCallback(int event, void *info) { 248 249 switch (event) { 250 case AudioTrack::EVENT_MORE_DATA: 251 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info); 252 break; 253 254 // Stream got rerouted so we disconnect. 255 case AudioTrack::EVENT_NEW_IAUDIOTRACK: 256 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info); 257 break; 258 259 default: 260 break; 261 } 262 return; 263} 264 265aaudio_result_t AudioStreamTrack::requestStart() { 266 if (mAudioTrack.get() == nullptr) { 267 ALOGE("requestStart() no AudioTrack"); 268 return AAUDIO_ERROR_INVALID_STATE; 269 } 270 // Get current position so we can detect when the track is playing. 271 status_t err = mAudioTrack->getPosition(&mPositionWhenStarting); 272 if (err != OK) { 273 return AAudioConvert_androidToAAudioResult(err); 274 } 275 276 // Enable callback before starting AudioTrack to avoid shutting 277 // down because of a race condition. 278 mCallbackEnabled.store(true); 279 err = mAudioTrack->start(); 280 if (err != OK) { 281 return AAudioConvert_androidToAAudioResult(err); 282 } else { 283 setState(AAUDIO_STREAM_STATE_STARTING); 284 } 285 return AAUDIO_OK; 286} 287 288aaudio_result_t AudioStreamTrack::requestPause() { 289 if (mAudioTrack.get() == nullptr) { 290 ALOGE("requestPause() no AudioTrack"); 291 return AAUDIO_ERROR_INVALID_STATE; 292 } 293 294 setState(AAUDIO_STREAM_STATE_PAUSING); 295 mAudioTrack->pause(); 296 mCallbackEnabled.store(false); 297 status_t err = mAudioTrack->getPosition(&mPositionWhenPausing); 298 if (err != OK) { 299 return AAudioConvert_androidToAAudioResult(err); 300 } 301 return checkForDisconnectRequest(false); 302} 303 304aaudio_result_t AudioStreamTrack::requestFlush() { 305 if (mAudioTrack.get() == nullptr) { 306 ALOGE("requestFlush() no AudioTrack"); 307 return AAUDIO_ERROR_INVALID_STATE; 308 } 309 310 setState(AAUDIO_STREAM_STATE_FLUSHING); 311 incrementFramesRead(getFramesWritten() - getFramesRead()); 312 mAudioTrack->flush(); 313 mFramesRead.reset32(); // service reads frames, service position reset on flush 314 mTimestampPosition.reset32(); 315 return AAUDIO_OK; 316} 317 318aaudio_result_t AudioStreamTrack::requestStop() { 319 if (mAudioTrack.get() == nullptr) { 320 ALOGE("requestStop() no AudioTrack"); 321 return AAUDIO_ERROR_INVALID_STATE; 322 } 323 324 setState(AAUDIO_STREAM_STATE_STOPPING); 325 incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review 326 mTimestampPosition.set(getFramesWritten()); 327 mFramesRead.reset32(); // service reads frames, service position reset on stop 328 mTimestampPosition.reset32(); 329 mAudioTrack->stop(); 330 mCallbackEnabled.store(false); 331 return checkForDisconnectRequest(false);; 332} 333 334aaudio_result_t AudioStreamTrack::updateStateMachine() 335{ 336 status_t err; 337 aaudio_wrapping_frames_t position; 338 switch (getState()) { 339 // TODO add better state visibility to AudioTrack 340 case AAUDIO_STREAM_STATE_STARTING: 341 if (mAudioTrack->hasStarted()) { 342 setState(AAUDIO_STREAM_STATE_STARTED); 343 } 344 break; 345 case AAUDIO_STREAM_STATE_PAUSING: 346 if (mAudioTrack->stopped()) { 347 err = mAudioTrack->getPosition(&position); 348 if (err != OK) { 349 return AAudioConvert_androidToAAudioResult(err); 350 } else if (position == mPositionWhenPausing) { 351 // Has stream really stopped advancing? 352 setState(AAUDIO_STREAM_STATE_PAUSED); 353 } 354 mPositionWhenPausing = position; 355 } 356 break; 357 case AAUDIO_STREAM_STATE_FLUSHING: 358 { 359 err = mAudioTrack->getPosition(&position); 360 if (err != OK) { 361 return AAudioConvert_androidToAAudioResult(err); 362 } else if (position == 0) { 363 // TODO Advance frames read to match written. 364 setState(AAUDIO_STREAM_STATE_FLUSHED); 365 } 366 } 367 break; 368 case AAUDIO_STREAM_STATE_STOPPING: 369 if (mAudioTrack->stopped()) { 370 setState(AAUDIO_STREAM_STATE_STOPPED); 371 } 372 break; 373 default: 374 break; 375 } 376 return AAUDIO_OK; 377} 378 379aaudio_result_t AudioStreamTrack::write(const void *buffer, 380 int32_t numFrames, 381 int64_t timeoutNanoseconds) 382{ 383 int32_t bytesPerFrame = getBytesPerFrame(); 384 int32_t numBytes; 385 aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes); 386 if (result != AAUDIO_OK) { 387 return result; 388 } 389 390 if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) { 391 return AAUDIO_ERROR_DISCONNECTED; 392 } 393 394 // TODO add timeout to AudioTrack 395 bool blocking = timeoutNanoseconds > 0; 396 ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking); 397 if (bytesWritten == WOULD_BLOCK) { 398 return 0; 399 } else if (bytesWritten < 0) { 400 ALOGE("invalid write, returned %d", (int)bytesWritten); 401 // in this context, a DEAD_OBJECT is more likely to be a disconnect notification due to 402 // AudioTrack invalidation 403 if (bytesWritten == DEAD_OBJECT) { 404 setState(AAUDIO_STREAM_STATE_DISCONNECTED); 405 return AAUDIO_ERROR_DISCONNECTED; 406 } 407 return AAudioConvert_androidToAAudioResult(bytesWritten); 408 } 409 int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame); 410 incrementFramesWritten(framesWritten); 411 412 result = updateStateMachine(); 413 if (result != AAUDIO_OK) { 414 return result; 415 } 416 417 return framesWritten; 418} 419 420aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames) 421{ 422 ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames); 423 if (result < 0) { 424 return AAudioConvert_androidToAAudioResult(result); 425 } else { 426 return result; 427 } 428} 429 430int32_t AudioStreamTrack::getBufferSize() const 431{ 432 return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames()); 433} 434 435int32_t AudioStreamTrack::getBufferCapacity() const 436{ 437 return static_cast<int32_t>(mAudioTrack->frameCount()); 438} 439 440int32_t AudioStreamTrack::getXRunCount() const 441{ 442 return static_cast<int32_t>(mAudioTrack->getUnderrunCount()); 443} 444 445int32_t AudioStreamTrack::getFramesPerBurst() const 446{ 447 return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames()); 448} 449 450int64_t AudioStreamTrack::getFramesRead() { 451 aaudio_wrapping_frames_t position; 452 status_t result; 453 switch (getState()) { 454 case AAUDIO_STREAM_STATE_STARTING: 455 case AAUDIO_STREAM_STATE_STARTED: 456 case AAUDIO_STREAM_STATE_STOPPING: 457 case AAUDIO_STREAM_STATE_PAUSING: 458 case AAUDIO_STREAM_STATE_PAUSED: 459 result = mAudioTrack->getPosition(&position); 460 if (result == OK) { 461 mFramesRead.update32(position); 462 } 463 break; 464 default: 465 break; 466 } 467 return AudioStreamLegacy::getFramesRead(); 468} 469 470aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId, 471 int64_t *framePosition, 472 int64_t *timeNanoseconds) { 473 ExtendedTimestamp extendedTimestamp; 474 status_t status = mAudioTrack->getTimestamp(&extendedTimestamp); 475 if (status == WOULD_BLOCK) { 476 return AAUDIO_ERROR_INVALID_STATE; 477 } if (status != NO_ERROR) { 478 return AAudioConvert_androidToAAudioResult(status); 479 } 480 int64_t position = 0; 481 int64_t nanoseconds = 0; 482 aaudio_result_t result = getBestTimestamp(clockId, &position, 483 &nanoseconds, &extendedTimestamp); 484 if (result == AAUDIO_OK) { 485 if (position < getFramesWritten()) { 486 *framePosition = position; 487 *timeNanoseconds = nanoseconds; 488 return result; 489 } else { 490 return AAUDIO_ERROR_INVALID_STATE; // TODO review, documented but not consistent 491 } 492 } 493 return result; 494} 495 496status_t AudioStreamTrack::doSetVolume() { 497 status_t status = NO_INIT; 498 if (mAudioTrack.get() != nullptr) { 499 float volume = getDuckAndMuteVolume(); 500 mAudioTrack->setVolume(volume, volume); 501 status = NO_ERROR; 502 } 503 return status; 504} 505 506#if AAUDIO_USE_VOLUME_SHAPER 507 508using namespace android::media::VolumeShaper; 509 510binder::Status AudioStreamTrack::applyVolumeShaper( 511 const VolumeShaper::Configuration& configuration, 512 const VolumeShaper::Operation& operation) { 513 514 sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration); 515 sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation); 516 517 if (mAudioTrack.get() != nullptr) { 518 ALOGD("applyVolumeShaper() from IPlayer"); 519 binder::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation); 520 if (status < 0) { // a non-negative value is the volume shaper id. 521 ALOGE("applyVolumeShaper() failed with status %d", status); 522 } 523 return binder::Status::fromStatusT(status); 524 } else { 525 ALOGD("applyVolumeShaper()" 526 " no AudioTrack for volume control from IPlayer"); 527 return binder::Status::ok(); 528 } 529} 530#endif 531