/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #include <Log.h> #include "audio/Buffer.h" #include "audio/AudioLocal.h" bool AudioLocal::prepare(AudioHardware::SamplingRate samplingRate, int gain, int /*mode*/) { LOGV("prepare"); // gain control not necessary in MobilePre as there is no control. // This means audio source itself should be adjusted to control volume if (mState == EStNone) { if (run() != android::NO_ERROR) { LOGE("AudioLocal cannot run"); // cannot run thread return false; } mState = EStCreated; } else if (mState == EStRunning) { // wrong usage. first stop! return false; } mClientCompletionWait.tryWait(); // this will reset semaphore to 0 if it is 1. mSamplingRate = samplingRate; return issueCommandAndWaitForCompletion(ECmInitialize); } bool AudioLocal::startPlaybackOrRecord(android::sp<Buffer>& buffer, int numberRepetition) { LOGV("startPlaybackOrRecord"); if (mState != EStInitialized) { LOGE("startPlaybackOrRecord while not initialized"); // wrong state return false; } mBuffer = buffer; mNumberRepetition = numberRepetition; mCurrentRepeat = 0; return issueCommandAndWaitForCompletion(ECmRun); } bool AudioLocal::waitForCompletion() { int waitTimeInMsec = mBuffer->getSamples() / (mSamplingRate/1000); waitTimeInMsec += COMMAND_WAIT_TIME_MSEC; LOGD("waitForCompletion will wait for %d", waitTimeInMsec); if (!mClientCompletionWait.timedWait(waitTimeInMsec)) { LOGE("waitForCompletion time-out"); return false; } return mCompletionResult; } void AudioLocal::stopPlaybackOrRecord() { LOGV("stopPlaybackOrRecord"); if (mState == EStRunning) { issueCommandAndWaitForCompletion(ECmStop); } if (mState != EStNone) { // thread alive requestExit(); mCurrentCommand = ECmThreadStop; mAudioThreadWait.post(); requestExitAndWait(); mState = EStNone; } } bool AudioLocal::issueCommandAndWaitForCompletion(AudioCommand command) { mCurrentCommand = command; mAudioThreadWait.post(); if (!mClientCommandWait.timedWait(COMMAND_WAIT_TIME_MSEC)) { LOGE("issueCommandAndWaitForCompletion timeout cmd %d", command); return false; } return mCommandResult; } AudioLocal::~AudioLocal() { LOGV("~AudioLocal"); } AudioLocal::AudioLocal() : mState(EStNone), mCurrentCommand(ECmNone), mClientCommandWait(0), mClientCompletionWait(0), mAudioThreadWait(0), mCompletionResult(false) { LOGV("AudioLocal"); } bool AudioLocal::threadLoop() { if (mCurrentCommand == ECmNone) { if (mState == EStRunning) { if (doPlaybackOrRecord(mBuffer)) { // check exit condition if (mBuffer->bufferHandled()) { mCurrentRepeat++; LOGV("repeat %d - %d", mCurrentRepeat, mNumberRepetition); if (mCurrentRepeat == mNumberRepetition) { LOGV("AudioLocal complete command"); mState = EStInitialized; mCompletionResult = true; mClientCompletionWait.post(); } else { mBuffer->restart(); } } } else { mState = EStInitialized; //notify error mCompletionResult = false; mClientCompletionWait.post(); } return true; } //LOGV("audio thread waiting"); mAudioThreadWait.wait(); //LOGV("audio thread waken up"); if (mCurrentCommand == ECmNone) { return true; // continue to check exit condition } } int pendingCommand = mCurrentCommand; // now there is a command switch (pendingCommand) { case ECmInitialize: mCommandResult = doPrepare(mSamplingRate, AudioHardware::SAMPLES_PER_ONE_GO); if (mCommandResult) { mState = EStInitialized; } break; case ECmRun: { mCommandResult = doPlaybackOrRecord(mBuffer); if (mCommandResult) { mState = EStRunning; } } break; case ECmStop: doStop(); mState = EStCreated; mCommandResult = true; break; case ECmThreadStop: return false; break; default: // this should not happen ASSERT(false); break; } mCurrentCommand = ECmNone; mClientCommandWait.post(); return true; }