AudioStreamTrack.cpp revision f53e613b3dedab3ecada2c93d8846233c442d129
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 "AudioStreamTrack.h" 27 28 29using namespace android; 30using namespace aaudio; 31 32/* 33 * Create a stream that uses the AudioTrack. 34 */ 35AudioStreamTrack::AudioStreamTrack() 36 : AudioStream() 37{ 38} 39 40AudioStreamTrack::~AudioStreamTrack() 41{ 42 const aaudio_stream_state_t state = getState(); 43 bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED); 44 ALOGE_IF(bad, "stream not closed, in state %d", state); 45} 46 47aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder) 48{ 49 aaudio_result_t result = AAUDIO_OK; 50 51 result = AudioStream::open(builder); 52 if (result != OK) { 53 return result; 54 } 55 56 // Try to create an AudioTrack 57 // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified. 58 int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) 59 ? 2 : getSamplesPerFrame(); 60 audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame); 61 ALOGD("AudioStreamTrack::open(), samplesPerFrame = %d, channelMask = 0x%08x", 62 samplesPerFrame, channelMask); 63 64 AudioTrack::callback_t callback = nullptr; 65 // TODO add more performance options 66 audio_output_flags_t flags = (audio_output_flags_t) AUDIO_OUTPUT_FLAG_FAST; 67 size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0 68 : builder.getBufferCapacity(); 69 // TODO implement an unspecified AudioTrack format then use that. 70 audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED) 71 ? AUDIO_FORMAT_PCM_FLOAT 72 : AAudioConvert_aaudioToAndroidDataFormat(getFormat()); 73 74 mAudioTrack = new AudioTrack( 75 (audio_stream_type_t) AUDIO_STREAM_MUSIC, 76 getSampleRate(), 77 format, 78 channelMask, 79 frameCount, 80 flags, 81 callback, 82 nullptr, // user callback data 83 0, // notificationFrames 84 AUDIO_SESSION_ALLOCATE, 85 AudioTrack::transfer_type::TRANSFER_SYNC // TODO - this does not allow FAST 86 ); 87 88 // Did we get a valid track? 89 status_t status = mAudioTrack->initCheck(); 90 ALOGD("AudioStreamTrack::open(), initCheck() returned %d", status); 91 if (status != NO_ERROR) { 92 close(); 93 ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status); 94 return AAudioConvert_androidToAAudioResult(status); 95 } 96 97 // Get the actual values from the AudioTrack. 98 setSamplesPerFrame(mAudioTrack->channelCount()); 99 setSampleRate(mAudioTrack->getSampleRate()); 100 setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format())); 101 102 setState(AAUDIO_STREAM_STATE_OPEN); 103 104 return AAUDIO_OK; 105} 106 107aaudio_result_t AudioStreamTrack::close() 108{ 109 // TODO maybe add close() or release() to AudioTrack API then call it from here 110 if (getState() != AAUDIO_STREAM_STATE_CLOSED) { 111 mAudioTrack.clear(); // TODO is this right? 112 setState(AAUDIO_STREAM_STATE_CLOSED); 113 } 114 return AAUDIO_OK; 115} 116 117aaudio_result_t AudioStreamTrack::requestStart() 118{ 119 if (mAudioTrack.get() == nullptr) { 120 return AAUDIO_ERROR_INVALID_STATE; 121 } 122 // Get current position so we can detect when the track is playing. 123 status_t err = mAudioTrack->getPosition(&mPositionWhenStarting); 124 if (err != OK) { 125 return AAudioConvert_androidToAAudioResult(err); 126 } 127 err = mAudioTrack->start(); 128 if (err != OK) { 129 return AAudioConvert_androidToAAudioResult(err); 130 } else { 131 setState(AAUDIO_STREAM_STATE_STARTING); 132 } 133 return AAUDIO_OK; 134} 135 136aaudio_result_t AudioStreamTrack::requestPause() 137{ 138 if (mAudioTrack.get() == nullptr) { 139 return AAUDIO_ERROR_INVALID_STATE; 140 } else if (getState() != AAUDIO_STREAM_STATE_STARTING 141 && getState() != AAUDIO_STREAM_STATE_STARTED) { 142 ALOGE("requestPause(), called when state is %s", AAudio_convertStreamStateToText(getState())); 143 return AAUDIO_ERROR_INVALID_STATE; 144 } 145 setState(AAUDIO_STREAM_STATE_PAUSING); 146 mAudioTrack->pause(); 147 status_t err = mAudioTrack->getPosition(&mPositionWhenPausing); 148 if (err != OK) { 149 return AAudioConvert_androidToAAudioResult(err); 150 } 151 return AAUDIO_OK; 152} 153 154aaudio_result_t AudioStreamTrack::requestFlush() { 155 if (mAudioTrack.get() == nullptr) { 156 return AAUDIO_ERROR_INVALID_STATE; 157 } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) { 158 return AAUDIO_ERROR_INVALID_STATE; 159 } 160 setState(AAUDIO_STREAM_STATE_FLUSHING); 161 incrementFramesRead(getFramesWritten() - getFramesRead()); 162 mAudioTrack->flush(); 163 mFramesWritten.reset32(); 164 return AAUDIO_OK; 165} 166 167aaudio_result_t AudioStreamTrack::requestStop() { 168 if (mAudioTrack.get() == nullptr) { 169 return AAUDIO_ERROR_INVALID_STATE; 170 } 171 setState(AAUDIO_STREAM_STATE_STOPPING); 172 incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review 173 mAudioTrack->stop(); 174 mFramesWritten.reset32(); 175 return AAUDIO_OK; 176} 177 178aaudio_result_t AudioStreamTrack::updateState() 179{ 180 status_t err; 181 aaudio_wrapping_frames_t position; 182 switch (getState()) { 183 // TODO add better state visibility to AudioTrack 184 case AAUDIO_STREAM_STATE_STARTING: 185 if (mAudioTrack->hasStarted()) { 186 setState(AAUDIO_STREAM_STATE_STARTED); 187 } 188 break; 189 case AAUDIO_STREAM_STATE_PAUSING: 190 if (mAudioTrack->stopped()) { 191 err = mAudioTrack->getPosition(&position); 192 if (err != OK) { 193 return AAudioConvert_androidToAAudioResult(err); 194 } else if (position == mPositionWhenPausing) { 195 // Has stream really stopped advancing? 196 setState(AAUDIO_STREAM_STATE_PAUSED); 197 } 198 mPositionWhenPausing = position; 199 } 200 break; 201 case AAUDIO_STREAM_STATE_FLUSHING: 202 { 203 err = mAudioTrack->getPosition(&position); 204 if (err != OK) { 205 return AAudioConvert_androidToAAudioResult(err); 206 } else if (position == 0) { 207 // Advance frames read to match written. 208 setState(AAUDIO_STREAM_STATE_FLUSHED); 209 } 210 } 211 break; 212 case AAUDIO_STREAM_STATE_STOPPING: 213 if (mAudioTrack->stopped()) { 214 setState(AAUDIO_STREAM_STATE_STOPPED); 215 } 216 break; 217 default: 218 break; 219 } 220 return AAUDIO_OK; 221} 222 223aaudio_result_t AudioStreamTrack::write(const void *buffer, 224 aaudio_size_frames_t numFrames, 225 aaudio_nanoseconds_t timeoutNanoseconds) 226{ 227 aaudio_size_frames_t bytesPerFrame = getBytesPerFrame(); 228 aaudio_size_bytes_t numBytes; 229 aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes); 230 if (result != AAUDIO_OK) { 231 return result; 232 } 233 234 // TODO add timeout to AudioTrack 235 bool blocking = timeoutNanoseconds > 0; 236 ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking); 237 if (bytesWritten == WOULD_BLOCK) { 238 return 0; 239 } else if (bytesWritten < 0) { 240 ALOGE("invalid write, returned %d", (int)bytesWritten); 241 return AAudioConvert_androidToAAudioResult(bytesWritten); 242 } 243 aaudio_size_frames_t framesWritten = (aaudio_size_frames_t)(bytesWritten / bytesPerFrame); 244 incrementFramesWritten(framesWritten); 245 return framesWritten; 246} 247 248aaudio_result_t AudioStreamTrack::setBufferSize(aaudio_size_frames_t requestedFrames, 249 aaudio_size_frames_t *actualFrames) 250{ 251 ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames); 252 if (result != OK) { 253 return AAudioConvert_androidToAAudioResult(result); 254 } else { 255 *actualFrames = result; 256 return AAUDIO_OK; 257 } 258} 259 260aaudio_size_frames_t AudioStreamTrack::getBufferSize() const 261{ 262 return static_cast<aaudio_size_frames_t>(mAudioTrack->getBufferSizeInFrames()); 263} 264 265aaudio_size_frames_t AudioStreamTrack::getBufferCapacity() const 266{ 267 return static_cast<aaudio_size_frames_t>(mAudioTrack->frameCount()); 268} 269 270int32_t AudioStreamTrack::getXRunCount() const 271{ 272 return static_cast<int32_t>(mAudioTrack->getUnderrunCount()); 273} 274 275int32_t AudioStreamTrack::getFramesPerBurst() const 276{ 277 return 192; // TODO add query to AudioTrack.cpp 278} 279 280aaudio_position_frames_t AudioStreamTrack::getFramesRead() { 281 aaudio_wrapping_frames_t position; 282 status_t result; 283 switch (getState()) { 284 case AAUDIO_STREAM_STATE_STARTING: 285 case AAUDIO_STREAM_STATE_STARTED: 286 case AAUDIO_STREAM_STATE_STOPPING: 287 result = mAudioTrack->getPosition(&position); 288 if (result == OK) { 289 mFramesRead.update32(position); 290 } 291 break; 292 default: 293 break; 294 } 295 return AudioStream::getFramesRead(); 296} 297