Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2015 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 "AAudioStream"
     18 //#define LOG_NDEBUG 0
     19 #include <utils/Log.h>
     20 
     21 #include <atomic>
     22 #include <stdint.h>
     23 #include <aaudio/AAudio.h>
     24 
     25 #include "AudioStreamBuilder.h"
     26 #include "AudioStream.h"
     27 #include "AudioClock.h"
     28 
     29 using namespace aaudio;
     30 
     31 AudioStream::AudioStream()
     32         : mPlayerBase(new MyPlayerBase(this))
     33 {
     34     // mThread is a pthread_t of unknown size so we need memset.
     35     memset(&mThread, 0, sizeof(mThread));
     36     setPeriodNanoseconds(0);
     37 }
     38 
     39 AudioStream::~AudioStream() {
     40     ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState()));
     41     // If the stream is deleted when OPEN or in use then audio resources will leak.
     42     // This would indicate an internal error. So we want to find this ASAP.
     43     LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
     44                           || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
     45                           || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
     46                         "aaudio stream still in use, state = %s",
     47                         AAudio_convertStreamStateToText(getState()));
     48 
     49     mPlayerBase->clearParentReference(); // remove reference to this AudioStream
     50 }
     51 
     52 static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
     53     const char *result;
     54     switch (sharingMode) {
     55         case AAUDIO_SHARING_MODE_EXCLUSIVE:
     56             result = "EX";
     57             break;
     58         case AAUDIO_SHARING_MODE_SHARED:
     59             result = "SH";
     60             break;
     61         default:
     62             result = "?!";
     63             break;
     64     }
     65     return result;
     66 }
     67 
     68 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
     69 {
     70     // Call here as well because the AAudioService will call this without calling build().
     71     aaudio_result_t result = builder.validate();
     72     if (result != AAUDIO_OK) {
     73         return result;
     74     }
     75 
     76     // Copy parameters from the Builder because the Builder may be deleted after this call.
     77     mSamplesPerFrame = builder.getSamplesPerFrame();
     78     mSampleRate = builder.getSampleRate();
     79     mDeviceId = builder.getDeviceId();
     80     mFormat = builder.getFormat();
     81     mSharingMode = builder.getSharingMode();
     82     mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
     83 
     84     mPerformanceMode = builder.getPerformanceMode();
     85 
     86     // callbacks
     87     mFramesPerDataCallback = builder.getFramesPerDataCallback();
     88     mDataCallbackProc = builder.getDataCallbackProc();
     89     mErrorCallbackProc = builder.getErrorCallbackProc();
     90     mDataCallbackUserData = builder.getDataCallbackUserData();
     91     mErrorCallbackUserData = builder.getErrorCallbackUserData();
     92 
     93     // This is very helpful for debugging in the future. Please leave it in.
     94     ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
     95           mSampleRate, mSamplesPerFrame, mFormat,
     96           AudioStream_convertSharingModeToShortText(mSharingMode),
     97           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
     98     ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d",
     99           mDeviceId, mPerformanceMode,
    100           (mDataCallbackProc == nullptr ? "OFF" : "ON"),
    101           mFramesPerDataCallback);
    102 
    103     return AAUDIO_OK;
    104 }
    105 
    106 
    107 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
    108                                                 aaudio_stream_state_t *nextState,
    109                                                 int64_t timeoutNanoseconds)
    110 {
    111     aaudio_result_t result = updateStateMachine();
    112     if (result != AAUDIO_OK) {
    113         return result;
    114     }
    115 
    116     int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
    117     aaudio_stream_state_t state = getState();
    118     while (state == currentState && timeoutNanoseconds > 0) {
    119         if (durationNanos > timeoutNanoseconds) {
    120             durationNanos = timeoutNanoseconds;
    121         }
    122         AudioClock::sleepForNanos(durationNanos);
    123         timeoutNanoseconds -= durationNanos;
    124 
    125         aaudio_result_t result = updateStateMachine();
    126         if (result != AAUDIO_OK) {
    127             return result;
    128         }
    129 
    130         state = getState();
    131     }
    132     if (nextState != nullptr) {
    133         *nextState = state;
    134     }
    135     return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
    136 }
    137 
    138 // This registers the callback thread with the server before
    139 // passing control to the app. This gives the server an opportunity to boost
    140 // the thread's performance characteristics.
    141 void* AudioStream::wrapUserThread() {
    142     void* procResult = nullptr;
    143     mThreadRegistrationResult = registerThread();
    144     if (mThreadRegistrationResult == AAUDIO_OK) {
    145         // Run callback loop. This may take a very long time.
    146         procResult = mThreadProc(mThreadArg);
    147         mThreadRegistrationResult = unregisterThread();
    148     }
    149     return procResult;
    150 }
    151 
    152 // This is the entry point for the new thread created by createThread().
    153 // It converts the 'C' function call to a C++ method call.
    154 static void* AudioStream_internalThreadProc(void* threadArg) {
    155     AudioStream *audioStream = (AudioStream *) threadArg;
    156     return audioStream->wrapUserThread();
    157 }
    158 
    159 // This is not exposed in the API.
    160 // But it is still used internally to implement callbacks for MMAP mode.
    161 aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
    162                                      aaudio_audio_thread_proc_t threadProc,
    163                                      void* threadArg)
    164 {
    165     if (mHasThread) {
    166         ALOGE("AudioStream::createThread() - mHasThread already true");
    167         return AAUDIO_ERROR_INVALID_STATE;
    168     }
    169     if (threadProc == nullptr) {
    170         return AAUDIO_ERROR_NULL;
    171     }
    172     // Pass input parameters to the background thread.
    173     mThreadProc = threadProc;
    174     mThreadArg = threadArg;
    175     setPeriodNanoseconds(periodNanoseconds);
    176     int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
    177     if (err != 0) {
    178         return AAudioConvert_androidToAAudioResult(-errno);
    179     } else {
    180         mHasThread = true;
    181         return AAUDIO_OK;
    182     }
    183 }
    184 
    185 aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
    186 {
    187     if (!mHasThread) {
    188         ALOGE("AudioStream::joinThread() - but has no thread");
    189         return AAUDIO_ERROR_INVALID_STATE;
    190     }
    191 #if 0
    192     // TODO implement equivalent of pthread_timedjoin_np()
    193     struct timespec abstime;
    194     int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
    195 #else
    196     int err = pthread_join(mThread, returnArg);
    197 #endif
    198     mHasThread = false;
    199     return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
    200 }
    201 
    202 
    203 #if AAUDIO_USE_VOLUME_SHAPER
    204 android::media::VolumeShaper::Status AudioStream::applyVolumeShaper(
    205         const android::media::VolumeShaper::Configuration& configuration __unused,
    206         const android::media::VolumeShaper::Operation& operation __unused) {
    207     ALOGW("applyVolumeShaper() is not supported");
    208     return android::media::VolumeShaper::Status::ok();
    209 }
    210 #endif
    211 
    212 AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) {
    213 }
    214 
    215 AudioStream::MyPlayerBase::~MyPlayerBase() {
    216     ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
    217 }
    218 
    219 void AudioStream::MyPlayerBase::registerWithAudioManager() {
    220     if (!mRegistered) {
    221         init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
    222         mRegistered = true;
    223     }
    224 }
    225 
    226 void AudioStream::MyPlayerBase::unregisterWithAudioManager() {
    227     if (mRegistered) {
    228         baseDestroy();
    229         mRegistered = false;
    230     }
    231 }
    232 
    233 
    234 void AudioStream::MyPlayerBase::destroy() {
    235     unregisterWithAudioManager();
    236 }
    237