Home | History | Annotate | Download | only in legacy
      1 /*
      2  * Copyright 2017 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 "AudioStreamLegacy"
     18 //#define LOG_NDEBUG 0
     19 #include <utils/Log.h>
     20 
     21 #include <stdint.h>
     22 
     23 #include <aaudio/AAudio.h>
     24 #include <audio_utils/primitives.h>
     25 #include <media/AudioTrack.h>
     26 #include <media/AudioTimestamp.h>
     27 #include <utils/String16.h>
     28 
     29 #include "core/AudioStream.h"
     30 #include "legacy/AudioStreamLegacy.h"
     31 
     32 using namespace android;
     33 using namespace aaudio;
     34 
     35 AudioStreamLegacy::AudioStreamLegacy()
     36         : AudioStream()
     37         , mDeviceCallback(new StreamDeviceCallback(this)) {
     38 }
     39 
     40 AudioStreamLegacy::~AudioStreamLegacy() {
     41 }
     42 
     43 // Called from AudioTrack.cpp or AudioRecord.cpp
     44 static void AudioStreamLegacy_callback(int event, void* userData, void *info) {
     45     AudioStreamLegacy *streamLegacy = (AudioStreamLegacy *) userData;
     46     streamLegacy->processCallback(event, info);
     47 }
     48 
     49 aaudio_legacy_callback_t AudioStreamLegacy::getLegacyCallback() {
     50     return AudioStreamLegacy_callback;
     51 }
     52 
     53 aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer,
     54                                                                         int32_t numFrames) {
     55     void *finalAudioData = buffer;
     56     if (getDirection() == AAUDIO_DIRECTION_INPUT) {
     57         // Increment before because we already got the data from the device.
     58         incrementFramesRead(numFrames);
     59         finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames);
     60     }
     61 
     62     // Call using the AAudio callback interface.
     63     aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, numFrames);
     64 
     65     if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
     66             && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
     67         // Increment after because we are going to write the data to the device.
     68         incrementFramesWritten(numFrames);
     69     }
     70     return callbackResult;
     71 }
     72 
     73 // Implement FixedBlockProcessor
     74 int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
     75     int32_t numFrames = numBytes / getBytesPerDeviceFrame();
     76     return (int32_t) callDataCallbackFrames(buffer, numFrames);
     77 }
     78 
     79 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
     80     aaudio_data_callback_result_t callbackResult;
     81     // This illegal size can be used to tell AudioFlinger to stop calling us.
     82     // This takes advantage of AudioFlinger killing the stream.
     83     // TODO add to API in AudioRecord and AudioTrack
     84     const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
     85 
     86     switch (opcode) {
     87         case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
     88             (void) checkForDisconnectRequest(true);
     89 
     90             // Note that this code assumes an AudioTrack::Buffer is the same as
     91             // AudioRecord::Buffer
     92             // TODO define our own AudioBuffer and pass it from the subclasses.
     93             AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
     94             if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
     95                 ALOGW("processCallbackCommon() data, stream disconnected");
     96                 audioBuffer->size = SIZE_STOP_CALLBACKS;
     97             } else if (!mCallbackEnabled.load()) {
     98                 ALOGW("processCallbackCommon() stopping because callback disabled");
     99                 audioBuffer->size = SIZE_STOP_CALLBACKS;
    100             } else {
    101                 if (audioBuffer->frameCount == 0) {
    102                     ALOGW("processCallbackCommon() data, frameCount is zero");
    103                     return;
    104                 }
    105 
    106                 // If the caller specified an exact size then use a block size adapter.
    107                 if (mBlockAdapter != nullptr) {
    108                     int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame();
    109                     callbackResult = mBlockAdapter->processVariableBlock(
    110                             (uint8_t *) audioBuffer->raw, byteCount);
    111                 } else {
    112                     // Call using the AAudio callback interface.
    113                     callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
    114                                                             audioBuffer->frameCount);
    115                 }
    116                 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
    117                     audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame();
    118                 } else { // STOP or invalid result
    119                     ALOGW("%s() callback requested stop, fake an error", __func__);
    120                     audioBuffer->size = SIZE_STOP_CALLBACKS;
    121                     // Disable the callback just in case AudioFlinger keeps trying to call us.
    122                     mCallbackEnabled.store(false);
    123                 }
    124 
    125                 if (updateStateMachine() != AAUDIO_OK) {
    126                     forceDisconnect();
    127                     mCallbackEnabled.store(false);
    128                 }
    129             }
    130         }
    131             break;
    132 
    133         // Stream got rerouted so we disconnect.
    134         case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
    135             ALOGD("processCallbackCommon() stream disconnected");
    136             forceDisconnect();
    137             mCallbackEnabled.store(false);
    138             break;
    139 
    140         default:
    141             break;
    142     }
    143 }
    144 
    145 aaudio_result_t AudioStreamLegacy::checkForDisconnectRequest(bool errorCallbackEnabled) {
    146     if (mRequestDisconnect.isRequested()) {
    147         ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
    148         forceDisconnect(errorCallbackEnabled);
    149         mRequestDisconnect.acknowledge();
    150         mCallbackEnabled.store(false);
    151         return AAUDIO_ERROR_DISCONNECTED;
    152     } else {
    153         return AAUDIO_OK;
    154     }
    155 }
    156 
    157 void AudioStreamLegacy::forceDisconnect(bool errorCallbackEnabled) {
    158     if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
    159         setState(AAUDIO_STREAM_STATE_DISCONNECTED);
    160         if (errorCallbackEnabled) {
    161             maybeCallErrorCallback(AAUDIO_ERROR_DISCONNECTED);
    162         }
    163     }
    164 }
    165 
    166 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
    167                                                    int64_t *framePosition,
    168                                                    int64_t *timeNanoseconds,
    169                                                    ExtendedTimestamp *extendedTimestamp) {
    170     int timebase;
    171     switch (clockId) {
    172         case CLOCK_BOOTTIME:
    173             timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
    174             break;
    175         case CLOCK_MONOTONIC:
    176             timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
    177             break;
    178         default:
    179             ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
    180             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
    181             break;
    182     }
    183     ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
    184     int64_t localPosition;
    185     status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
    186                                                           timebase, &location);
    187     if (status == OK) {
    188         // use MonotonicCounter to prevent retrograde motion.
    189         mTimestampPosition.update32((int32_t) localPosition);
    190         *framePosition = mTimestampPosition.get();
    191     }
    192 
    193 //    ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
    194 //          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
    195 //          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
    196 //          (int)location);
    197     return AAudioConvert_androidToAAudioResult(status);
    198 }
    199 
    200 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
    201 {
    202     ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
    203     if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
    204             getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
    205         // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
    206         // If we have a data callback and the stream is active, then ask the data callback
    207         // to DISCONNECT and call the error callback.
    208         if (isDataCallbackActive()) {
    209             ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
    210             // If the stream is stopped before the data callback has a chance to handle the
    211             // request then the requestStop() and requestPause() methods will handle it after
    212             // the callback has stopped.
    213             mRequestDisconnect.request();
    214         } else {
    215             ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
    216             forceDisconnect();
    217         }
    218     }
    219     setDeviceId(deviceId);
    220 }
    221