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