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
prepare(AudioHardware::SamplingRate samplingRate,int gain,int)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("AudioLocal") != 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
startPlaybackOrRecord(android::sp<Buffer> & buffer,int numberRepetition)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
waitForCompletion()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
stopPlaybackOrRecord()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
issueCommandAndWaitForCompletion(AudioCommand command)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
~AudioLocal()94 AudioLocal::~AudioLocal()
95 {
96 LOGV("~AudioLocal");
97 }
98
AudioLocal()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
threadLoop()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