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