AudioStreamTrack.cpp revision b588402d48c9634fa72e7e13ca6d6f2a0766cb98
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 "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 146 return AAUDIO_OK; 147} 148 149aaudio_result_t AudioStreamTrack::close() 150{ 151 // TODO maybe add close() or release() to AudioTrack API then call it from here 152 if (getState() != AAUDIO_STREAM_STATE_CLOSED) { 153 mAudioTrack.clear(); // TODO is this right? 154 setState(AAUDIO_STREAM_STATE_CLOSED); 155 } 156 mFixedBlockReader.close(); 157 return AAUDIO_OK; 158} 159 160void AudioStreamTrack::processCallback(int event, void *info) { 161 162 switch (event) { 163 case AudioTrack::EVENT_MORE_DATA: 164 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_PROCESS_DATA, info); 165 break; 166 167 // Stream got rerouted so we disconnect. 168 case AudioTrack::EVENT_NEW_IAUDIOTRACK: 169 processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info); 170 break; 171 172 default: 173 break; 174 } 175 return; 176} 177 178aaudio_result_t AudioStreamTrack::requestStart() 179{ 180 std::lock_guard<std::mutex> lock(mStreamMutex); 181 182 if (mAudioTrack.get() == nullptr) { 183 return AAUDIO_ERROR_INVALID_STATE; 184 } 185 // Get current position so we can detect when the track is playing. 186 status_t err = mAudioTrack->getPosition(&mPositionWhenStarting); 187 if (err != OK) { 188 return AAudioConvert_androidToAAudioResult(err); 189 } 190 191 err = mAudioTrack->start(); 192 if (err != OK) { 193 return AAudioConvert_androidToAAudioResult(err); 194 } else { 195 setState(AAUDIO_STREAM_STATE_STARTING); 196 } 197 return AAUDIO_OK; 198} 199 200aaudio_result_t AudioStreamTrack::requestPause() 201{ 202 std::lock_guard<std::mutex> lock(mStreamMutex); 203 204 if (mAudioTrack.get() == nullptr) { 205 return AAUDIO_ERROR_INVALID_STATE; 206 } else if (getState() != AAUDIO_STREAM_STATE_STARTING 207 && getState() != AAUDIO_STREAM_STATE_STARTED) { 208 ALOGE("requestPause(), called when state is %s", 209 AAudio_convertStreamStateToText(getState())); 210 return AAUDIO_ERROR_INVALID_STATE; 211 } 212 setState(AAUDIO_STREAM_STATE_PAUSING); 213 mAudioTrack->pause(); 214 status_t err = mAudioTrack->getPosition(&mPositionWhenPausing); 215 if (err != OK) { 216 return AAudioConvert_androidToAAudioResult(err); 217 } 218 return AAUDIO_OK; 219} 220 221aaudio_result_t AudioStreamTrack::requestFlush() { 222 std::lock_guard<std::mutex> lock(mStreamMutex); 223 224 if (mAudioTrack.get() == nullptr) { 225 return AAUDIO_ERROR_INVALID_STATE; 226 } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) { 227 return AAUDIO_ERROR_INVALID_STATE; 228 } 229 setState(AAUDIO_STREAM_STATE_FLUSHING); 230 incrementFramesRead(getFramesWritten() - getFramesRead()); 231 mAudioTrack->flush(); 232 mFramesWritten.reset32(); 233 return AAUDIO_OK; 234} 235 236aaudio_result_t AudioStreamTrack::requestStop() { 237 std::lock_guard<std::mutex> lock(mStreamMutex); 238 239 if (mAudioTrack.get() == nullptr) { 240 return AAUDIO_ERROR_INVALID_STATE; 241 } 242 setState(AAUDIO_STREAM_STATE_STOPPING); 243 incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review 244 mAudioTrack->stop(); 245 mFramesWritten.reset32(); 246 return AAUDIO_OK; 247} 248 249aaudio_result_t AudioStreamTrack::updateStateWhileWaiting() 250{ 251 status_t err; 252 aaudio_wrapping_frames_t position; 253 switch (getState()) { 254 // TODO add better state visibility to AudioTrack 255 case AAUDIO_STREAM_STATE_STARTING: 256 if (mAudioTrack->hasStarted()) { 257 setState(AAUDIO_STREAM_STATE_STARTED); 258 } 259 break; 260 case AAUDIO_STREAM_STATE_PAUSING: 261 if (mAudioTrack->stopped()) { 262 err = mAudioTrack->getPosition(&position); 263 if (err != OK) { 264 return AAudioConvert_androidToAAudioResult(err); 265 } else if (position == mPositionWhenPausing) { 266 // Has stream really stopped advancing? 267 setState(AAUDIO_STREAM_STATE_PAUSED); 268 } 269 mPositionWhenPausing = position; 270 } 271 break; 272 case AAUDIO_STREAM_STATE_FLUSHING: 273 { 274 err = mAudioTrack->getPosition(&position); 275 if (err != OK) { 276 return AAudioConvert_androidToAAudioResult(err); 277 } else if (position == 0) { 278 // Advance frames read to match written. 279 setState(AAUDIO_STREAM_STATE_FLUSHED); 280 } 281 } 282 break; 283 case AAUDIO_STREAM_STATE_STOPPING: 284 if (mAudioTrack->stopped()) { 285 setState(AAUDIO_STREAM_STATE_STOPPED); 286 } 287 break; 288 default: 289 break; 290 } 291 return AAUDIO_OK; 292} 293 294aaudio_result_t AudioStreamTrack::write(const void *buffer, 295 int32_t numFrames, 296 int64_t timeoutNanoseconds) 297{ 298 int32_t bytesPerFrame = getBytesPerFrame(); 299 int32_t numBytes; 300 aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes); 301 if (result != AAUDIO_OK) { 302 return result; 303 } 304 305 // TODO add timeout to AudioTrack 306 bool blocking = timeoutNanoseconds > 0; 307 ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking); 308 if (bytesWritten == WOULD_BLOCK) { 309 return 0; 310 } else if (bytesWritten < 0) { 311 ALOGE("invalid write, returned %d", (int)bytesWritten); 312 return AAudioConvert_androidToAAudioResult(bytesWritten); 313 } 314 int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame); 315 incrementFramesWritten(framesWritten); 316 return framesWritten; 317} 318 319aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames) 320{ 321 ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames); 322 if (result < 0) { 323 return AAudioConvert_androidToAAudioResult(result); 324 } else { 325 return result; 326 } 327} 328 329int32_t AudioStreamTrack::getBufferSize() const 330{ 331 return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames()); 332} 333 334int32_t AudioStreamTrack::getBufferCapacity() const 335{ 336 return static_cast<int32_t>(mAudioTrack->frameCount()); 337} 338 339int32_t AudioStreamTrack::getXRunCount() const 340{ 341 return static_cast<int32_t>(mAudioTrack->getUnderrunCount()); 342} 343 344int32_t AudioStreamTrack::getFramesPerBurst() const 345{ 346 return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames()); 347} 348 349int64_t AudioStreamTrack::getFramesRead() { 350 aaudio_wrapping_frames_t position; 351 status_t result; 352 switch (getState()) { 353 case AAUDIO_STREAM_STATE_STARTING: 354 case AAUDIO_STREAM_STATE_STARTED: 355 case AAUDIO_STREAM_STATE_STOPPING: 356 result = mAudioTrack->getPosition(&position); 357 if (result == OK) { 358 mFramesRead.update32(position); 359 } 360 break; 361 default: 362 break; 363 } 364 return AudioStream::getFramesRead(); 365} 366 367aaudio_result_t AudioStreamTrack::getTimestamp(clockid_t clockId, 368 int64_t *framePosition, 369 int64_t *timeNanoseconds) { 370 ExtendedTimestamp extendedTimestamp; 371 status_t status = mAudioTrack->getTimestamp(&extendedTimestamp); 372 if (status != NO_ERROR) { 373 return AAudioConvert_androidToAAudioResult(status); 374 } 375 // TODO Merge common code into AudioStreamLegacy after rebasing. 376 int timebase; 377 switch (clockId) { 378 case CLOCK_BOOTTIME: 379 timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME; 380 break; 381 case CLOCK_MONOTONIC: 382 timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC; 383 break; 384 default: 385 ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId); 386 return AAUDIO_ERROR_UNEXPECTED_VALUE; 387 break; 388 } 389 status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase); 390 return AAudioConvert_androidToAAudioResult(status); 391} 392