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