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