| 9066cfe by The Android Open Source Project at 2009-03-04 |
1 |
/* //device/include/server/AudioFlinger/AudioFlinger.cpp |
|
2 |
** |
|
3 |
** Copyright 2007, The Android Open Source Project |
|
4 |
** |
|
5 |
** Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 |
** you may not use this file except in compliance with the License. |
|
7 |
** You may obtain a copy of the License at |
|
8 |
** |
|
9 |
** http://www.apache.org/licenses/LICENSE-2.0 |
|
10 |
** |
|
11 |
** Unless required by applicable law or agreed to in writing, software |
|
12 |
** distributed under the License is distributed on an "AS IS" BASIS, |
|
13 |
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 |
** See the License for the specific language governing permissions and |
|
15 |
** limitations under the License. |
|
16 |
*/ |
|
17 |
|
|
18 |
|
|
19 |
#define LOG_TAG "AudioFlinger" |
|
20 |
//#define LOG_NDEBUG 0 |
|
21 |
|
|
22 |
#include <math.h> |
|
23 |
#include <signal.h> |
|
24 |
#include <sys/time.h> |
|
25 |
#include <sys/resource.h> |
|
26 |
|
|
27 |
#include <utils/IServiceManager.h> |
|
28 |
#include <utils/Log.h> |
|
29 |
#include <utils/Parcel.h> |
|
30 |
#include <utils/IPCThreadState.h> |
|
31 |
#include <utils/String16.h> |
|
32 |
#include <utils/threads.h> |
|
33 |
|
|
34 |
#include <cutils/properties.h> |
|
35 |
|
|
36 |
#include <media/AudioTrack.h> |
|
37 |
#include <media/AudioRecord.h> |
|
38 |
|
|
39 |
#include <private/media/AudioTrackShared.h> |
|
40 |
|
|
41 |
#include <hardware_legacy/AudioHardwareInterface.h> |
|
42 |
|
|
43 |
#include "AudioMixer.h" |
|
44 |
#include "AudioFlinger.h" |
|
45 |
|
|
46 |
#ifdef WITH_A2DP |
|
47 |
#include "A2dpAudioInterface.h" |
|
48 |
#endif |
|
49 |
|
|
50 |
// ---------------------------------------------------------------------------- |
|
51 |
// the sim build doesn't have gettid |
|
52 |
|
|
53 |
#ifndef HAVE_GETTID |
|
54 |
# define gettid getpid |
|
55 |
#endif |
|
56 |
|
|
57 |
// ---------------------------------------------------------------------------- |
|
58 |
|
|
59 |
namespace android { |
|
60 |
|
| 1059253 by The Android Open Source Project at 2009-03-19 |
61 |
static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n"; |
|
62 |
static const char* kHardwareLockedString = "Hardware lock is taken\n"; |
|
63 |
|
| 9066cfe by The Android Open Source Project at 2009-03-04 |
64 |
//static const nsecs_t kStandbyTimeInNsecs = seconds(3); |
|
65 |
static const unsigned long kBufferRecoveryInUsecs = 2000; |
|
66 |
static const unsigned long kMaxBufferRecoveryInUsecs = 20000; |
|
67 |
static const float MAX_GAIN = 4096.0f; |
|
68 |
|
|
69 |
// retry counts for buffer fill timeout |
|
70 |
// 50 * ~20msecs = 1 second |
|
71 |
static const int8_t kMaxTrackRetries = 50; |
|
72 |
static const int8_t kMaxTrackStartupRetries = 50; |
|
73 |
|
|
74 |
static const int kStartSleepTime = 30000; |
|
75 |
static const int kStopSleepTime = 30000; |
|
76 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
77 |
static const int kDumpLockRetries = 50; |
|
78 |
static const int kDumpLockSleep = 20000; |
|
79 |
|
| 9066cfe by The Android Open Source Project at 2009-03-04 |
80 |
// Maximum number of pending buffers allocated by OutputTrack::write() |
|
81 |
static const uint8_t kMaxOutputTrackBuffers = 5; |
|
82 |
|
|
83 |
|
|
84 |
#define AUDIOFLINGER_SECURITY_ENABLED 1 |
|
85 |
|
|
86 |
// ---------------------------------------------------------------------------- |
|
87 |
|
|
88 |
static bool recordingAllowed() { |
|
89 |
#ifndef HAVE_ANDROID_OS |
|
90 |
return true; |
|
91 |
#endif |
|
92 |
#if AUDIOFLINGER_SECURITY_ENABLED |
|
93 |
if (getpid() == IPCThreadState::self()->getCallingPid()) return true; |
|
94 |
bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO")); |
|
95 |
if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO"); |
|
96 |
return ok; |
|
97 |
#else |
|
98 |
if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO"))) |
|
99 |
LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest"); |
|
100 |
return true; |
|
101 |
#endif |
|
102 |
} |
|
103 |
|
|
104 |
static bool settingsAllowed() { |
|
105 |
#ifndef HAVE_ANDROID_OS |
|
106 |
return true; |
|
107 |
#endif |
|
108 |
#if AUDIOFLINGER_SECURITY_ENABLED |
|
109 |
if (getpid() == IPCThreadState::self()->getCallingPid()) return true; |
|
110 |
bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")); |
|
111 |
if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); |
|
112 |
return ok; |
|
113 |
#else |
|
114 |
if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"))) |
|
115 |
LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest"); |
|
116 |
return true; |
|
117 |
#endif |
|
118 |
} |
|
119 |
|
|
120 |
// ---------------------------------------------------------------------------- |
|
121 |
|
|
122 |
AudioFlinger::AudioFlinger() |
|
123 |
: BnAudioFlinger(), |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
124 |
mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false), |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
125 |
mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0), |
|
126 |
mRouteRestoreTime(0), mMusicMuteSaved(false) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
127 |
{ |
|
128 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
129 |
mAudioHardware = AudioHardwareInterface::create(); |
|
130 |
mHardwareStatus = AUDIO_HW_INIT; |
|
131 |
if (mAudioHardware->initCheck() == NO_ERROR) { |
|
132 |
// open 16-bit output stream for s/w mixer |
|
133 |
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; |
|
134 |
status_t status; |
|
135 |
AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); |
|
136 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
137 |
if (hwOutput) { |
|
138 |
mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE); |
|
139 |
} else { |
|
140 |
LOGE("Failed to initialize hardware output stream, status: %d", status); |
|
141 |
} |
|
142 |
|
|
143 |
#ifdef WITH_A2DP |
|
144 |
// Create A2DP interface |
|
145 |
mA2dpAudioInterface = new A2dpAudioInterface(); |
|
146 |
AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); |
|
147 |
if (a2dpOutput) { |
|
148 |
mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP); |
|
149 |
if (hwOutput) { |
|
150 |
uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate(); |
|
151 |
MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread, |
|
152 |
hwOutput->sampleRate(), |
|
153 |
AudioSystem::PCM_16_BIT, |
|
154 |
hwOutput->channelCount(), |
|
155 |
frameCount); |
|
156 |
mHardwareMixerThread->setOuputTrack(a2dpOutTrack); |
|
157 |
} |
|
158 |
} else { |
|
159 |
LOGE("Failed to initialize A2DP output stream, status: %d", status); |
|
160 |
} |
|
161 |
#endif |
|
162 |
|
|
163 |
// FIXME - this should come from settings |
|
164 |
setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL); |
|
165 |
setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL); |
|
166 |
setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL); |
|
167 |
setMode(AudioSystem::MODE_NORMAL); |
|
168 |
|
|
169 |
setMasterVolume(1.0f); |
|
170 |
setMasterMute(false); |
|
171 |
|
|
172 |
// Start record thread |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
173 |
mAudioRecordThread = new AudioRecordThread(mAudioHardware, this); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
174 |
if (mAudioRecordThread != 0) { |
|
175 |
mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO); |
|
176 |
} |
|
177 |
} else { |
|
178 |
LOGE("Couldn't even initialize the stubbed audio hardware!"); |
|
179 |
} |
|
180 |
} |
|
181 |
|
|
182 |
AudioFlinger::~AudioFlinger() |
|
183 |
{ |
|
184 |
if (mAudioRecordThread != 0) { |
|
185 |
mAudioRecordThread->exit(); |
|
186 |
mAudioRecordThread.clear(); |
|
187 |
} |
|
188 |
mHardwareMixerThread.clear(); |
|
189 |
delete mAudioHardware; |
|
190 |
// deleting mA2dpAudioInterface also deletes mA2dpOutput; |
|
191 |
#ifdef WITH_A2DP |
|
192 |
mA2dpMixerThread.clear(); |
|
193 |
delete mA2dpAudioInterface; |
|
194 |
#endif |
|
195 |
} |
|
196 |
|
|
197 |
|
|
198 |
#ifdef WITH_A2DP |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
199 |
// setA2dpEnabled_l() must be called with AudioFlinger::mLock held |
|
200 |
void AudioFlinger::setA2dpEnabled_l(bool enable) |
| 1059253 by The Android Open Source Project at 2009-03-19 |
201 |
{ |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
202 |
SortedVector < sp<MixerThread::Track> > tracks; |
|
203 |
SortedVector < wp<MixerThread::Track> > activeTracks; |
|
204 |
|
| 9066cfe by The Android Open Source Project at 2009-03-04 |
205 |
LOGV_IF(enable, "set output to A2DP\n"); |
|
206 |
LOGV_IF(!enable, "set output to hardware audio\n"); |
|
207 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
208 |
// Transfer tracks playing on MUSIC stream from one mixer to the other |
|
209 |
if (enable) { |
|
210 |
mHardwareMixerThread->getTracks_l(tracks, activeTracks); |
|
211 |
mA2dpMixerThread->putTracks_l(tracks, activeTracks); |
|
212 |
} else { |
|
213 |
mA2dpMixerThread->getTracks_l(tracks, activeTracks); |
|
214 |
mHardwareMixerThread->putTracks_l(tracks, activeTracks); |
|
215 |
} |
|
216 |
mA2dpEnabled = enable; |
|
217 |
mNotifyA2dpChange = true; |
|
218 |
mWaitWorkCV.broadcast(); |
|
219 |
} |
|
220 |
|
|
221 |
// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held |
|
222 |
void AudioFlinger::checkA2dpEnabledChange_l() |
|
223 |
{ |
|
224 |
if (mNotifyA2dpChange) { |
|
225 |
// Notify AudioSystem of the A2DP activation/deactivation |
|
226 |
size_t size = mNotificationClients.size(); |
|
227 |
for (size_t i = 0; i < size; i++) { |
|
228 |
sp<IBinder> binder = mNotificationClients.itemAt(i).promote(); |
|
229 |
if (binder != NULL) { |
|
230 |
LOGV("Notifying output change to client %p", binder.get()); |
|
231 |
sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder); |
|
232 |
client->a2dpEnabledChanged(mA2dpEnabled); |
|
233 |
} |
|
234 |
} |
|
235 |
mNotifyA2dpChange = false; |
|
236 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
237 |
} |
|
238 |
#endif // WITH_A2DP |
|
239 |
|
|
240 |
bool AudioFlinger::streamForcedToSpeaker(int streamType) |
|
241 |
{ |
|
242 |
// NOTE that streams listed here must not be routed to A2DP by default: |
|
243 |
// AudioSystem::routedToA2dpOutput(streamType) == false |
|
244 |
return (streamType == AudioSystem::RING || |
|
245 |
streamType == AudioSystem::ALARM || |
| eeea922 by Eric Laurent <> at 2009-03-26 |
246 |
streamType == AudioSystem::NOTIFICATION || |
|
247 |
streamType == AudioSystem::ENFORCED_AUDIBLE); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
248 |
} |
|
249 |
|
|
250 |
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) |
|
251 |
{ |
|
252 |
const size_t SIZE = 256; |
|
253 |
char buffer[SIZE]; |
|
254 |
String8 result; |
|
255 |
|
|
256 |
result.append("Clients:\n"); |
|
257 |
for (size_t i = 0; i < mClients.size(); ++i) { |
|
258 |
wp<Client> wClient = mClients.valueAt(i); |
|
259 |
if (wClient != 0) { |
|
260 |
sp<Client> client = wClient.promote(); |
|
261 |
if (client != 0) { |
|
262 |
snprintf(buffer, SIZE, " pid: %d\n", client->pid()); |
|
263 |
result.append(buffer); |
|
264 |
} |
|
265 |
} |
|
266 |
} |
|
267 |
write(fd, result.string(), result.size()); |
|
268 |
return NO_ERROR; |
|
269 |
} |
|
270 |
|
|
271 |
|
|
272 |
status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) |
|
273 |
{ |
|
274 |
const size_t SIZE = 256; |
|
275 |
char buffer[SIZE]; |
|
276 |
String8 result; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
277 |
int hardwareStatus = mHardwareStatus; |
|
278 |
|
|
279 |
if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) { |
|
280 |
hardwareStatus = AUDIO_HW_STANDBY; |
|
281 |
} |
|
282 |
snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
283 |
result.append(buffer); |
|
284 |
write(fd, result.string(), result.size()); |
|
285 |
return NO_ERROR; |
|
286 |
} |
|
287 |
|
|
288 |
status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args) |
|
289 |
{ |
|
290 |
const size_t SIZE = 256; |
|
291 |
char buffer[SIZE]; |
|
292 |
String8 result; |
|
293 |
snprintf(buffer, SIZE, "Permission Denial: " |
|
294 |
"can't dump AudioFlinger from pid=%d, uid=%d\n", |
|
295 |
IPCThreadState::self()->getCallingPid(), |
|
296 |
IPCThreadState::self()->getCallingUid()); |
|
297 |
result.append(buffer); |
|
298 |
write(fd, result.string(), result.size()); |
|
299 |
return NO_ERROR; |
|
300 |
} |
|
301 |
|
| 1059253 by The Android Open Source Project at 2009-03-19 |
302 |
static bool tryLock(Mutex& mutex) |
|
303 |
{ |
|
304 |
bool locked = false; |
|
305 |
for (int i = 0; i < kDumpLockRetries; ++i) { |
|
306 |
if (mutex.tryLock() == NO_ERROR) { |
|
307 |
locked = true; |
|
308 |
break; |
|
309 |
} |
|
310 |
usleep(kDumpLockSleep); |
|
311 |
} |
|
312 |
return locked; |
|
313 |
} |
|
314 |
|
| 9066cfe by The Android Open Source Project at 2009-03-04 |
315 |
status_t AudioFlinger::dump(int fd, const Vector<String16>& args) |
|
316 |
{ |
|
317 |
if (checkCallingPermission(String16("android.permission.DUMP")) == false) { |
|
318 |
dumpPermissionDenial(fd, args); |
|
319 |
} else { |
| 1059253 by The Android Open Source Project at 2009-03-19 |
320 |
// get state of hardware lock |
|
321 |
bool hardwareLocked = tryLock(mHardwareLock); |
|
322 |
if (!hardwareLocked) { |
|
323 |
String8 result(kHardwareLockedString); |
|
324 |
write(fd, result.string(), result.size()); |
|
325 |
} else { |
|
326 |
mHardwareLock.unlock(); |
|
327 |
} |
|
328 |
|
|
329 |
bool locked = tryLock(mLock); |
|
330 |
|
|
331 |
// failed to lock - AudioFlinger is probably deadlocked |
|
332 |
if (!locked) { |
|
333 |
String8 result(kDeadlockedString); |
|
334 |
write(fd, result.string(), result.size()); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
335 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
336 |
|
|
337 |
dumpClients(fd, args); |
|
338 |
dumpInternals(fd, args); |
|
339 |
mHardwareMixerThread->dump(fd, args); |
|
340 |
#ifdef WITH_A2DP |
|
341 |
mA2dpMixerThread->dump(fd, args); |
|
342 |
#endif |
|
343 |
|
|
344 |
// dump record client |
|
345 |
if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args); |
|
346 |
|
|
347 |
if (mAudioHardware) { |
|
348 |
mAudioHardware->dumpState(fd, args); |
|
349 |
} |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
350 |
if (locked) mLock.unlock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
351 |
} |
|
352 |
return NO_ERROR; |
|
353 |
} |
|
354 |
|
|
355 |
// IAudioFlinger interface |
|
356 |
|
|
357 |
|
|
358 |
sp<IAudioTrack> AudioFlinger::createTrack( |
|
359 |
pid_t pid, |
|
360 |
int streamType, |
|
361 |
uint32_t sampleRate, |
|
362 |
int format, |
|
363 |
int channelCount, |
|
364 |
int frameCount, |
|
365 |
uint32_t flags, |
|
366 |
const sp<IMemory>& sharedBuffer, |
|
367 |
status_t *status) |
|
368 |
{ |
|
369 |
sp<MixerThread::Track> track; |
|
370 |
sp<TrackHandle> trackHandle; |
|
371 |
sp<Client> client; |
|
372 |
wp<Client> wclient; |
|
373 |
status_t lStatus; |
|
374 |
|
|
375 |
if (streamType >= AudioSystem::NUM_STREAM_TYPES) { |
|
376 |
LOGE("invalid stream type"); |
|
377 |
lStatus = BAD_VALUE; |
|
378 |
goto Exit; |
|
379 |
} |
|
380 |
|
|
381 |
{ |
|
382 |
Mutex::Autolock _l(mLock); |
|
383 |
|
|
384 |
wclient = mClients.valueFor(pid); |
|
385 |
|
|
386 |
if (wclient != NULL) { |
|
387 |
client = wclient.promote(); |
|
388 |
} else { |
|
389 |
client = new Client(this, pid); |
|
390 |
mClients.add(pid, client); |
|
391 |
} |
|
392 |
#ifdef WITH_A2DP |
|
393 |
if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) { |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
394 |
track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format, |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
395 |
channelCount, frameCount, sharedBuffer, &lStatus); |
|
396 |
} else |
|
397 |
#endif |
|
398 |
{ |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
399 |
track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format, |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
400 |
channelCount, frameCount, sharedBuffer, &lStatus); |
|
401 |
} |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
402 |
} |
|
403 |
if (lStatus == NO_ERROR) { |
|
404 |
trackHandle = new TrackHandle(track); |
|
405 |
} else { |
|
406 |
track.clear(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
407 |
} |
|
408 |
|
|
409 |
Exit: |
|
410 |
if(status) { |
|
411 |
*status = lStatus; |
|
412 |
} |
|
413 |
return trackHandle; |
|
414 |
} |
|
415 |
|
|
416 |
uint32_t AudioFlinger::sampleRate(int output) const |
|
417 |
{ |
|
418 |
#ifdef WITH_A2DP |
|
419 |
if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { |
|
420 |
return mA2dpMixerThread->sampleRate(); |
|
421 |
} |
|
422 |
#endif |
|
423 |
return mHardwareMixerThread->sampleRate(); |
|
424 |
} |
|
425 |
|
|
426 |
int AudioFlinger::channelCount(int output) const |
|
427 |
{ |
|
428 |
#ifdef WITH_A2DP |
|
429 |
if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { |
|
430 |
return mA2dpMixerThread->channelCount(); |
|
431 |
} |
|
432 |
#endif |
|
433 |
return mHardwareMixerThread->channelCount(); |
|
434 |
} |
|
435 |
|
|
436 |
int AudioFlinger::format(int output) const |
|
437 |
{ |
|
438 |
#ifdef WITH_A2DP |
|
439 |
if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { |
|
440 |
return mA2dpMixerThread->format(); |
|
441 |
} |
|
442 |
#endif |
|
443 |
return mHardwareMixerThread->format(); |
|
444 |
} |
|
445 |
|
|
446 |
size_t AudioFlinger::frameCount(int output) const |
|
447 |
{ |
|
448 |
#ifdef WITH_A2DP |
|
449 |
if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { |
|
450 |
return mA2dpMixerThread->frameCount(); |
|
451 |
} |
|
452 |
#endif |
|
453 |
return mHardwareMixerThread->frameCount(); |
|
454 |
} |
|
455 |
|
|
456 |
uint32_t AudioFlinger::latency(int output) const |
|
457 |
{ |
|
458 |
#ifdef WITH_A2DP |
|
459 |
if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { |
|
460 |
return mA2dpMixerThread->latency(); |
|
461 |
} |
|
462 |
#endif |
|
463 |
return mHardwareMixerThread->latency(); |
|
464 |
} |
|
465 |
|
|
466 |
status_t AudioFlinger::setMasterVolume(float value) |
|
467 |
{ |
|
468 |
// check calling permissions |
|
469 |
if (!settingsAllowed()) { |
|
470 |
return PERMISSION_DENIED; |
|
471 |
} |
|
472 |
|
|
473 |
// when hw supports master volume, don't scale in sw mixer |
|
474 |
AutoMutex lock(mHardwareLock); |
|
475 |
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; |
|
476 |
if (mAudioHardware->setMasterVolume(value) == NO_ERROR) { |
|
477 |
value = 1.0f; |
|
478 |
} |
|
479 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
480 |
mHardwareMixerThread->setMasterVolume(value); |
|
481 |
#ifdef WITH_A2DP |
|
482 |
mA2dpMixerThread->setMasterVolume(value); |
|
483 |
#endif |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
484 |
|
| 9066cfe by The Android Open Source Project at 2009-03-04 |
485 |
return NO_ERROR; |
|
486 |
} |
|
487 |
|
|
488 |
status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) |
|
489 |
{ |
|
490 |
status_t err = NO_ERROR; |
|
491 |
|
|
492 |
// check calling permissions |
|
493 |
if (!settingsAllowed()) { |
|
494 |
return PERMISSION_DENIED; |
|
495 |
} |
|
496 |
if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) { |
|
497 |
LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask); |
|
498 |
return BAD_VALUE; |
|
499 |
} |
|
500 |
|
|
501 |
#ifdef WITH_A2DP |
|
502 |
LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid()); |
|
503 |
if (mode == AudioSystem::MODE_NORMAL && |
|
504 |
(mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) { |
|
505 |
AutoMutex lock(&mLock); |
|
506 |
|
|
507 |
bool enableA2dp = false; |
|
508 |
if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) { |
|
509 |
enableA2dp = true; |
|
510 |
} |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
511 |
if (mA2dpDisableCount > 0) { |
|
512 |
mA2dpSuppressed = enableA2dp; |
|
513 |
} else { |
|
514 |
setA2dpEnabled_l(enableA2dp); |
|
515 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
516 |
LOGV("setOutput done\n"); |
|
517 |
} |
| 1059253 by The Android Open Source Project at 2009-03-19 |
518 |
// setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when |
|
519 |
// SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only |
|
520 |
// in this case to avoid doing it several times. |
|
521 |
if (mode == AudioSystem::MODE_IN_CALL && |
|
522 |
(mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) { |
|
523 |
AutoMutex lock(&mLock); |
|
524 |
handleRouteDisablesA2dp_l(routes); |
|
525 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
526 |
#endif |
|
527 |
|
|
528 |
// do nothing if only A2DP routing is affected |
|
529 |
mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP; |
|
530 |
if (mask) { |
|
531 |
AutoMutex lock(mHardwareLock); |
|
532 |
mHardwareStatus = AUDIO_HW_GET_ROUTING; |
|
533 |
uint32_t r; |
|
534 |
err = mAudioHardware->getRouting(mode, &r); |
|
535 |
if (err == NO_ERROR) { |
|
536 |
r = (r & ~mask) | (routes & mask); |
|
537 |
if (mode == AudioSystem::MODE_NORMAL || |
|
538 |
(mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) { |
|
539 |
mSavedRoute = r; |
|
540 |
r |= mForcedRoute; |
|
541 |
LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute); |
|
542 |
} |
|
543 |
mHardwareStatus = AUDIO_HW_SET_ROUTING; |
|
544 |
err = mAudioHardware->setRouting(mode, r); |
|
545 |
} |
|
546 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
547 |
} |
|
548 |
return err; |
|
549 |
} |
|
550 |
|
|
551 |
uint32_t AudioFlinger::getRouting(int mode) const |
|
552 |
{ |
|
553 |
uint32_t routes = 0; |
|
554 |
if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) { |
|
555 |
if (mode == AudioSystem::MODE_NORMAL || |
|
556 |
(mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) { |
|
557 |
routes = mSavedRoute; |
|
558 |
} else { |
|
559 |
mHardwareStatus = AUDIO_HW_GET_ROUTING; |
|
560 |
mAudioHardware->getRouting(mode, &routes); |
|
561 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
562 |
} |
|
563 |
} else { |
|
564 |
LOGW("Illegal value: getRouting(%d)", mode); |
|
565 |
} |
|
566 |
return routes; |
|
567 |
} |
|
568 |
|
|
569 |
status_t AudioFlinger::setMode(int mode) |
|
570 |
{ |
|
571 |
// check calling permissions |
|
572 |
if (!settingsAllowed()) { |
|
573 |
return PERMISSION_DENIED; |
|
574 |
} |
|
575 |
if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) { |
|
576 |
LOGW("Illegal value: setMode(%d)", mode); |
|
577 |
return BAD_VALUE; |
|
578 |
} |
|
579 |
|
|
580 |
AutoMutex lock(mHardwareLock); |
|
581 |
mHardwareStatus = AUDIO_HW_SET_MODE; |
|
582 |
status_t ret = mAudioHardware->setMode(mode); |
|
583 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
584 |
return ret; |
|
585 |
} |
|
586 |
|
|
587 |
int AudioFlinger::getMode() const |
|
588 |
{ |
|
589 |
int mode = AudioSystem::MODE_INVALID; |
|
590 |
mHardwareStatus = AUDIO_HW_SET_MODE; |
|
591 |
mAudioHardware->getMode(&mode); |
|
592 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
593 |
return mode; |
|
594 |
} |
|
595 |
|
|
596 |
status_t AudioFlinger::setMicMute(bool state) |
|
597 |
{ |
|
598 |
// check calling permissions |
|
599 |
if (!settingsAllowed()) { |
|
600 |
return PERMISSION_DENIED; |
|
601 |
} |
|
602 |
|
|
603 |
AutoMutex lock(mHardwareLock); |
|
604 |
mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; |
|
605 |
status_t ret = mAudioHardware->setMicMute(state); |
|
606 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
607 |
return ret; |
|
608 |
} |
|
609 |
|
|
610 |
bool AudioFlinger::getMicMute() const |
|
611 |
{ |
|
612 |
bool state = AudioSystem::MODE_INVALID; |
|
613 |
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE; |
|
614 |
mAudioHardware->getMicMute(&state); |
|
615 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
616 |
return state; |
|
617 |
} |
|
618 |
|
|
619 |
status_t AudioFlinger::setMasterMute(bool muted) |
|
620 |
{ |
|
621 |
// check calling permissions |
|
622 |
if (!settingsAllowed()) { |
|
623 |
return PERMISSION_DENIED; |
|
624 |
} |
|
625 |
mHardwareMixerThread->setMasterMute(muted); |
|
626 |
#ifdef WITH_A2DP |
|
627 |
mA2dpMixerThread->setMasterMute(muted); |
|
628 |
#endif |
|
629 |
return NO_ERROR; |
|
630 |
} |
|
631 |
|
|
632 |
float AudioFlinger::masterVolume() const |
|
633 |
{ |
|
634 |
return mHardwareMixerThread->masterVolume(); |
|
635 |
} |
|
636 |
|
|
637 |
bool AudioFlinger::masterMute() const |
|
638 |
{ |
|
639 |
return mHardwareMixerThread->masterMute(); |
|
640 |
} |
|
641 |
|
|
642 |
status_t AudioFlinger::setStreamVolume(int stream, float value) |
|
643 |
{ |
|
644 |
// check calling permissions |
|
645 |
if (!settingsAllowed()) { |
|
646 |
return PERMISSION_DENIED; |
|
647 |
} |
|
648 |
|
| eeea922 by Eric Laurent <> at 2009-03-26 |
649 |
if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES || |
|
650 |
uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) { |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
651 |
return BAD_VALUE; |
|
652 |
} |
|
653 |
|
|
654 |
mHardwareMixerThread->setStreamVolume(stream, value); |
|
655 |
#ifdef WITH_A2DP |
|
656 |
mA2dpMixerThread->setStreamVolume(stream, value); |
|
657 |
#endif |
|
658 |
|
|
659 |
status_t ret = NO_ERROR; |
|
660 |
if (stream == AudioSystem::VOICE_CALL || |
|
661 |
stream == AudioSystem::BLUETOOTH_SCO) { |
|
662 |
|
|
663 |
if (stream == AudioSystem::VOICE_CALL) { |
|
664 |
value = (float)AudioSystem::logToLinear(value)/100.0f; |
|
665 |
} else { // (type == AudioSystem::BLUETOOTH_SCO) |
|
666 |
value = 1.0f; |
|
667 |
} |
|
668 |
|
|
669 |
AutoMutex lock(mHardwareLock); |
|
670 |
mHardwareStatus = AUDIO_SET_VOICE_VOLUME; |
|
671 |
ret = mAudioHardware->setVoiceVolume(value); |
|
672 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
673 |
} |
|
674 |
|
|
675 |
return ret; |
|
676 |
} |
|
677 |
|
|
678 |
status_t AudioFlinger::setStreamMute(int stream, bool muted) |
|
679 |
{ |
|
680 |
// check calling permissions |
|
681 |
if (!settingsAllowed()) { |
|
682 |
return PERMISSION_DENIED; |
|
683 |
} |
|
684 |
|
| eeea922 by Eric Laurent <> at 2009-03-26 |
685 |
if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES || |
|
686 |
uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) { |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
687 |
return BAD_VALUE; |
|
688 |
} |
| 1059253 by The Android Open Source Project at 2009-03-19 |
689 |
|
| 9066cfe by The Android Open Source Project at 2009-03-04 |
690 |
#ifdef WITH_A2DP |
|
691 |
mA2dpMixerThread->setStreamMute(stream, muted); |
|
692 |
#endif |
|
693 |
if (stream == AudioSystem::MUSIC) |
|
694 |
{ |
|
695 |
AutoMutex lock(&mHardwareLock); |
|
696 |
if (mForcedRoute != 0) |
|
697 |
mMusicMuteSaved = muted; |
|
698 |
else |
|
699 |
mHardwareMixerThread->setStreamMute(stream, muted); |
|
700 |
} else { |
|
701 |
mHardwareMixerThread->setStreamMute(stream, muted); |
|
702 |
} |
|
703 |
|
|
704 |
return NO_ERROR; |
|
705 |
} |
|
706 |
|
|
707 |
float AudioFlinger::streamVolume(int stream) const |
|
708 |
{ |
|
709 |
if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { |
|
710 |
return 0.0f; |
|
711 |
} |
|
712 |
return mHardwareMixerThread->streamVolume(stream); |
|
713 |
} |
|
714 |
|
|
715 |
bool AudioFlinger::streamMute(int stream) const |
|
716 |
{ |
|
717 |
if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { |
|
718 |
return true; |
|
719 |
} |
|
720 |
|
|
721 |
if (stream == AudioSystem::MUSIC && mForcedRoute != 0) |
|
722 |
{ |
|
723 |
return mMusicMuteSaved; |
|
724 |
} |
|
725 |
return mHardwareMixerThread->streamMute(stream); |
|
726 |
} |
|
727 |
|
|
728 |
bool AudioFlinger::isMusicActive() const |
|
729 |
{ |
|
730 |
#ifdef WITH_A2DP |
|
731 |
if (isA2dpEnabled()) { |
|
732 |
return mA2dpMixerThread->isMusicActive(); |
|
733 |
} |
|
734 |
#endif |
|
735 |
return mHardwareMixerThread->isMusicActive(); |
|
736 |
} |
|
737 |
|
|
738 |
status_t AudioFlinger::setParameter(const char* key, const char* value) |
|
739 |
{ |
|
740 |
status_t result, result2; |
|
741 |
AutoMutex lock(mHardwareLock); |
|
742 |
mHardwareStatus = AUDIO_SET_PARAMETER; |
|
743 |
|
|
744 |
LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid()); |
|
745 |
result = mAudioHardware->setParameter(key, value); |
|
746 |
if (mA2dpAudioInterface) { |
|
747 |
result2 = mA2dpAudioInterface->setParameter(key, value); |
|
748 |
if (result2) |
|
749 |
result = result2; |
|
750 |
} |
|
751 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
752 |
return result; |
|
753 |
} |
|
754 |
|
|
755 |
size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) |
|
756 |
{ |
|
757 |
return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); |
|
758 |
} |
|
759 |
|
|
760 |
void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) |
|
761 |
{ |
|
762 |
|
|
763 |
LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid()); |
|
764 |
Mutex::Autolock _l(mLock); |
|
765 |
|
|
766 |
sp<IBinder> binder = client->asBinder(); |
|
767 |
if (mNotificationClients.indexOf(binder) < 0) { |
|
768 |
LOGV("Adding notification client %p", binder.get()); |
|
769 |
binder->linkToDeath(this); |
|
770 |
mNotificationClients.add(binder); |
|
771 |
client->a2dpEnabledChanged(isA2dpEnabled()); |
|
772 |
} |
|
773 |
} |
|
774 |
|
|
775 |
void AudioFlinger::binderDied(const wp<IBinder>& who) { |
|
776 |
|
|
777 |
LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); |
|
778 |
Mutex::Autolock _l(mLock); |
|
779 |
|
|
780 |
IBinder *binder = who.unsafe_get(); |
|
781 |
|
|
782 |
if (binder != NULL) { |
|
783 |
int index = mNotificationClients.indexOf(binder); |
|
784 |
if (index >= 0) { |
|
785 |
LOGV("Removing notification client %p", binder); |
|
786 |
mNotificationClients.removeAt(index); |
|
787 |
} |
|
788 |
} |
|
789 |
} |
|
790 |
|
|
791 |
void AudioFlinger::removeClient(pid_t pid) |
|
792 |
{ |
|
793 |
LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid()); |
|
794 |
Mutex::Autolock _l(mLock); |
|
795 |
mClients.removeItem(pid); |
|
796 |
} |
|
797 |
|
|
798 |
bool AudioFlinger::isA2dpEnabled() const |
|
799 |
{ |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
800 |
return mA2dpEnabled; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
801 |
} |
|
802 |
|
|
803 |
void AudioFlinger::handleForcedSpeakerRoute(int command) |
|
804 |
{ |
|
805 |
switch(command) { |
|
806 |
case ACTIVE_TRACK_ADDED: |
|
807 |
{ |
|
808 |
AutoMutex lock(mHardwareLock); |
|
809 |
if (mForcedSpeakerCount++ == 0) { |
|
810 |
mRouteRestoreTime = 0; |
|
811 |
mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC); |
|
812 |
if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) { |
|
813 |
LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER); |
|
814 |
mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true); |
|
815 |
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; |
|
816 |
mAudioHardware->setMasterVolume(0); |
|
817 |
usleep(mHardwareMixerThread->latency()*1000); |
|
818 |
mHardwareStatus = AUDIO_HW_SET_ROUTING; |
|
819 |
mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER); |
|
820 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
821 |
// delay track start so that audio hardware has time to siwtch routes |
|
822 |
usleep(kStartSleepTime); |
|
823 |
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; |
|
824 |
mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume()); |
|
825 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
826 |
} |
|
827 |
mForcedRoute = AudioSystem::ROUTE_SPEAKER; |
|
828 |
} |
|
829 |
LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount); |
|
830 |
} |
|
831 |
break; |
|
832 |
case ACTIVE_TRACK_REMOVED: |
|
833 |
{ |
|
834 |
AutoMutex lock(mHardwareLock); |
|
835 |
if (mForcedSpeakerCount > 0){ |
|
836 |
if (--mForcedSpeakerCount == 0) { |
|
837 |
mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000); |
|
838 |
} |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
839 |
LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
840 |
} else { |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
841 |
LOGE("mForcedSpeakerCount is already zero"); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
842 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
843 |
} |
|
844 |
break; |
|
845 |
case CHECK_ROUTE_RESTORE_TIME: |
|
846 |
case FORCE_ROUTE_RESTORE: |
|
847 |
if (mRouteRestoreTime) { |
|
848 |
AutoMutex lock(mHardwareLock); |
|
849 |
if (mRouteRestoreTime && |
|
850 |
(systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) { |
|
851 |
mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved); |
|
852 |
mForcedRoute = 0; |
|
853 |
if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) { |
|
854 |
mHardwareStatus = AUDIO_HW_SET_ROUTING; |
|
855 |
mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute); |
|
856 |
mHardwareStatus = AUDIO_HW_IDLE; |
|
857 |
LOGV("Route forced to Speaker OFF %08x", mSavedRoute); |
|
858 |
} |
|
859 |
mRouteRestoreTime = 0; |
|
860 |
} |
|
861 |
} |
|
862 |
break; |
|
863 |
} |
|
864 |
} |
|
865 |
|
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
866 |
#ifdef WITH_A2DP |
| 1059253 by The Android Open Source Project at 2009-03-19 |
867 |
// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held |
|
868 |
void AudioFlinger::handleRouteDisablesA2dp_l(int routes) |
|
869 |
{ |
|
870 |
if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) { |
|
871 |
if (mA2dpDisableCount++ == 0) { |
|
872 |
if (mA2dpEnabled) { |
|
873 |
setA2dpEnabled_l(false); |
|
874 |
mA2dpSuppressed = true; |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
875 |
} |
|
876 |
} |
| 1059253 by The Android Open Source Project at 2009-03-19 |
877 |
LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount); |
|
878 |
} else { |
|
879 |
if (mA2dpDisableCount > 0) { |
|
880 |
if (--mA2dpDisableCount == 0) { |
|
881 |
if (mA2dpSuppressed) { |
|
882 |
setA2dpEnabled_l(true); |
|
883 |
mA2dpSuppressed = false; |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
884 |
} |
|
885 |
} |
| 1059253 by The Android Open Source Project at 2009-03-19 |
886 |
LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount); |
|
887 |
} else { |
|
888 |
LOGE("mA2dpDisableCount is already zero"); |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
889 |
} |
|
890 |
} |
|
891 |
} |
|
892 |
#endif |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
893 |
|
|
894 |
// ---------------------------------------------------------------------------- |
|
895 |
|
|
896 |
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType) |
|
897 |
: Thread(false), |
|
898 |
mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType), |
|
899 |
mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0), |
|
900 |
mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false), |
|
901 |
mInWrite(false) |
|
902 |
{ |
|
903 |
mSampleRate = output->sampleRate(); |
|
904 |
mChannelCount = output->channelCount(); |
|
905 |
|
|
906 |
// FIXME - Current mixer implementation only supports stereo output |
|
907 |
if (mChannelCount == 1) { |
|
908 |
LOGE("Invalid audio hardware channel count"); |
|
909 |
} |
|
910 |
|
|
911 |
mFormat = output->format(); |
|
912 |
mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t); |
|
913 |
mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate()); |
|
914 |
|
|
915 |
// FIXME - Current mixer implementation only supports stereo output: Always |
|
916 |
// Allocate a stereo buffer even if HW output is mono. |
|
917 |
mMixBuffer = new int16_t[mFrameCount * 2]; |
|
918 |
memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); |
|
919 |
} |
|
920 |
|
|
921 |
AudioFlinger::MixerThread::~MixerThread() |
|
922 |
{ |
|
923 |
delete [] mMixBuffer; |
|
924 |
delete mAudioMixer; |
|
925 |
} |
|
926 |
|
|
927 |
status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args) |
|
928 |
{ |
|
929 |
dumpInternals(fd, args); |
|
930 |
dumpTracks(fd, args); |
|
931 |
return NO_ERROR; |
|
932 |
} |
|
933 |
|
|
934 |
status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args) |
|
935 |
{ |
|
936 |
const size_t SIZE = 256; |
|
937 |
char buffer[SIZE]; |
|
938 |
String8 result; |
|
939 |
|
|
940 |
snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType); |
|
941 |
result.append(buffer); |
|
942 |
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n"); |
|
943 |
for (size_t i = 0; i < mTracks.size(); ++i) { |
| 08defa0 by Eric Laurent <> at 2009-03-31 |
944 |
sp<Track> track = mTracks[i]; |
|
945 |
if (track != 0) { |
|
946 |
track->dump(buffer, SIZE); |
|
947 |
result.append(buffer); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
948 |
} |
|
949 |
} |
|
950 |
|
|
951 |
snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType); |
|
952 |
result.append(buffer); |
|
953 |
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n"); |
|
954 |
for (size_t i = 0; i < mActiveTracks.size(); ++i) { |
| 08defa0 by Eric Laurent <> at 2009-03-31 |
955 |
wp<Track> wTrack = mActiveTracks[i]; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
956 |
if (wTrack != 0) { |
|
957 |
sp<Track> track = wTrack.promote(); |
|
958 |
if (track != 0) { |
|
959 |
track->dump(buffer, SIZE); |
|
960 |
result.append(buffer); |
|
961 |
} |
|
962 |
} |
|
963 |
} |
|
964 |
write(fd, result.string(), result.size()); |
|
965 |
return NO_ERROR; |
|
966 |
} |
|
967 |
|
|
968 |
status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) |
|
969 |
{ |
|
970 |
const size_t SIZE = 256; |
|
971 |
char buffer[SIZE]; |
|
972 |
String8 result; |
|
973 |
|
|
974 |
snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType); |
|
975 |
result.append(buffer); |
|
976 |
snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames()); |
|
977 |
result.append(buffer); |
|
978 |
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); |
|
979 |
result.append(buffer); |
|
980 |
snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites); |
|
981 |
result.append(buffer); |
|
982 |
snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites); |
|
983 |
result.append(buffer); |
|
984 |
snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite); |
|
985 |
result.append(buffer); |
|
986 |
snprintf(buffer, SIZE, "standby: %d\n", mStandby); |
|
987 |
result.append(buffer); |
|
988 |
write(fd, result.string(), result.size()); |
|
989 |
return NO_ERROR; |
|
990 |
} |
|
991 |
|
|
992 |
// Thread virtuals |
|
993 |
bool AudioFlinger::MixerThread::threadLoop() |
|
994 |
{ |
|
995 |
unsigned long sleepTime = kBufferRecoveryInUsecs; |
|
996 |
int16_t* curBuf = mMixBuffer; |
|
997 |
Vector< sp<Track> > tracksToRemove; |
|
998 |
size_t enabledTracks = 0; |
|
999 |
nsecs_t standbyTime = systemTime(); |
|
1000 |
size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t); |
|
1001 |
nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2; |
|
1002 |
|
|
1003 |
#ifdef WITH_A2DP |
|
1004 |
bool outputTrackActive = false; |
|
1005 |
#endif |
|
1006 |
|
|
1007 |
do { |
|
1008 |
enabledTracks = 0; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1009 |
{ // scope for the AudioFlinger::mLock |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1010 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1011 |
Mutex::Autolock _l(mAudioFlinger->mLock); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1012 |
|
|
1013 |
#ifdef WITH_A2DP |
|
1014 |
if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) { |
|
1015 |
if (outputTrackActive) { |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1016 |
mAudioFlinger->mLock.unlock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1017 |
mOutputTrack->stop(); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1018 |
mAudioFlinger->mLock.lock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1019 |
outputTrackActive = false; |
|
1020 |
} |
|
1021 |
} |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1022 |
mAudioFlinger->checkA2dpEnabledChange_l(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1023 |
#endif |
|
1024 |
|
|
1025 |
const SortedVector< wp<Track> >& activeTracks = mActiveTracks; |
|
1026 |
|
|
1027 |
// put audio hardware into standby after short delay |
|
1028 |
if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) { |
|
1029 |
// wait until we have something to do... |
|
1030 |
LOGV("Audio hardware entering standby, output %d\n", mOutputType); |
|
1031 |
if (!mStandby) { |
|
1032 |
mOutput->standby(); |
|
1033 |
mStandby = true; |
|
1034 |
} |
|
1035 |
|
|
1036 |
#ifdef WITH_A2DP |
|
1037 |
if (outputTrackActive) { |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1038 |
mAudioFlinger->mLock.unlock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1039 |
mOutputTrack->stop(); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1040 |
mAudioFlinger->mLock.lock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1041 |
outputTrackActive = false; |
|
1042 |
} |
|
1043 |
#endif |
|
1044 |
if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { |
|
1045 |
mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE); |
|
1046 |
} |
|
1047 |
// we're about to wait, flush the binder command buffer |
|
1048 |
IPCThreadState::self()->flushCommands(); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1049 |
mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1050 |
LOGV("Audio hardware exiting standby, output %d\n", mOutputType); |
|
1051 |
|
|
1052 |
if (mMasterMute == false) { |
|
1053 |
char value[PROPERTY_VALUE_MAX]; |
|
1054 |
property_get("ro.audio.silent", value, "0"); |
|
1055 |
if (atoi(value)) { |
|
1056 |
LOGD("Silence is golden"); |
|
1057 |
setMasterMute(true); |
|
1058 |
} |
|
1059 |
} |
|
1060 |
|
|
1061 |
standbyTime = systemTime() + kStandbyTimeInNsecs; |
|
1062 |
continue; |
|
1063 |
} |
|
1064 |
|
|
1065 |
// Forced route to speaker is handled by hardware mixer thread |
|
1066 |
if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { |
|
1067 |
mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME); |
|
1068 |
} |
|
1069 |
|
|
1070 |
// find out which tracks need to be processed |
|
1071 |
size_t count = activeTracks.size(); |
|
1072 |
for (size_t i=0 ; i<count ; i++) { |
|
1073 |
sp<Track> t = activeTracks[i].promote(); |
|
1074 |
if (t == 0) continue; |
|
1075 |
|
|
1076 |
Track* const track = t.get(); |
|
1077 |
audio_track_cblk_t* cblk = track->cblk(); |
|
1078 |
|
|
1079 |
// The first time a track is added we wait |
|
1080 |
// for all its buffers to be filled before processing it |
|
1081 |
mAudioMixer->setActiveTrack(track->name()); |
|
1082 |
if (cblk->framesReady() && (track->isReady() || track->isStopped()) && |
|
1083 |
!track->isPaused()) |
|
1084 |
{ |
|
1085 |
//LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); |
|
1086 |
|
|
1087 |
// compute volume for this track |
|
1088 |
int16_t left, right; |
|
1089 |
if (track->isMuted() || mMasterMute || track->isPausing()) { |
|
1090 |
left = right = 0; |
|
1091 |
if (track->isPausing()) { |
|
1092 |
LOGV("paused(%d)", track->name()); |
|
1093 |
track->setPaused(); |
|
1094 |
} |
|
1095 |
} else { |
|
1096 |
float typeVolume = mStreamTypes[track->type()].volume; |
|
1097 |
float v = mMasterVolume * typeVolume; |
|
1098 |
float v_clamped = v * cblk->volume[0]; |
|
1099 |
if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; |
|
1100 |
left = int16_t(v_clamped); |
|
1101 |
v_clamped = v * cblk->volume[1]; |
|
1102 |
if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; |
|
1103 |
right = int16_t(v_clamped); |
|
1104 |
} |
|
1105 |
|
|
1106 |
// XXX: these things DON'T need to be done each time |
|
1107 |
mAudioMixer->setBufferProvider(track); |
|
1108 |
mAudioMixer->enable(AudioMixer::MIXING); |
|
1109 |
|
|
1110 |
int param; |
|
1111 |
if ( track->mFillingUpStatus == Track::FS_FILLED) { |
|
1112 |
// no ramp for the first volume setting |
|
1113 |
track->mFillingUpStatus = Track::FS_ACTIVE; |
|
1114 |
if (track->mState == TrackBase::RESUMING) { |
|
1115 |
track->mState = TrackBase::ACTIVE; |
|
1116 |
param = AudioMixer::RAMP_VOLUME; |
|
1117 |
} else { |
|
1118 |
param = AudioMixer::VOLUME; |
|
1119 |
} |
|
1120 |
} else { |
|
1121 |
param = AudioMixer::RAMP_VOLUME; |
|
1122 |
} |
|
1123 |
mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); |
|
1124 |
mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right); |
|
1125 |
mAudioMixer->setParameter( |
|
1126 |
AudioMixer::TRACK, |
|
1127 |
AudioMixer::FORMAT, track->format()); |
|
1128 |
mAudioMixer->setParameter( |
|
1129 |
AudioMixer::TRACK, |
|
1130 |
AudioMixer::CHANNEL_COUNT, track->channelCount()); |
|
1131 |
mAudioMixer->setParameter( |
|
1132 |
AudioMixer::RESAMPLE, |
|
1133 |
AudioMixer::SAMPLE_RATE, |
|
1134 |
int(cblk->sampleRate)); |
|
1135 |
|
|
1136 |
// reset retry count |
|
1137 |
track->mRetryCount = kMaxTrackRetries; |
|
1138 |
enabledTracks++; |
|
1139 |
} else { |
|
1140 |
//LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server); |
|
1141 |
if (track->isStopped()) { |
|
1142 |
track->reset(); |
|
1143 |
} |
|
1144 |
if (track->isTerminated() || track->isStopped() || track->isPaused()) { |
|
1145 |
// We have consumed all the buffers of this track. |
|
1146 |
// Remove it from the list of active tracks. |
|
1147 |
LOGV("remove(%d) from active list", track->name()); |
|
1148 |
tracksToRemove.add(track); |
|
1149 |
} else { |
|
1150 |
// No buffers for this track. Give it a few chances to |
|
1151 |
// fill a buffer, then remove it from active list. |
|
1152 |
if (--(track->mRetryCount) <= 0) { |
|
1153 |
LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name()); |
|
1154 |
tracksToRemove.add(track); |
|
1155 |
} |
|
1156 |
} |
|
1157 |
// LOGV("disable(%d)", track->name()); |
|
1158 |
mAudioMixer->disable(AudioMixer::MIXING); |
|
1159 |
} |
|
1160 |
} |
|
1161 |
|
|
1162 |
// remove all the tracks that need to be... |
|
1163 |
count = tracksToRemove.size(); |
|
1164 |
if (UNLIKELY(count)) { |
|
1165 |
for (size_t i=0 ; i<count ; i++) { |
|
1166 |
const sp<Track>& track = tracksToRemove[i]; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1167 |
removeActiveTrack_l(track); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1168 |
if (track->isTerminated()) { |
|
1169 |
mTracks.remove(track); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1170 |
deleteTrackName_l(track->mName); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1171 |
} |
|
1172 |
} |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1173 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1174 |
} |
|
1175 |
|
|
1176 |
if (LIKELY(enabledTracks)) { |
|
1177 |
// mix buffers... |
|
1178 |
mAudioMixer->process(curBuf); |
|
1179 |
|
|
1180 |
#ifdef WITH_A2DP |
|
1181 |
if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) { |
|
1182 |
if (!outputTrackActive) { |
|
1183 |
LOGV("starting output track in mixer for output %d", mOutputType); |
|
1184 |
mOutputTrack->start(); |
|
1185 |
outputTrackActive = true; |
|
1186 |
} |
|
1187 |
mOutputTrack->write(curBuf, mFrameCount); |
|
1188 |
} |
|
1189 |
#endif |
|
1190 |
|
|
1191 |
// output audio to hardware |
|
1192 |
mLastWriteTime = systemTime(); |
|
1193 |
mInWrite = true; |
|
1194 |
mOutput->write(curBuf, mixBufferSize); |
|
1195 |
mNumWrites++; |
|
1196 |
mInWrite = false; |
|
1197 |
mStandby = false; |
|
1198 |
nsecs_t temp = systemTime(); |
|
1199 |
standbyTime = temp + kStandbyTimeInNsecs; |
|
1200 |
nsecs_t delta = temp - mLastWriteTime; |
|
1201 |
if (delta > maxPeriod) { |
|
1202 |
LOGW("write blocked for %llu msecs", ns2ms(delta)); |
|
1203 |
mNumDelayedWrites++; |
|
1204 |
} |
|
1205 |
sleepTime = kBufferRecoveryInUsecs; |
|
1206 |
} else { |
|
1207 |
#ifdef WITH_A2DP |
|
1208 |
if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) { |
|
1209 |
if (outputTrackActive) { |
|
1210 |
mOutputTrack->write(curBuf, 0); |
|
1211 |
if (mOutputTrack->bufferQueueEmpty()) { |
|
1212 |
mOutputTrack->stop(); |
|
1213 |
outputTrackActive = false; |
|
1214 |
} else { |
|
1215 |
standbyTime = systemTime() + kStandbyTimeInNsecs; |
|
1216 |
} |
|
1217 |
} |
|
1218 |
} |
|
1219 |
#endif |
|
1220 |
// There was nothing to mix this round, which means all |
|
1221 |
// active tracks were late. Sleep a little bit to give |
|
1222 |
// them another chance. If we're too late, the audio |
|
1223 |
// hardware will zero-fill for us. |
|
1224 |
//LOGV("no buffers - usleep(%lu)", sleepTime); |
|
1225 |
usleep(sleepTime); |
|
1226 |
if (sleepTime < kMaxBufferRecoveryInUsecs) { |
|
1227 |
sleepTime += kBufferRecoveryInUsecs; |
|
1228 |
} |
|
1229 |
} |
|
1230 |
|
|
1231 |
// finally let go of all our tracks, without the lock held |
|
1232 |
// since we can't guarantee the destructors won't acquire that |
|
1233 |
// same lock. |
|
1234 |
tracksToRemove.clear(); |
|
1235 |
} while (true); |
|
1236 |
|
|
1237 |
return false; |
|
1238 |
} |
|
1239 |
|
|
1240 |
status_t AudioFlinger::MixerThread::readyToRun() |
|
1241 |
{ |
|
1242 |
if (mSampleRate == 0) { |
|
1243 |
LOGE("No working audio driver found."); |
|
1244 |
return NO_INIT; |
|
1245 |
} |
|
1246 |
LOGI("AudioFlinger's thread ready to run for output %d", mOutputType); |
|
1247 |
return NO_ERROR; |
|
1248 |
} |
|
1249 |
|
|
1250 |
void AudioFlinger::MixerThread::onFirstRef() |
|
1251 |
{ |
|
1252 |
const size_t SIZE = 256; |
|
1253 |
char buffer[SIZE]; |
|
1254 |
|
|
1255 |
snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType); |
|
1256 |
|
|
1257 |
run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); |
|
1258 |
} |
|
1259 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1260 |
// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held |
|
1261 |
sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l( |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1262 |
const sp<AudioFlinger::Client>& client, |
|
1263 |
int streamType, |
|
1264 |
uint32_t sampleRate, |
|
1265 |
int format, |
|
1266 |
int channelCount, |
|
1267 |
int frameCount, |
|
1268 |
const sp<IMemory>& sharedBuffer, |
|
1269 |
status_t *status) |
|
1270 |
{ |
|
1271 |
sp<Track> track; |
|
1272 |
status_t lStatus; |
|
1273 |
|
|
1274 |
// Resampler implementation limits input sampling rate to 2 x output sampling rate. |
|
1275 |
if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) { |
|
1276 |
LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate); |
|
1277 |
lStatus = BAD_VALUE; |
|
1278 |
goto Exit; |
|
1279 |
} |
|
1280 |
|
|
1281 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1282 |
if (mSampleRate == 0) { |
|
1283 |
LOGE("Audio driver not initialized."); |
|
1284 |
lStatus = NO_INIT; |
|
1285 |
goto Exit; |
|
1286 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1287 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1288 |
track = new Track(this, client, streamType, sampleRate, format, |
|
1289 |
channelCount, frameCount, sharedBuffer); |
|
1290 |
if (track->getCblk() == NULL) { |
|
1291 |
lStatus = NO_MEMORY; |
|
1292 |
goto Exit; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1293 |
} |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1294 |
mTracks.add(track); |
|
1295 |
lStatus = NO_ERROR; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1296 |
|
|
1297 |
Exit: |
|
1298 |
if(status) { |
|
1299 |
*status = lStatus; |
|
1300 |
} |
|
1301 |
return track; |
|
1302 |
} |
|
1303 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1304 |
// getTracks_l() must be called with AudioFlinger::mLock held |
|
1305 |
void AudioFlinger::MixerThread::getTracks_l( |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1306 |
SortedVector < sp<Track> >& tracks, |
|
1307 |
SortedVector < wp<Track> >& activeTracks) |
|
1308 |
{ |
|
1309 |
size_t size = mTracks.size(); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1310 |
LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size()); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1311 |
for (size_t i = 0; i < size; i++) { |
|
1312 |
sp<Track> t = mTracks[i]; |
|
1313 |
if (AudioSystem::routedToA2dpOutput(t->mStreamType)) { |
|
1314 |
tracks.add(t); |
|
1315 |
int j = mActiveTracks.indexOf(t); |
|
1316 |
if (j >= 0) { |
|
1317 |
t = mActiveTracks[j].promote(); |
|
1318 |
if (t != NULL) { |
|
1319 |
activeTracks.add(t); |
|
1320 |
} |
|
1321 |
} |
|
1322 |
} |
|
1323 |
} |
|
1324 |
|
|
1325 |
size = activeTracks.size(); |
|
1326 |
for (size_t i = 0; i < size; i++) { |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1327 |
removeActiveTrack_l(activeTracks[i]); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1328 |
} |
|
1329 |
|
|
1330 |
size = tracks.size(); |
|
1331 |
for (size_t i = 0; i < size; i++) { |
|
1332 |
sp<Track> t = tracks[i]; |
|
1333 |
mTracks.remove(t); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1334 |
deleteTrackName_l(t->name()); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1335 |
} |
|
1336 |
} |
|
1337 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1338 |
// putTracks_l() must be called with AudioFlinger::mLock held |
|
1339 |
void AudioFlinger::MixerThread::putTracks_l( |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1340 |
SortedVector < sp<Track> >& tracks, |
|
1341 |
SortedVector < wp<Track> >& activeTracks) |
|
1342 |
{ |
|
1343 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1344 |
LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size()); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1345 |
|
|
1346 |
size_t size = tracks.size(); |
|
1347 |
for (size_t i = 0; i < size ; i++) { |
|
1348 |
sp<Track> t = tracks[i]; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1349 |
int name = getTrackName_l(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1350 |
|
|
1351 |
if (name < 0) return; |
|
1352 |
|
|
1353 |
t->mName = name; |
|
1354 |
t->mMixerThread = this; |
|
1355 |
mTracks.add(t); |
|
1356 |
|
|
1357 |
int j = activeTracks.indexOf(t); |
|
1358 |
if (j >= 0) { |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1359 |
addActiveTrack_l(t); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1360 |
} |
|
1361 |
} |
|
1362 |
} |
|
1363 |
|
|
1364 |
uint32_t AudioFlinger::MixerThread::sampleRate() const |
|
1365 |
{ |
|
1366 |
return mSampleRate; |
|
1367 |
} |
|
1368 |
|
|
1369 |
int AudioFlinger::MixerThread::channelCount() const |
|
1370 |
{ |
|
1371 |
return mChannelCount; |
|
1372 |
} |
|
1373 |
|
|
1374 |
int AudioFlinger::MixerThread::format() const |
|
1375 |
{ |
|
1376 |
return mFormat; |
|
1377 |
} |
|
1378 |
|
|
1379 |
size_t AudioFlinger::MixerThread::frameCount() const |
|
1380 |
{ |
|
1381 |
return mFrameCount; |
|
1382 |
} |
|
1383 |
|
|
1384 |
uint32_t AudioFlinger::MixerThread::latency() const |
|
1385 |
{ |
|
1386 |
if (mOutput) { |
|
1387 |
return mOutput->latency(); |
|
1388 |
} |
|
1389 |
else { |
|
1390 |
return 0; |
|
1391 |
} |
|
1392 |
} |
|
1393 |
|
|
1394 |
status_t AudioFlinger::MixerThread::setMasterVolume(float value) |
|
1395 |
{ |
|
1396 |
mMasterVolume = value; |
|
1397 |
return NO_ERROR; |
|
1398 |
} |
|
1399 |
|
|
1400 |
status_t AudioFlinger::MixerThread::setMasterMute(bool muted) |
|
1401 |
{ |
|
1402 |
mMasterMute = muted; |
|
1403 |
return NO_ERROR; |
|
1404 |
} |
|
1405 |
|
|
1406 |
float AudioFlinger::MixerThread::masterVolume() const |
|
1407 |
{ |
|
1408 |
return mMasterVolume; |
|
1409 |
} |
|
1410 |
|
|
1411 |
bool AudioFlinger::MixerThread::masterMute() const |
|
1412 |
{ |
|
1413 |
return mMasterMute; |
|
1414 |
} |
|
1415 |
|
|
1416 |
status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value) |
|
1417 |
{ |
|
1418 |
mStreamTypes[stream].volume = value; |
|
1419 |
return NO_ERROR; |
|
1420 |
} |
|
1421 |
|
|
1422 |
status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted) |
|
1423 |
{ |
|
1424 |
mStreamTypes[stream].mute = muted; |
|
1425 |
return NO_ERROR; |
|
1426 |
} |
|
1427 |
|
|
1428 |
float AudioFlinger::MixerThread::streamVolume(int stream) const |
|
1429 |
{ |
|
1430 |
return mStreamTypes[stream].volume; |
|
1431 |
} |
|
1432 |
|
|
1433 |
bool AudioFlinger::MixerThread::streamMute(int stream) const |
|
1434 |
{ |
|
1435 |
return mStreamTypes[stream].mute; |
|
1436 |
} |
|
1437 |
|
|
1438 |
bool AudioFlinger::MixerThread::isMusicActive() const |
|
1439 |
{ |
|
1440 |
size_t count = mActiveTracks.size(); |
|
1441 |
for (size_t i = 0 ; i < count ; ++i) { |
|
1442 |
sp<Track> t = mActiveTracks[i].promote(); |
|
1443 |
if (t == 0) continue; |
|
1444 |
Track* const track = t.get(); |
|
1445 |
if (t->mStreamType == AudioSystem::MUSIC) |
|
1446 |
return true; |
|
1447 |
} |
|
1448 |
return false; |
|
1449 |
} |
|
1450 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1451 |
// addTrack_l() must be called with AudioFlinger::mLock held |
|
1452 |
status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1453 |
{ |
|
1454 |
status_t status = ALREADY_EXISTS; |
|
1455 |
|
|
1456 |
// here the track could be either new, or restarted |
|
1457 |
// in both cases "unstop" the track |
|
1458 |
if (track->isPaused()) { |
|
1459 |
track->mState = TrackBase::RESUMING; |
|
1460 |
LOGV("PAUSED => RESUMING (%d)", track->name()); |
|
1461 |
} else { |
|
1462 |
track->mState = TrackBase::ACTIVE; |
|
1463 |
LOGV("? => ACTIVE (%d)", track->name()); |
|
1464 |
} |
|
1465 |
// set retry count for buffer fill |
|
1466 |
track->mRetryCount = kMaxTrackStartupRetries; |
|
1467 |
if (mActiveTracks.indexOf(track) < 0) { |
|
1468 |
// the track is newly added, make sure it fills up all its |
|
1469 |
// buffers before playing. This is to ensure the client will |
|
1470 |
// effectively get the latency it requested. |
|
1471 |
track->mFillingUpStatus = Track::FS_FILLING; |
|
1472 |
track->mResetDone = false; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1473 |
addActiveTrack_l(track); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1474 |
status = NO_ERROR; |
|
1475 |
} |
|
1476 |
|
|
1477 |
LOGV("mWaitWorkCV.broadcast"); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1478 |
mAudioFlinger->mWaitWorkCV.broadcast(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1479 |
|
|
1480 |
return status; |
|
1481 |
} |
|
1482 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1483 |
// removeTrack_l() must be called with AudioFlinger::mLock held |
|
1484 |
void AudioFlinger::MixerThread::removeTrack_l(wp<Track> track, int name) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1485 |
{ |
|
1486 |
sp<Track> t = track.promote(); |
|
1487 |
if (t!=NULL && (t->mState <= TrackBase::STOPPED)) { |
|
1488 |
t->reset(); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1489 |
deleteTrackName_l(name); |
|
1490 |
removeActiveTrack_l(track); |
|
1491 |
mAudioFlinger->mWaitWorkCV.broadcast(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1492 |
} |
|
1493 |
} |
|
1494 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1495 |
// destroyTrack_l() must be called with AudioFlinger::mLock held |
|
1496 |
void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1497 |
{ |
|
1498 |
track->mState = TrackBase::TERMINATED; |
|
1499 |
if (mActiveTracks.indexOf(track) < 0) { |
|
1500 |
LOGV("remove track (%d) and delete from mixer", track->name()); |
|
1501 |
mTracks.remove(track); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1502 |
deleteTrackName_l(track->name()); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1503 |
} |
|
1504 |
} |
|
1505 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1506 |
// addActiveTrack_l() must be called with AudioFlinger::mLock held |
|
1507 |
void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1508 |
{ |
|
1509 |
mActiveTracks.add(t); |
|
1510 |
|
|
1511 |
// Force routing to speaker for certain stream types |
|
1512 |
// The forced routing to speaker is managed by hardware mixer |
|
1513 |
if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { |
|
1514 |
sp<Track> track = t.promote(); |
|
1515 |
if (track == NULL) return; |
|
1516 |
|
|
1517 |
if (streamForcedToSpeaker(track->type())) { |
|
1518 |
mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED); |
|
1519 |
} |
|
1520 |
} |
|
1521 |
} |
|
1522 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1523 |
// removeActiveTrack_l() must be called with AudioFlinger::mLock held |
|
1524 |
void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1525 |
{ |
|
1526 |
mActiveTracks.remove(t); |
|
1527 |
|
|
1528 |
// Force routing to speaker for certain stream types |
|
1529 |
// The forced routing to speaker is managed by hardware mixer |
|
1530 |
if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { |
|
1531 |
sp<Track> track = t.promote(); |
|
1532 |
if (track == NULL) return; |
|
1533 |
|
|
1534 |
if (streamForcedToSpeaker(track->type())) { |
|
1535 |
mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED); |
|
1536 |
} |
|
1537 |
} |
|
1538 |
} |
|
1539 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1540 |
// getTrackName_l() must be called with AudioFlinger::mLock held |
|
1541 |
int AudioFlinger::MixerThread::getTrackName_l() |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1542 |
{ |
|
1543 |
return mAudioMixer->getTrackName(); |
|
1544 |
} |
|
1545 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1546 |
// deleteTrackName_l() must be called with AudioFlinger::mLock held |
|
1547 |
void AudioFlinger::MixerThread::deleteTrackName_l(int name) |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1548 |
{ |
|
1549 |
mAudioMixer->deleteTrackName(name); |
|
1550 |
} |
|
1551 |
|
|
1552 |
size_t AudioFlinger::MixerThread::getOutputFrameCount() |
|
1553 |
{ |
|
1554 |
return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t); |
|
1555 |
} |
|
1556 |
|
|
1557 |
// ---------------------------------------------------------------------------- |
|
1558 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1559 |
// TrackBase constructor must be called with AudioFlinger::mLock held |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1560 |
AudioFlinger::MixerThread::TrackBase::TrackBase( |
|
1561 |
const sp<MixerThread>& mixerThread, |
|
1562 |
const sp<Client>& client, |
|
1563 |
int streamType, |
|
1564 |
uint32_t sampleRate, |
|
1565 |
int format, |
|
1566 |
int channelCount, |
|
1567 |
int frameCount, |
|
1568 |
uint32_t flags, |
|
1569 |
const sp<IMemory>& sharedBuffer) |
|
1570 |
: RefBase(), |
|
1571 |
mMixerThread(mixerThread), |
|
1572 |
mClient(client), |
|
1573 |
mStreamType(streamType), |
|
1574 |
mFrameCount(0), |
|
1575 |
mState(IDLE), |
|
1576 |
mClientTid(-1), |
|
1577 |
mFormat(format), |
|
1578 |
mFlags(flags & ~SYSTEM_FLAGS_MASK) |
|
1579 |
{ |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1580 |
mName = mixerThread->getTrackName_l(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1581 |
LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); |
|
1582 |
if (mName < 0) { |
|
1583 |
LOGE("no more track names availlable"); |
|
1584 |
return; |
|
1585 |
} |
|
1586 |
|
|
1587 |
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); |
|
1588 |
|
|
1589 |
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); |
|
1590 |
size_t size = sizeof(audio_track_cblk_t); |
|
1591 |
size_t bufferSize = frameCount*channelCount*sizeof(int16_t); |
|
1592 |
if (sharedBuffer == 0) { |
|
1593 |
size += bufferSize; |
|
1594 |
} |
|
1595 |
|
|
1596 |
if (client != NULL) { |
|
1597 |
mCblkMemory = client->heap()->allocate(size); |
|
1598 |
if (mCblkMemory != 0) { |
|
1599 |
mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); |
|
1600 |
if (mCblk) { // construct the shared structure in-place. |
|
1601 |
new(mCblk) audio_track_cblk_t(); |
|
1602 |
// clear all buffers |
|
1603 |
mCblk->frameCount = frameCount; |
| 1059253 by The Android Open Source Project at 2009-03-19 |
1604 |
mCblk->sampleRate = (uint16_t)sampleRate; |
|
1605 |
mCblk->channels = (uint16_t)channelCount; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1606 |
if (sharedBuffer == 0) { |
|
1607 |
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); |
|
1608 |
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); |
|
1609 |
// Force underrun condition to avoid false underrun callback until first data is |
|
1610 |
// written to buffer |
|
1611 |
mCblk->flowControlFlag = 1; |
|
1612 |
} else { |
|
1613 |
mBuffer = sharedBuffer->pointer(); |
|
1614 |
} |
|
1615 |
mBufferEnd = (uint8_t *)mBuffer + bufferSize; |
|
1616 |
} |
|
1617 |
} else { |
|
1618 |
LOGE("not enough memory for AudioTrack size=%u", size); |
|
1619 |
client->heap()->dump("AudioTrack"); |
|
1620 |
return; |
|
1621 |
} |
|
1622 |
} else { |
|
1623 |
mCblk = (audio_track_cblk_t *)(new uint8_t[size]); |
|
1624 |
if (mCblk) { // construct the shared structure in-place. |
|
1625 |
new(mCblk) audio_track_cblk_t(); |
|
1626 |
// clear all buffers |
|
1627 |
mCblk->frameCount = frameCount; |
| 1059253 by The Android Open Source Project at 2009-03-19 |
1628 |
mCblk->sampleRate = (uint16_t)sampleRate; |
|
1629 |
mCblk->channels = (uint16_t)channelCount; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1630 |
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); |
|
1631 |
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); |
|
1632 |
// Force underrun condition to avoid false underrun callback until first data is |
|
1633 |
// written to buffer |
|
1634 |
mCblk->flowControlFlag = 1; |
|
1635 |
mBufferEnd = (uint8_t *)mBuffer + bufferSize; |
|
1636 |
} |
|
1637 |
} |
|
1638 |
} |
|
1639 |
|
|
1640 |
AudioFlinger::MixerThread::TrackBase::~TrackBase() |
|
1641 |
{ |
|
1642 |
if (mCblk) { |
|
1643 |
mCblk->~audio_track_cblk_t(); // destroy our shared-structure. |
|
1644 |
} |
|
1645 |
mCblkMemory.clear(); // and free the shared memory |
|
1646 |
mClient.clear(); |
|
1647 |
} |
|
1648 |
|
|
1649 |
void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) |
|
1650 |
{ |
|
1651 |
buffer->raw = 0; |
|
1652 |
mFrameCount = buffer->frameCount; |
|
1653 |
step(); |
|
1654 |
buffer->frameCount = 0; |
|
1655 |
} |
|
1656 |
|
|
1657 |
bool AudioFlinger::MixerThread::TrackBase::step() { |
|
1658 |
bool result; |
|
1659 |
audio_track_cblk_t* cblk = this->cblk(); |
|
1660 |
|
|
1661 |
result = cblk->stepServer(mFrameCount); |
|
1662 |
if (!result) { |
|
1663 |
LOGV("stepServer failed acquiring cblk mutex"); |
|
1664 |
mFlags |= STEPSERVER_FAILED; |
|
1665 |
} |
|
1666 |
return result; |
|
1667 |
} |
|
1668 |
|
|
1669 |
void AudioFlinger::MixerThread::TrackBase::reset() { |
|
1670 |
audio_track_cblk_t* cblk = this->cblk(); |
|
1671 |
|
|
1672 |
cblk->user = 0; |
|
1673 |
cblk->server = 0; |
|
1674 |
cblk->userBase = 0; |
|
1675 |
cblk->serverBase = 0; |
|
1676 |
mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK); |
|
1677 |
LOGV("TrackBase::reset"); |
|
1678 |
} |
|
1679 |
|
|
1680 |
sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const |
|
1681 |
{ |
|
1682 |
return mCblkMemory; |
|
1683 |
} |
|
1684 |
|
|
1685 |
int AudioFlinger::MixerThread::TrackBase::sampleRate() const { |
| 1059253 by The Android Open Source Project at 2009-03-19 |
1686 |
return (int)mCblk->sampleRate; |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1687 |
} |
|
1688 |
|
|
1689 |
int AudioFlinger::MixerThread::TrackBase::channelCount() const { |
|
1690 |
return mCblk->channels; |
|
1691 |
} |
|
1692 |
|
|
1693 |
void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { |
|
1694 |
audio_track_cblk_t* cblk = this->cblk(); |
|
1695 |
int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels; |
|
1696 |
int16_t *bufferEnd = bufferStart + frames * cblk->channels; |
|
1697 |
|
|
1698 |
// Check validity of returned pointer in case the track control block would have been corrupted. |
| 1059253 by The Android Open Source Project at 2009-03-19 |
1699 |
if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || |
|
1700 |
cblk->channels == 2 && ((unsigned long)bufferStart & 3) ) { |
|
1701 |
LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ |
|
1702 |
server %d, serverBase %d, user %d, userBase %d, channels %d", |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1703 |
bufferStart, bufferEnd, mBuffer, mBufferEnd, |
| 1059253 by The Android Open Source Project at 2009-03-19 |
1704 |
cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1705 |
return 0; |
|
1706 |
} |
|
1707 |
|
|
1708 |
return bufferStart; |
|
1709 |
} |
|
1710 |
|
|
1711 |
// ---------------------------------------------------------------------------- |
|
1712 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1713 |
// Track constructor must be called with AudioFlinger::mLock held |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1714 |
AudioFlinger::MixerThread::Track::Track( |
|
1715 |
const sp<MixerThread>& mixerThread, |
|
1716 |
const sp<Client>& client, |
|
1717 |
int streamType, |
|
1718 |
uint32_t sampleRate, |
|
1719 |
int format, |
|
1720 |
int channelCount, |
|
1721 |
int frameCount, |
|
1722 |
const sp<IMemory>& sharedBuffer) |
|
1723 |
: TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer) |
|
1724 |
{ |
|
1725 |
mVolume[0] = 1.0f; |
|
1726 |
mVolume[1] = 1.0f; |
|
1727 |
mMute = false; |
|
1728 |
mSharedBuffer = sharedBuffer; |
|
1729 |
} |
|
1730 |
|
|
1731 |
AudioFlinger::MixerThread::Track::~Track() |
|
1732 |
{ |
|
1733 |
wp<Track> weak(this); // never create a strong ref from the dtor |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1734 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1735 |
mState = TERMINATED; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1736 |
mMixerThread->removeTrack_l(weak, mName); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1737 |
} |
|
1738 |
|
|
1739 |
void AudioFlinger::MixerThread::Track::destroy() |
|
1740 |
{ |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1741 |
// NOTE: destroyTrack_l() can remove a strong reference to this Track |
|
1742 |
// by removing it from mTracks vector, so there is a risk that this Tracks's |
|
1743 |
// desctructor is called. As the destructor needs to lock AudioFlinger::mLock, |
|
1744 |
// we must acquire a strong reference on this Track before locking AudioFlinger::mLock |
|
1745 |
// here so that the destructor is called only when exiting this function. |
|
1746 |
// On the other hand, as long as Track::destroy() is only called by |
|
1747 |
// TrackHandle destructor, the TrackHandle still holds a strong ref on |
|
1748 |
// this Track with its member mTrack. |
|
1749 |
sp<Track> keep(this); |
|
1750 |
{ // scope for AudioFlinger::mLock |
|
1751 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
|
1752 |
mMixerThread->destroyTrack_l(this); |
|
1753 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1754 |
} |
|
1755 |
|
|
1756 |
void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size) |
|
1757 |
{ |
|
1758 |
snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n", |
|
1759 |
mName - AudioMixer::TRACK0, |
|
1760 |
(mClient == NULL) ? getpid() : mClient->pid(), |
|
1761 |
mStreamType, |
|
1762 |
mFormat, |
|
1763 |
mCblk->channels, |
|
1764 |
mFrameCount, |
|
1765 |
mState, |
|
1766 |
mMute, |
|
1767 |
mFillingUpStatus, |
|
1768 |
mCblk->sampleRate, |
|
1769 |
mCblk->volume[0], |
|
1770 |
mCblk->volume[1], |
|
1771 |
mCblk->server, |
|
1772 |
mCblk->user); |
|
1773 |
} |
|
1774 |
|
|
1775 |
status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) |
|
1776 |
{ |
|
1777 |
audio_track_cblk_t* cblk = this->cblk(); |
|
1778 |
uint32_t framesReady; |
|
1779 |
uint32_t framesReq = buffer->frameCount; |
|
1780 |
|
|
1781 |
// Check if last stepServer failed, try to step now |
|
1782 |
if (mFlags & TrackBase::STEPSERVER_FAILED) { |
|
1783 |
if (!step()) goto getNextBuffer_exit; |
|
1784 |
LOGV("stepServer recovered"); |
|
1785 |
mFlags &= ~TrackBase::STEPSERVER_FAILED; |
|
1786 |
} |
|
1787 |
|
|
1788 |
framesReady = cblk->framesReady(); |
|
1789 |
|
|
1790 |
if (LIKELY(framesReady)) { |
|
1791 |
uint32_t s = cblk->server; |
|
1792 |
uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; |
|
1793 |
|
|
1794 |
bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd; |
|
1795 |
if (framesReq > framesReady) { |
|
1796 |
framesReq = framesReady; |
|
1797 |
} |
|
1798 |
if (s + framesReq > bufferEnd) { |
|
1799 |
framesReq = bufferEnd - s; |
|
1800 |
} |
|
1801 |
|
|
1802 |
buffer->raw = getBuffer(s, framesReq); |
|
1803 |
if (buffer->raw == 0) goto getNextBuffer_exit; |
|
1804 |
|
|
1805 |
buffer->frameCount = framesReq; |
|
1806 |
return NO_ERROR; |
|
1807 |
} |
|
1808 |
|
|
1809 |
getNextBuffer_exit: |
|
1810 |
buffer->raw = 0; |
|
1811 |
buffer->frameCount = 0; |
|
1812 |
return NOT_ENOUGH_DATA; |
|
1813 |
} |
|
1814 |
|
|
1815 |
bool AudioFlinger::MixerThread::Track::isReady() const { |
|
1816 |
if (mFillingUpStatus != FS_FILLING) return true; |
|
1817 |
|
|
1818 |
if (mCblk->framesReady() >= mCblk->frameCount || |
|
1819 |
mCblk->forceReady) { |
|
1820 |
mFillingUpStatus = FS_FILLED; |
|
1821 |
mCblk->forceReady = 0; |
|
1822 |
LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType); |
|
1823 |
return true; |
|
1824 |
} |
|
1825 |
return false; |
|
1826 |
} |
|
1827 |
|
|
1828 |
status_t AudioFlinger::MixerThread::Track::start() |
|
1829 |
{ |
|
1830 |
LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1831 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
|
1832 |
mMixerThread->addTrack_l(this); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1833 |
return NO_ERROR; |
|
1834 |
} |
|
1835 |
|
|
1836 |
void AudioFlinger::MixerThread::Track::stop() |
|
1837 |
{ |
|
1838 |
LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1839 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1840 |
if (mState > STOPPED) { |
|
1841 |
mState = STOPPED; |
|
1842 |
// If the track is not active (PAUSED and buffers full), flush buffers |
|
1843 |
if (mMixerThread->mActiveTracks.indexOf(this) < 0) { |
|
1844 |
reset(); |
|
1845 |
} |
|
1846 |
LOGV("(> STOPPED) => STOPPED (%d)", mName); |
|
1847 |
} |
|
1848 |
} |
|
1849 |
|
|
1850 |
void AudioFlinger::MixerThread::Track::pause() |
|
1851 |
{ |
|
1852 |
LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1853 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1854 |
if (mState == ACTIVE || mState == RESUMING) { |
|
1855 |
mState = PAUSING; |
|
1856 |
LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName); |
|
1857 |
} |
|
1858 |
} |
|
1859 |
|
|
1860 |
void AudioFlinger::MixerThread::Track::flush() |
|
1861 |
{ |
|
1862 |
LOGV("flush(%d)", mName); |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1863 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1864 |
if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { |
|
1865 |
return; |
|
1866 |
} |
|
1867 |
// No point remaining in PAUSED state after a flush => go to |
|
1868 |
// STOPPED state |
|
1869 |
mState = STOPPED; |
|
1870 |
|
| 1059253 by The Android Open Source Project at 2009-03-19 |
1871 |
mCblk->lock.lock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1872 |
// NOTE: reset() will reset cblk->user and cblk->server with |
|
1873 |
// the risk that at the same time, the AudioMixer is trying to read |
|
1874 |
// data. In this case, getNextBuffer() would return a NULL pointer |
|
1875 |
// as audio buffer => the AudioMixer code MUST always test that pointer |
|
1876 |
// returned by getNextBuffer() is not NULL! |
|
1877 |
reset(); |
| 1059253 by The Android Open Source Project at 2009-03-19 |
1878 |
mCblk->lock.unlock(); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1879 |
} |
|
1880 |
|
|
1881 |
void AudioFlinger::MixerThread::Track::reset() |
|
1882 |
{ |
|
1883 |
// Do not reset twice to avoid discarding data written just after a flush and before |
|
1884 |
// the audioflinger thread detects the track is stopped. |
|
1885 |
if (!mResetDone) { |
|
1886 |
TrackBase::reset(); |
|
1887 |
// Force underrun condition to avoid false underrun callback until first data is |
|
1888 |
// written to buffer |
|
1889 |
mCblk->flowControlFlag = 1; |
|
1890 |
mCblk->forceReady = 0; |
|
1891 |
mFillingUpStatus = FS_FILLING; |
|
1892 |
mResetDone = true; |
|
1893 |
} |
|
1894 |
} |
|
1895 |
|
|
1896 |
void AudioFlinger::MixerThread::Track::mute(bool muted) |
|
1897 |
{ |
|
1898 |
mMute = muted; |
|
1899 |
} |
|
1900 |
|
|
1901 |
void AudioFlinger::MixerThread::Track::setVolume(float left, float right) |
|
1902 |
{ |
|
1903 |
mVolume[0] = left; |
|
1904 |
mVolume[1] = right; |
|
1905 |
} |
|
1906 |
|
|
1907 |
// ---------------------------------------------------------------------------- |
|
1908 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1909 |
// RecordTrack constructor must be called with AudioFlinger::mLock held |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1910 |
AudioFlinger::MixerThread::RecordTrack::RecordTrack( |
|
1911 |
const sp<MixerThread>& mixerThread, |
|
1912 |
const sp<Client>& client, |
|
1913 |
int streamType, |
|
1914 |
uint32_t sampleRate, |
|
1915 |
int format, |
|
1916 |
int channelCount, |
|
1917 |
int frameCount, |
|
1918 |
uint32_t flags) |
|
1919 |
: TrackBase(mixerThread, client, streamType, sampleRate, format, |
|
1920 |
channelCount, frameCount, flags, 0), |
|
1921 |
mOverflow(false) |
|
1922 |
{ |
|
1923 |
} |
|
1924 |
|
|
1925 |
AudioFlinger::MixerThread::RecordTrack::~RecordTrack() |
|
1926 |
{ |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
1927 |
Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); |
|
1928 |
mMixerThread->deleteTrackName_l(mName); |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
1929 |
} |
|
1930 |
|
|
1931 |
status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) |
|
1932 |
{ |
|
1933 |
audio_track_cblk_t* cblk = this->cblk(); |
|
1934 |
uint32_t framesAvail; |
|
1935 |
uint32_t framesReq = buffer->frameCount; |
|
1936 |
|
|
1937 |
// Check if last stepServer failed, try to step now |
|
1938 |
if (mFlags & TrackBase::STEPSERVER_FAILED) { |
|
1939 |
if (!step()) goto getNextBuffer_exit; |
|
1940 |
LOGV("stepServer recovered"); |
|
1941 |
mFlags &= ~TrackBase::STEPSERVER_FAILED; |
|
1942 |
} |
|
1943 |
|
|
1944 |
framesAvail = cblk->framesAvailable_l(); |
|
1945 |
|
|
1946 |
if (LIKELY(framesAvail)) { |
|
1947 |
uint32_t s = cblk->server; |
|
1948 |
uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; |
|
1949 |
|
|
1950 |
if (framesReq > framesAvail) { |
|
1951 |
framesReq = framesAvail; |
|
1952 |
} |
|
1953 |
if (s + framesReq > bufferEnd) { |
|
1954 |
framesReq = bufferEnd - s; |
|
1955 |
} |
|
1956 |
|
|
1957 |
buffer->raw = getBuffer(s, framesReq); |
|
1958 |
if (buffer->raw == 0) goto getNextBuffer_exit; |
|
1959 |
|
|
1960 |
buffer->frameCount = framesReq; |
|
1961 |
return NO_ERROR; |
|
1962 |
} |
|
1963 |
|
|
1964 |
getNextBuffer_exit: |
|
1965 |
buffer->raw = 0; |
|
1966 |
buffer->frameCount = 0; |
|
1967 |
return NOT_ENOUGH_DATA; |
|
1968 |
} |
|
1969 |
|
|
1970 |
status_t AudioFlinger::MixerThread::RecordTrack::start() |
|
1971 |
{ |
|
1972 |
return mMixerThread->mAudioFlinger->startRecord(this); |
|
1973 |
} |
|
1974 |
|
|
1975 |
void AudioFlinger::MixerThread::RecordTrack::stop() |
|
1976 |
{ |
|
1977 |
mMixerThread->mAudioFlinger->stopRecord(this); |
|
1978 |
TrackBase::reset(); |
|
1979 |
// Force overerrun condition to avoid false overrun callback until first data is |
|
1980 |
// read from buffer |
|
1981 |
mCblk->flowControlFlag = 1; |
|
1982 |
} |
|
1983 |
|
|
1984 |
|
|
1985 |
// ---------------------------------------------------------------------------- |
|
1986 |
|
|
1987 |
AudioFlinger::MixerThread::OutputTrack::OutputTrack( |
|
1988 |
const sp<MixerThread>& mixerThread, |
|
1989 |
uint32_t sampleRate, |
|
1990 |
int format, |
|
1991 |
int channelCount, |
|
1992 |
int frameCount) |
|
1993 |
: Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL), |
|
1994 |
mOutputMixerThread(mixerThread) |
|
1995 |
{ |
|
1996 |
|
|
1997 |
mCblk->out = 1; |
|
1998 |
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); |
|
1999 |
mCblk->volume[0] = mCblk->volume[1] = 0x1000; |
|
2000 |
mOutBuffer.frameCount = 0; |
|
2001 |
mCblk->bufferTimeoutMs = 10; |
|
2002 |
|
|
2003 |
LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", |
|
2004 |
mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd); |
|
2005 |
|
|
2006 |
} |
|
2007 |
|
|
2008 |
AudioFlinger::MixerThread::OutputTrack::~OutputTrack() |
|
2009 |
{ |
|
2010 |
stop(); |
|
2011 |
} |
|
2012 |
|
|
2013 |
status_t AudioFlinger::MixerThread::OutputTrack::start() |
|
2014 |
{ |
|
2015 |
status_t status = Track::start(); |
|
2016 |
|
|
2017 |
mRetryCount = 127; |
|
2018 |
return status; |
|
2019 |
} |
|
2020 |
|
|
2021 |
void AudioFlinger::MixerThread::OutputTrack::stop() |
|
2022 |
{ |
|
2023 |
Track::stop(); |
|
2024 |
clearBufferQueue(); |
|
2025 |
mOutBuffer.frameCount = 0; |
|
2026 |
} |
|
2027 |
|
|
2028 |
void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames) |
|
2029 |
{ |
|
2030 |
Buffer *pInBuffer; |
|
2031 |
Buffer inBuffer; |
|
2032 |
uint32_t channels = mCblk->channels; |
|
2033 |
|
|
2034 |
inBuffer.frameCount = frames; |
|
2035 |
inBuffer.i16 = data; |
|
2036 |
|
|
2037 |
if (mCblk->user == 0) { |
|
2038 |
if (mOutputMixerThread->isMusicActive()) { |
|
2039 |
mCblk->forceReady = 1; |
|
2040 |
LOGV("OutputTrack::start() force ready"); |
|
2041 |
} else if (mCblk->frameCount > frames){ |
|
2042 |
if (mBufferQueue.size() < kMaxOutputTrackBuffers) { |
|
2043 |
uint32_t startFrames = (mCblk->frameCount - frames); |
|
2044 |
LOGV("OutputTrack::start() write %d frames", startFrames); |
|
2045 |
pInBuffer = new Buffer; |
|
2046 |
pInBuffer->mBuffer = new int16_t[startFrames * channels]; |
|
2047 |
pInBuffer->frameCount = startFrames; |
|
2048 |
pInBuffer->i16 = pInBuffer->mBuffer; |
|
2049 |
memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t)); |
|
2050 |
mBufferQueue.add(pInBuffer); |
|
2051 |
} else { |
|
2052 |
LOGW ("OutputTrack::write() no more buffers"); |
|
2053 |
} |
|
2054 |
} |
|
2055 |
} |
|
2056 |
|
|
2057 |
while (1) { |
|
2058 |
// First write pending buffers, then new data |
|
2059 |
if (mBufferQueue.size()) { |
|
2060 |
pInBuffer = mBufferQueue.itemAt(0); |
|
2061 |
} else { |
|
2062 |
pInBuffer = &inBuffer; |
|
2063 |
} |
|
2064 |
|
|
2065 |
if (pInBuffer->frameCount == 0) { |
|
2066 |
break; |
|
2067 |
} |
|
2068 |
|
|
2069 |
if (mOutBuffer.frameCount == 0) { |
|
2070 |
mOutBuffer.frameCount = pInBuffer->frameCount; |
|
2071 |
if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) { |
|
2072 |
break; |
|
2073 |
} |
|
2074 |
} |
|
2075 |
|
|
2076 |
uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; |
|
2077 |
memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t)); |
|
2078 |
mCblk->stepUser(outFrames); |
|
2079 |
pInBuffer->frameCount -= outFrames; |
|
2080 |
pInBuffer->i16 += outFrames * channels; |
|
2081 |
mOutBuffer.frameCount -= outFrames; |
|
2082 |
mOutBuffer.i16 += outFrames * channels; |
|
2083 |
|
|
2084 |
if (pInBuffer->frameCount == 0) { |
|
2085 |
if (mBufferQueue.size()) { |
|
2086 |
mBufferQueue.removeAt(0); |
|
2087 |
delete [] pInBuffer->mBuffer; |
|
2088 |
delete pInBuffer; |
|
2089 |
} else { |
|
2090 |
break; |
|
2091 |
} |
|
2092 |
} |
|
2093 |
} |
|
2094 |
|
|
2095 |
// If we could not write all frames, allocate a buffer and queue it for next time. |
|
2096 |
if (inBuffer.frameCount) { |
|
2097 |
if (mBufferQueue.size() < kMaxOutputTrackBuffers) { |
|
2098 |
pInBuffer = new Buffer; |
|
2099 |
pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels]; |
|
2100 |
pInBuffer->frameCount = inBuffer.frameCount; |
|
2101 |
pInBuffer->i16 = pInBuffer->mBuffer; |
|
2102 |
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t)); |
|
2103 |
mBufferQueue.add(pInBuffer); |
|
2104 |
} else { |
|
2105 |
LOGW("OutputTrack::write() no more buffers"); |
|
2106 |
} |
|
2107 |
} |
|
2108 |
|
|
2109 |
// Calling write() with a 0 length buffer, means that no more data will be written: |
|
2110 |
// If no more buffers are pending, fill output track buffer to make sure it is started |
|
2111 |
// by output mixer. |
|
2112 |
if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) { |
|
2113 |
frames = mCblk->frameCount - mCblk->user; |
|
2114 |
pInBuffer = new Buffer; |
|
2115 |
pInBuffer->mBuffer = new int16_t[frames * channels]; |
|
2116 |
pInBuffer->frameCount = frames; |
|
2117 |
pInBuffer->i16 = pInBuffer->mBuffer; |
|
2118 |
memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t)); |
|
2119 |
mBufferQueue.add(pInBuffer); |
|
2120 |
} |
|
2121 |
|
|
2122 |
} |
|
2123 |
|
|
2124 |
status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer) |
|
2125 |
{ |
|
2126 |
int active; |
|
2127 |
int timeout = 0; |
|
2128 |
status_t result; |
|
2129 |
audio_track_cblk_t* cblk = mCblk; |
|
2130 |
uint32_t framesReq = buffer->frameCount; |
|
2131 |
|
|
2132 |
LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server); |
|
2133 |
buffer->frameCount = 0; |
|
2134 |
|
|
2135 |
uint32_t framesAvail = cblk->framesAvailable(); |
|
2136 |
|
|
2137 |
if (framesAvail == 0) { |
|
2138 |
return AudioTrack::NO_MORE_BUFFERS; |
|
2139 |
} |
|
2140 |
|
|
2141 |
if (framesReq > framesAvail) { |
|
2142 |
framesReq = framesAvail; |
|
2143 |
} |
|
2144 |
|
|
2145 |
uint32_t u = cblk->user; |
|
2146 |
uint32_t bufferEnd = cblk->userBase + cblk->frameCount; |
|
2147 |
|
|
2148 |
if (u + framesReq > bufferEnd) { |
|
2149 |
framesReq = bufferEnd - u; |
|
2150 |
} |
|
2151 |
|
|
2152 |
buffer->frameCount = framesReq; |
|
2153 |
buffer->raw = (void *)cblk->buffer(u); |
|
2154 |
return NO_ERROR; |
|
2155 |
} |
|
2156 |
|
|
2157 |
|
|
2158 |
void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue() |
|
2159 |
{ |
|
2160 |
size_t size = mBufferQueue.size(); |
|
2161 |
Buffer *pBuffer; |
|
2162 |
|
|
2163 |
for (size_t i = 0; i < size; i++) { |
|
2164 |
pBuffer = mBufferQueue.itemAt(i); |
|
2165 |
delete [] pBuffer->mBuffer; |
|
2166 |
delete pBuffer; |
|
2167 |
} |
|
2168 |
mBufferQueue.clear(); |
|
2169 |
} |
|
2170 |
|
|
2171 |
// ---------------------------------------------------------------------------- |
|
2172 |
|
|
2173 |
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) |
|
2174 |
: RefBase(), |
|
2175 |
mAudioFlinger(audioFlinger), |
|
2176 |
mMemoryDealer(new MemoryDealer(1024*1024)), |
|
2177 |
mPid(pid) |
|
2178 |
{ |
|
2179 |
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer |
|
2180 |
} |
|
2181 |
|
|
2182 |
AudioFlinger::Client::~Client() |
|
2183 |
{ |
|
2184 |
mAudioFlinger->removeClient(mPid); |
|
2185 |
} |
|
2186 |
|
|
2187 |
const sp<MemoryDealer>& AudioFlinger::Client::heap() const |
|
2188 |
{ |
|
2189 |
return mMemoryDealer; |
|
2190 |
} |
|
2191 |
|
|
2192 |
// ---------------------------------------------------------------------------- |
|
2193 |
|
|
2194 |
AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track) |
|
2195 |
: BnAudioTrack(), |
|
2196 |
mTrack(track) |
|
2197 |
{ |
|
2198 |
} |
|
2199 |
|
|
2200 |
AudioFlinger::TrackHandle::~TrackHandle() { |
|
2201 |
// just stop the track on deletion, associated resources |
|
2202 |
// will be freed from the main thread once all pending buffers have |
|
2203 |
// been played. Unless it's not in the active track list, in which |
|
2204 |
// case we free everything now... |
|
2205 |
mTrack->destroy(); |
|
2206 |
} |
|
2207 |
|
|
2208 |
status_t AudioFlinger::TrackHandle::start() { |
|
2209 |
return mTrack->start(); |
|
2210 |
} |
|
2211 |
|
|
2212 |
void AudioFlinger::TrackHandle::stop() { |
|
2213 |
mTrack->stop(); |
|
2214 |
} |
|
2215 |
|
|
2216 |
void AudioFlinger::TrackHandle::flush() { |
|
2217 |
mTrack->flush(); |
|
2218 |
} |
|
2219 |
|
|
2220 |
void AudioFlinger::TrackHandle::mute(bool e) { |
|
2221 |
mTrack->mute(e); |
|
2222 |
} |
|
2223 |
|
|
2224 |
void AudioFlinger::TrackHandle::pause() { |
|
2225 |
mTrack->pause(); |
|
2226 |
} |
|
2227 |
|
|
2228 |
void AudioFlinger::TrackHandle::setVolume(float left, float right) { |
|
2229 |
mTrack->setVolume(left, right); |
|
2230 |
} |
|
2231 |
|
|
2232 |
sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { |
|
2233 |
return mTrack->getCblk(); |
|
2234 |
} |
|
2235 |
|
|
2236 |
status_t AudioFlinger::TrackHandle::onTransact( |
|
2237 |
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) |
|
2238 |
{ |
|
2239 |
return BnAudioTrack::onTransact(code, data, reply, flags); |
|
2240 |
} |
|
2241 |
|
|
2242 |
// ---------------------------------------------------------------------------- |
|
2243 |
|
|
2244 |
sp<IAudioRecord> AudioFlinger::openRecord( |
|
2245 |
pid_t pid, |
|
2246 |
int streamType, |
|
2247 |
uint32_t sampleRate, |
|
2248 |
int format, |
|
2249 |
int channelCount, |
|
2250 |
int frameCount, |
|
2251 |
uint32_t flags, |
|
2252 |
status_t *status) |
|
2253 |
{ |
|
2254 |
sp<MixerThread::RecordTrack> recordTrack; |
|
2255 |
sp<RecordHandle> recordHandle; |
|
2256 |
sp<Client> client; |
|
2257 |
wp<Client> wclient; |
|
2258 |
AudioStreamIn* input = 0; |
|
2259 |
int inFrameCount; |
|
2260 |
size_t inputBufferSize; |
|
2261 |
status_t lStatus; |
|
2262 |
|
|
2263 |
// check calling permissions |
|
2264 |
if (!recordingAllowed()) { |
|
2265 |
lStatus = PERMISSION_DENIED; |
|
2266 |
goto Exit; |
|
2267 |
} |
|
2268 |
|
|
2269 |
if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) { |
|
2270 |
LOGE("invalid stream type"); |
|
2271 |
lStatus = BAD_VALUE; |
|
2272 |
goto Exit; |
|
2273 |
} |
|
2274 |
|
|
2275 |
if (sampleRate > MAX_SAMPLE_RATE) { |
|
2276 |
LOGE("Sample rate out of range"); |
|
2277 |
lStatus = BAD_VALUE; |
|
2278 |
goto Exit; |
|
2279 |
} |
|
2280 |
|
|
2281 |
if (mAudioRecordThread == 0) { |
|
2282 |
LOGE("Audio record thread not started"); |
|
2283 |
lStatus = NO_INIT; |
|
2284 |
goto Exit; |
|
2285 |
} |
|
2286 |
|
|
2287 |
|
|
2288 |
// Check that audio input stream accepts requested audio parameters |
|
2289 |
inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); |
|
2290 |
if (inputBufferSize == 0) { |
|
2291 |
lStatus = BAD_VALUE; |
|
2292 |
LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount); |
|
2293 |
goto Exit; |
|
2294 |
} |
|
2295 |
|
|
2296 |
// add client to list |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
2297 |
{ // scope for mLock |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
2298 |
Mutex::Autolock _l(mLock); |
|
2299 |
wclient = mClients.valueFor(pid); |
|
2300 |
if (wclient != NULL) { |
|
2301 |
client = wclient.promote(); |
|
2302 |
} else { |
|
2303 |
client = new Client(this, pid); |
|
2304 |
mClients.add(pid, client); |
|
2305 |
} |
|
2306 |
|
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
2307 |
// frameCount must be a multiple of input buffer size |
|
2308 |
inFrameCount = inputBufferSize/channelCount/sizeof(short); |
|
2309 |
frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount; |
|
2310 |
|
|
2311 |
// create new record track. The record track uses one track in mHardwareMixerThread by convention. |
|
2312 |
recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate, |
|
2313 |
format, channelCount, frameCount, flags); |
|
2314 |
} |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
2315 |
if (recordTrack->getCblk() == NULL) { |
|
2316 |
recordTrack.clear(); |
|
2317 |
lStatus = NO_MEMORY; |
|
2318 |
goto Exit; |
|
2319 |
} |
|
2320 |
|
|
2321 |
// return to handle to client |
|
2322 |
recordHandle = new RecordHandle(recordTrack); |
|
2323 |
lStatus = NO_ERROR; |
|
2324 |
|
|
2325 |
Exit: |
|
2326 |
if (status) { |
|
2327 |
*status = lStatus; |
|
2328 |
} |
|
2329 |
return recordHandle; |
|
2330 |
} |
|
2331 |
|
|
2332 |
status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) { |
|
2333 |
if (mAudioRecordThread != 0) { |
|
2334 |
return mAudioRecordThread->start(recordTrack); |
|
2335 |
} |
|
2336 |
return NO_INIT; |
|
2337 |
} |
|
2338 |
|
|
2339 |
void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) { |
|
2340 |
if (mAudioRecordThread != 0) { |
|
2341 |
mAudioRecordThread->stop(recordTrack); |
|
2342 |
} |
|
2343 |
} |
|
2344 |
|
|
2345 |
// ---------------------------------------------------------------------------- |
|
2346 |
|
|
2347 |
AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack) |
|
2348 |
: BnAudioRecord(), |
|
2349 |
mRecordTrack(recordTrack) |
|
2350 |
{ |
|
2351 |
} |
|
2352 |
|
|
2353 |
AudioFlinger::RecordHandle::~RecordHandle() { |
|
2354 |
stop(); |
|
2355 |
} |
|
2356 |
|
|
2357 |
status_t AudioFlinger::RecordHandle::start() { |
|
2358 |
LOGV("RecordHandle::start()"); |
|
2359 |
return mRecordTrack->start(); |
|
2360 |
} |
|
2361 |
|
|
2362 |
void AudioFlinger::RecordHandle::stop() { |
|
2363 |
LOGV("RecordHandle::stop()"); |
|
2364 |
mRecordTrack->stop(); |
|
2365 |
} |
|
2366 |
|
|
2367 |
sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { |
|
2368 |
return mRecordTrack->getCblk(); |
|
2369 |
} |
|
2370 |
|
|
2371 |
status_t AudioFlinger::RecordHandle::onTransact( |
|
2372 |
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) |
|
2373 |
{ |
|
2374 |
return BnAudioRecord::onTransact(code, data, reply, flags); |
|
2375 |
} |
|
2376 |
|
|
2377 |
// ---------------------------------------------------------------------------- |
|
2378 |
|
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
2379 |
AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware, |
|
2380 |
const sp<AudioFlinger>& audioFlinger) : |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
2381 |
mAudioHardware(audioHardware), |
| c39a6e0 by The Android Open Source Project at 2009-03-11 |
2382 |
mAudioFlinger(audioFlinger), |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
2383 |
mActive(false) |
|
2384 |
{ |
|
2385 |
} |
|
2386 |
|
|
2387 |
AudioFlinger::AudioRecordThread::~AudioRecordThread() |
|
2388 |
{ |
|
2389 |
} |
|
2390 |
|
|
2391 |
bool AudioFlinger::AudioRecordThread::threadLoop() |
|
2392 |
{ |
|
2393 |
LOGV("AudioRecordThread: start record loop"); |
|
2394 |
AudioBufferProvider::Buffer buffer; |
|
2395 |
int inBufferSize = 0; |
|
2396 |
int inFrameCount = 0; |
|
2397 |
AudioStreamIn* input = 0; |
|
2398 |
|
|
2399 |
mActive = 0; |
|
2400 |
|
|
2401 |
// start recording |
|
2402 |
while (!exitPending()) { |
|
2403 |
if (!mActive) { |
|
2404 |
mLock.lock(); |
|
2405 |
if (!mActive && !exitPending()) { |
|
2406 |
LOGV("AudioRecordThread: loop stopping"); |
|
2407 |
if (input) { |
|
2408 |
delete input; |
|
2409 |
input = 0; |
|
2410 |
} |
|
2411 |
mRecordTrack.clear(); |
|
2412 |
mStopped.signal(); |
|
2413 |
|
|
2414 |
mWaitWorkCV.wait(mLock); |
|
2415 |
|
|
2416 |
LOGV("AudioRecordThread: loop starting"); |
|
2417 |
if (mRecordTrack != 0) { |
|
2418 |
input = mAudioHardware->openInputStream(mRecordTrack->format(), |
|
2419 |
mRecordTrack->channelCount(), |
|
2420 |
mRecordTrack->sampleRate(), |
|
2421 |
&mStartStatus, |
|
2422 |
(AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16)); |
|
2423 |
if (input != 0) { |
|
2424 |
inBufferSize = input->bufferSize(); |
|
2425 |
inFrameCount = inBufferSize/input->frameSize(); |
|
2426 |
} |
|
2427 |
} else { |
|
2428 |
mStartStatus = NO_INIT; |
|
2429 |
} |
|
2430 |
if (mStartStatus !=NO_ERROR) { |
|
2431 |
LOGW("record start failed, status %d", mStartStatus); |
|
2432 |
mActive = false; |
|
2433 |
mRecordTrack.clear(); |
|
2434 |
} |
|
2435 |
mWaitWorkCV.signal(); |
|
2436 |
} |
|
2437 |
mLock.unlock(); |
|
2438 |
} else if (mRecordTrack != 0) { |
|
2439 |
|
|
2440 |
buffer.frameCount = inFrameCount; |
| b2a3dd8 by The Android Open Source Project at 2009-03-09 |
2441 |
if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR && |
|
2442 |
(int)buffer.frameCount == inFrameCount)) { |
| 9066cfe by The Android Open Source Project at 2009-03-04 |
2443 |
LOGV("AudioRecordThread read: %d frames", buffer.frameCount); |
|
2444 |
ssize_t bytesRead = input->read(buffer.raw, inBufferSize); |
|
2445 |
if (bytesRead < 0) { |
|
2446 |
LOGE("Error reading audio input"); |
|
2447 |
sleep(1); |
|
2448 |
} |
|
2449 |
mRecordTrack->releaseBuffer(&buffer); |
|
2450 |
mRecordTrack->overflow(); |
|
2451 |
} |
|
2452 |
|
|
2453 |
// client isn't retrieving buffers fast enough |
|
2454 |
else { |
|
2455 |
if (!mRecordTrack->setOverflow()) |
|
2456 |
LOGW("AudioRecordThread: buffer overflow"); |
|
2457 |
// Release the processor for a while before asking for a new buffer. |
|
2458 |
// This will give the application more chance to read from the buffer and |
|
2459 |
// clear the overflow. |
|
2460 |
usleep(5000); |
|
2461 |
} |
|
2462 |
} |
|
2463 |
} |
|
2464 |
|
|
2465 |
|
|
2466 |
if (input) { |
|
2467 |
delete input; |
|
2468 |
} |
|
2469 |
mRecordTrack.clear(); |
|
2470 |
|
|
2471 |
return false; |
|
2472 |
} |
|
2473 |
|
|
2474 |
status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack) |
|
2475 |
{ |
|
2476 |
LOGV("AudioRecordThread::start"); |
|
2477 |
AutoMutex lock(&mLock); |
|
2478 |
mActive = true; |
|
2479 |
// If starting the active track, just reset mActive in case a stop |
|
2480 |
// was pending and exit |
|
2481 |
if (recordTrack == mRecordTrack.get()) return NO_ERROR; |
|
2482 |
|
|
2483 |
if (mRecordTrack != 0) return -EBUSY; |
|
2484 |
|
|
2485 |
mRecordTrack = recordTrack; |
|
2486 |
|
|
2487 |
// signal thread to start |
|
2488 |
LOGV("Signal record thread"); |
|
2489 |
mWaitWorkCV.signal(); |
|
2490 |
mWaitWorkCV.wait(mLock); |
|
2491 |
LOGV("Record started, status %d", mStartStatus); |
|
2492 |
return mStartStatus; |
|
2493 |
} |
|
2494 |
|
|
2495 |
void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) { |
|
2496 |
LOGV("AudioRecordThread::stop"); |
|
2497 |
AutoMutex lock(&mLock); |
|
2498 |
if (mActive && (recordTrack == mRecordTrack.get())) { |
|
2499 |
mActive = false; |
|
2500 |
mStopped.wait(mLock); |
|
2501 |
} |
|
2502 |
} |
|
2503 |
|
|
2504 |
void AudioFlinger::AudioRecordThread::exit() |
|
2505 |
{ |
|
2506 |
LOGV("AudioRecordThread::exit"); |
|
2507 |
{ |
|
2508 |
AutoMutex lock(&mLock); |
|
2509 |
requestExit(); |
|
2510 |
mWaitWorkCV.signal(); |
|
2511 |
} |
|
2512 |
requestExitAndWait(); |
|
2513 |
} |
|
2514 |
|
|
2515 |
status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args) |
|
2516 |
{ |
|
2517 |
const size_t SIZE = 256; |
|
2518 |
char buffer[SIZE]; |
|
2519 |
String8 result; |
|
2520 |
pid_t pid = 0; |
|
2521 |
|
|
2522 |
if (mRecordTrack != 0 && mRecordTrack->mClient != 0) { |
|
2523 |
snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid()); |
|
2524 |
result.append(buffer); |
|
2525 |
} else { |
|
2526 |
result.append("No record client\n"); |
|
2527 |
} |
|
2528 |
write(fd, result.string(), result.size()); |
|
2529 |
return NO_ERROR; |
|
2530 |
} |
|
2531 |
|
|
2532 |
status_t AudioFlinger::onTransact( |
|
2533 |
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) |
|
2534 |
{ |
|
2535 |
return BnAudioFlinger::onTransact(code, data, reply, flags); |
|
2536 |
} |
|
2537 |
|
|
2538 |
// ---------------------------------------------------------------------------- |
|
2539 |
void AudioFlinger::instantiate() { |
|
2540 |
defaultServiceManager()->addService( |
|
2541 |
String16("media.audio_flinger"), new AudioFlinger()); |
|
2542 |
} |
|
2543 |
|
|
2544 |
}; // namespace android |