blob: 71b7afb724082eae65ac0dd9b0646b04e8f7faf0 [file] [log] [blame]
Keun young Park4bbb5d72012-03-26 18:31:29 -07001/*
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
20bool 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
41bool 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
55bool 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
67void 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
83bool 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
94AudioLocal::~AudioLocal()
95{
96 LOGV("~AudioLocal");
97}
98
99AudioLocal::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
111bool 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