Home | History | Annotate | Download | only in legacy
      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 
     31 using namespace android;
     32 using 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  */
     40 AudioStreamTrack::AudioStreamTrack()
     41     : AudioStreamLegacy()
     42     , mFixedBlockReader(*this)
     43 {
     44 }
     45 
     46 AudioStreamTrack::~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 
     53 aaudio_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 
    237 aaudio_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 
    247 void 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 
    265 aaudio_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 
    288 aaudio_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 
    304 aaudio_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 
    318 aaudio_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 
    334 aaudio_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 
    379 aaudio_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 
    420 aaudio_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 
    430 int32_t AudioStreamTrack::getBufferSize() const
    431 {
    432     return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames());
    433 }
    434 
    435 int32_t AudioStreamTrack::getBufferCapacity() const
    436 {
    437     return static_cast<int32_t>(mAudioTrack->frameCount());
    438 }
    439 
    440 int32_t AudioStreamTrack::getXRunCount() const
    441 {
    442     return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
    443 }
    444 
    445 int32_t AudioStreamTrack::getFramesPerBurst() const
    446 {
    447     return static_cast<int32_t>(mAudioTrack->getNotificationPeriodInFrames());
    448 }
    449 
    450 int64_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 
    470 aaudio_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 
    496 status_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 
    508 using namespace android::media::VolumeShaper;
    509 
    510 binder::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