Home | History | Annotate | Download | only in audio
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 #include <Log.h>
     17 #include "audio/Buffer.h"
     18 #include "audio/AudioLocal.h"
     19 
     20 bool AudioLocal::prepare(AudioHardware::SamplingRate samplingRate,  int gain, int /*mode*/)
     21 {
     22     LOGV("prepare");
     23     // gain control not necessary in MobilePre as there is no control.
     24     // This means audio source itself should be adjusted to control volume
     25     if (mState == EStNone) {
     26         if (run() != android::NO_ERROR) {
     27             LOGE("AudioLocal cannot run");
     28             // cannot run thread
     29             return false;
     30         }
     31         mState = EStCreated;
     32     } else if (mState == EStRunning) {
     33         // wrong usage. first stop!
     34         return false;
     35     }
     36     mClientCompletionWait.tryWait(); // this will reset semaphore to 0 if it is 1.
     37     mSamplingRate = samplingRate;
     38     return issueCommandAndWaitForCompletion(ECmInitialize);
     39 }
     40 
     41 bool AudioLocal::startPlaybackOrRecord(android::sp<Buffer>& buffer, int numberRepetition)
     42 {
     43     LOGV("startPlaybackOrRecord");
     44     if (mState != EStInitialized) {
     45         LOGE("startPlaybackOrRecord while not initialized");
     46         // wrong state
     47         return false;
     48     }
     49     mBuffer = buffer;
     50     mNumberRepetition = numberRepetition;
     51     mCurrentRepeat = 0;
     52     return issueCommandAndWaitForCompletion(ECmRun);
     53 }
     54 
     55 bool AudioLocal::waitForCompletion()
     56 {
     57     int waitTimeInMsec = mBuffer->getSamples() / (mSamplingRate/1000);
     58     waitTimeInMsec += COMMAND_WAIT_TIME_MSEC;
     59     LOGD("waitForCompletion will wait for %d", waitTimeInMsec);
     60     if (!mClientCompletionWait.timedWait(waitTimeInMsec)) {
     61         LOGE("waitForCompletion time-out");
     62         return false;
     63     }
     64     return mCompletionResult;
     65 }
     66 
     67 void AudioLocal::stopPlaybackOrRecord()
     68 {
     69     LOGV("stopPlaybackOrRecord");
     70     if (mState == EStRunning) {
     71         issueCommandAndWaitForCompletion(ECmStop);
     72     }
     73 
     74     if (mState != EStNone) { // thread alive
     75         requestExit();
     76         mCurrentCommand = ECmThreadStop;
     77         mAudioThreadWait.post();
     78         requestExitAndWait();
     79         mState = EStNone;
     80     }
     81 }
     82 
     83 bool AudioLocal::issueCommandAndWaitForCompletion(AudioCommand command)
     84 {
     85     mCurrentCommand = command;
     86     mAudioThreadWait.post();
     87     if (!mClientCommandWait.timedWait(COMMAND_WAIT_TIME_MSEC)) {
     88         LOGE("issueCommandAndWaitForCompletion timeout cmd %d", command);
     89         return false;
     90     }
     91     return mCommandResult;
     92 }
     93 
     94 AudioLocal::~AudioLocal()
     95 {
     96     LOGV("~AudioLocal");
     97 }
     98 
     99 AudioLocal::AudioLocal()
    100     : mState(EStNone),
    101       mCurrentCommand(ECmNone),
    102       mClientCommandWait(0),
    103       mClientCompletionWait(0),
    104       mAudioThreadWait(0),
    105       mCompletionResult(false)
    106 {
    107     LOGV("AudioLocal");
    108 }
    109 
    110 
    111 bool AudioLocal::threadLoop()
    112 {
    113     if (mCurrentCommand == ECmNone) {
    114         if (mState == EStRunning) {
    115             if (doPlaybackOrRecord(mBuffer)) {
    116                 // check exit condition
    117                 if (mBuffer->bufferHandled()) {
    118                     mCurrentRepeat++;
    119                     LOGV("repeat %d - %d", mCurrentRepeat, mNumberRepetition);
    120                     if (mCurrentRepeat == mNumberRepetition) {
    121                         LOGV("AudioLocal complete command");
    122                         mState = EStInitialized;
    123                         mCompletionResult = true;
    124                         mClientCompletionWait.post();
    125                     } else {
    126                         mBuffer->restart();
    127                     }
    128                 }
    129             } else {
    130                 mState = EStInitialized;
    131                 //notify error
    132                 mCompletionResult = false;
    133                 mClientCompletionWait.post();
    134             }
    135             return true;
    136         }
    137         //LOGV("audio thread waiting");
    138         mAudioThreadWait.wait();
    139         //LOGV("audio thread waken up");
    140         if (mCurrentCommand == ECmNone) {
    141             return true; // continue to check exit condition
    142         }
    143     }
    144 
    145     int pendingCommand = mCurrentCommand;
    146     // now there is a command
    147     switch (pendingCommand) {
    148     case ECmInitialize:
    149         mCommandResult = doPrepare(mSamplingRate, AudioHardware::SAMPLES_PER_ONE_GO);
    150         if (mCommandResult) {
    151             mState = EStInitialized;
    152         }
    153         break;
    154     case ECmRun: {
    155         mCommandResult = doPlaybackOrRecord(mBuffer);
    156         if (mCommandResult) {
    157             mState = EStRunning;
    158         }
    159     }
    160         break;
    161     case ECmStop:
    162         doStop();
    163         mState = EStCreated;
    164         mCommandResult = true;
    165         break;
    166     case ECmThreadStop:
    167         return false;
    168         break;
    169     default:
    170         // this should not happen
    171         ASSERT(false);
    172         break;
    173     }
    174 
    175     mCurrentCommand = ECmNone;
    176     mClientCommandWait.post();
    177 
    178     return true;
    179 }
    180 
    181 
    182