blob: 557d93b2d2209c90c7047efa0e3975a531498f49 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/* //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
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080034#include <cutils/properties.h>
35
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070036#include <media/AudioTrack.h>
37#include <media/AudioRecord.h>
38
39#include <private/media/AudioTrackShared.h>
40
The Android Open Source Project8a7a6752009-01-15 16:12:10 -080041#include <hardware_legacy/AudioHardwareInterface.h>
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070042
43#include "AudioMixer.h"
44#include "AudioFlinger.h"
45
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080046#ifdef WITH_A2DP
47#include "A2dpAudioInterface.h"
48#endif
49
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -080050// ----------------------------------------------------------------------------
51// the sim build doesn't have gettid
52
53#ifndef HAVE_GETTID
54# define gettid getpid
55#endif
56
57// ----------------------------------------------------------------------------
58
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070059namespace android {
60
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080061//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070062static const unsigned long kBufferRecoveryInUsecs = 2000;
63static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
64static const float MAX_GAIN = 4096.0f;
65
66// retry counts for buffer fill timeout
67// 50 * ~20msecs = 1 second
68static const int8_t kMaxTrackRetries = 50;
69static const int8_t kMaxTrackStartupRetries = 50;
70
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -080071static const int kStartSleepTime = 30000;
72static const int kStopSleepTime = 30000;
73
74// Maximum number of pending buffers allocated by OutputTrack::write()
75static const uint8_t kMaxOutputTrackBuffers = 5;
76
77
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070078#define AUDIOFLINGER_SECURITY_ENABLED 1
79
80// ----------------------------------------------------------------------------
81
82static bool recordingAllowed() {
83#ifndef HAVE_ANDROID_OS
84 return true;
85#endif
86#if AUDIOFLINGER_SECURITY_ENABLED
87 if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
88 bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
89 if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO");
90 return ok;
91#else
92 if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO")))
93 LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest");
94 return true;
95#endif
96}
97
98static bool settingsAllowed() {
99#ifndef HAVE_ANDROID_OS
100 return true;
101#endif
102#if AUDIOFLINGER_SECURITY_ENABLED
103 if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
104 bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
105 if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
106 return ok;
107#else
108 if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")))
109 LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest");
110 return true;
111#endif
112}
113
114// ----------------------------------------------------------------------------
115
116AudioFlinger::AudioFlinger()
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800117 : BnAudioFlinger(),
118 mAudioHardware(0), mA2dpAudioInterface(0),
119 mA2dpEnabled(false), mA2dpEnabledReq(false),
120 mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700121{
122 mHardwareStatus = AUDIO_HW_IDLE;
123 mAudioHardware = AudioHardwareInterface::create();
124 mHardwareStatus = AUDIO_HW_INIT;
125 if (mAudioHardware->initCheck() == NO_ERROR) {
126 // open 16-bit output stream for s/w mixer
127 mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800128 status_t status;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800129 AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700130 mHardwareStatus = AUDIO_HW_IDLE;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800131 if (hwOutput) {
132 mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700133 } else {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800134 LOGE("Failed to initialize hardware output stream, status: %d", status);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700135 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800136
137#ifdef WITH_A2DP
138 // Create A2DP interface
139 mA2dpAudioInterface = new A2dpAudioInterface();
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800140 AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
141 if (a2dpOutput) {
142 mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
143 if (hwOutput) {
144 uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
145 MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
146 hwOutput->sampleRate(),
147 AudioSystem::PCM_16_BIT,
148 hwOutput->channelCount(),
149 frameCount);
150 mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
151 }
152 } else {
153 LOGE("Failed to initialize A2DP output stream, status: %d", status);
154 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800155#endif
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800156
157 // FIXME - this should come from settings
158 setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
159 setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
160 setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
161 setMode(AudioSystem::MODE_NORMAL);
162
163 setMasterVolume(1.0f);
164 setMasterMute(false);
165
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800166 // Start record thread
167 mAudioRecordThread = new AudioRecordThread(mAudioHardware);
168 if (mAudioRecordThread != 0) {
169 mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
170 }
171 } else {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700172 LOGE("Couldn't even initialize the stubbed audio hardware!");
173 }
The Android Open Source Project43aa2b12009-03-03 14:04:24 -0800174
175 char value[PROPERTY_VALUE_MAX];
176 property_get("ro.audio.silent", value, "0");
177 if (atoi(value)) {
178 LOGD("Silence is golden");
179 setMasterMute(true);
180 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700181}
182
183AudioFlinger::~AudioFlinger()
184{
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800185 if (mAudioRecordThread != 0) {
186 mAudioRecordThread->exit();
187 mAudioRecordThread.clear();
188 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800189 mHardwareMixerThread.clear();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700190 delete mAudioHardware;
The Android Open Source Project27629322009-01-09 17:51:23 -0800191 // deleting mA2dpAudioInterface also deletes mA2dpOutput;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800192#ifdef WITH_A2DP
193 mA2dpMixerThread.clear();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800194 delete mA2dpAudioInterface;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800195#endif
The Android Open Source Project27629322009-01-09 17:51:23 -0800196}
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800197
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700198
The Android Open Source Projecte41dd752009-01-22 00:13:42 -0800199#ifdef WITH_A2DP
The Android Open Source Projecte41dd752009-01-22 00:13:42 -0800200void AudioFlinger::setA2dpEnabled(bool enable)
201{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800202 LOGV_IF(enable, "set output to A2DP\n");
203 LOGV_IF(!enable, "set output to hardware audio\n");
204
205 mA2dpEnabledReq = enable;
206 mA2dpMixerThread->wakeUp();
The Android Open Source Projecte41dd752009-01-22 00:13:42 -0800207}
208#endif // WITH_A2DP
209
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800210bool AudioFlinger::streamForcedToSpeaker(int streamType)
211{
212 // NOTE that streams listed here must not be routed to A2DP by default:
213 // AudioSystem::routedToA2dpOutput(streamType) == false
214 return (streamType == AudioSystem::RING ||
215 streamType == AudioSystem::ALARM ||
216 streamType == AudioSystem::NOTIFICATION);
217}
218
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700219status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
220{
221 const size_t SIZE = 256;
222 char buffer[SIZE];
223 String8 result;
224
225 result.append("Clients:\n");
226 for (size_t i = 0; i < mClients.size(); ++i) {
227 wp<Client> wClient = mClients.valueAt(i);
228 if (wClient != 0) {
229 sp<Client> client = wClient.promote();
230 if (client != 0) {
231 snprintf(buffer, SIZE, " pid: %d\n", client->pid());
232 result.append(buffer);
233 }
234 }
235 }
236 write(fd, result.string(), result.size());
237 return NO_ERROR;
238}
239
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700240
241status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
242{
243 const size_t SIZE = 256;
244 char buffer[SIZE];
245 String8 result;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800246
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700247 snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
248 result.append(buffer);
249 write(fd, result.string(), result.size());
250 return NO_ERROR;
251}
252
253status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
254{
255 const size_t SIZE = 256;
256 char buffer[SIZE];
257 String8 result;
258 snprintf(buffer, SIZE, "Permission Denial: "
259 "can't dump AudioFlinger from pid=%d, uid=%d\n",
260 IPCThreadState::self()->getCallingPid(),
261 IPCThreadState::self()->getCallingUid());
262 result.append(buffer);
263 write(fd, result.string(), result.size());
264 return NO_ERROR;
265}
266
267status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
268{
269 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
270 dumpPermissionDenial(fd, args);
271 } else {
272 AutoMutex lock(&mLock);
273
274 dumpClients(fd, args);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700275 dumpInternals(fd, args);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800276 mHardwareMixerThread->dump(fd, args);
277#ifdef WITH_A2DP
278 mA2dpMixerThread->dump(fd, args);
279#endif
280
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -0800281 // dump record client
282 if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
283
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700284 if (mAudioHardware) {
285 mAudioHardware->dumpState(fd, args);
286 }
287 }
288 return NO_ERROR;
289}
290
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700291// IAudioFlinger interface
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800292
293
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700294sp<IAudioTrack> AudioFlinger::createTrack(
295 pid_t pid,
296 int streamType,
297 uint32_t sampleRate,
298 int format,
299 int channelCount,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800300 int frameCount,
301 uint32_t flags,
302 const sp<IMemory>& sharedBuffer,
303 status_t *status)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700304{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800305 sp<MixerThread::Track> track;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700306 sp<TrackHandle> trackHandle;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700307 sp<Client> client;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800308 wp<Client> wclient;
309 status_t lStatus;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700310
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800311 if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800312 LOGE("invalid stream type");
313 lStatus = BAD_VALUE;
314 goto Exit;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700315 }
316
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800317 {
318 Mutex::Autolock _l(mLock);
319
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800320 wclient = mClients.valueFor(pid);
321
322 if (wclient != NULL) {
323 client = wclient.promote();
324 } else {
325 client = new Client(this, pid);
326 mClients.add(pid, client);
327 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800328#ifdef WITH_A2DP
329 if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
330 track = mA2dpMixerThread->createTrack(client, streamType, sampleRate, format,
331 channelCount, frameCount, sharedBuffer, &lStatus);
332 } else
333#endif
334 {
335 track = mHardwareMixerThread->createTrack(client, streamType, sampleRate, format,
336 channelCount, frameCount, sharedBuffer, &lStatus);
337 }
338 if (track != NULL) {
339 trackHandle = new TrackHandle(track);
340 lStatus = NO_ERROR;
341 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800342 }
343
344Exit:
345 if(status) {
346 *status = lStatus;
347 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700348 return trackHandle;
349}
350
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800351uint32_t AudioFlinger::sampleRate(int output) const
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700352{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800353#ifdef WITH_A2DP
354 if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
355 return mA2dpMixerThread->sampleRate();
356 }
357#endif
358 return mHardwareMixerThread->sampleRate();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700359}
360
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800361int AudioFlinger::channelCount(int output) const
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700362{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800363#ifdef WITH_A2DP
364 if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
365 return mA2dpMixerThread->channelCount();
366 }
367#endif
368 return mHardwareMixerThread->channelCount();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700369}
370
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800371int AudioFlinger::format(int output) const
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700372{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800373#ifdef WITH_A2DP
374 if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
375 return mA2dpMixerThread->format();
376 }
377#endif
378 return mHardwareMixerThread->format();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700379}
380
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800381size_t AudioFlinger::frameCount(int output) const
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700382{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800383#ifdef WITH_A2DP
384 if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
385 return mA2dpMixerThread->frameCount();
386 }
387#endif
388 return mHardwareMixerThread->frameCount();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700389}
390
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800391uint32_t AudioFlinger::latency(int output) const
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800392{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800393#ifdef WITH_A2DP
394 if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
395 return mA2dpMixerThread->latency();
396 }
397#endif
398 return mHardwareMixerThread->latency();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800399}
400
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700401status_t AudioFlinger::setMasterVolume(float value)
402{
403 // check calling permissions
404 if (!settingsAllowed()) {
405 return PERMISSION_DENIED;
406 }
407
408 // when hw supports master volume, don't scale in sw mixer
409 AutoMutex lock(mHardwareLock);
410 mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
411 if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800412 value = 1.0f;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700413 }
414 mHardwareStatus = AUDIO_HW_IDLE;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800415 mHardwareMixerThread->setMasterVolume(value);
416#ifdef WITH_A2DP
417 mA2dpMixerThread->setMasterVolume(value);
418#endif
419
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700420 return NO_ERROR;
421}
422
423status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
424{
The Android Open Source Project27629322009-01-09 17:51:23 -0800425 status_t err = NO_ERROR;
426
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700427 // check calling permissions
428 if (!settingsAllowed()) {
429 return PERMISSION_DENIED;
430 }
431 if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
432 LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
433 return BAD_VALUE;
434 }
435
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800436#ifdef WITH_A2DP
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800437 LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800438 if (mode == AudioSystem::MODE_NORMAL &&
439 (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
The Android Open Source Projecte41dd752009-01-22 00:13:42 -0800440 AutoMutex lock(&mLock);
441
442 bool enableA2dp = false;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800443 if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800444 enableA2dp = true;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800445 }
The Android Open Source Projecte41dd752009-01-22 00:13:42 -0800446 setA2dpEnabled(enableA2dp);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800447 LOGV("setOutput done\n");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800448 }
449#endif
450
The Android Open Source Project27629322009-01-09 17:51:23 -0800451 // do nothing if only A2DP routing is affected
452 mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
453 if (mask) {
454 AutoMutex lock(mHardwareLock);
455 mHardwareStatus = AUDIO_HW_GET_ROUTING;
456 uint32_t r;
457 err = mAudioHardware->getRouting(mode, &r);
458 if (err == NO_ERROR) {
459 r = (r & ~mask) | (routes & mask);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800460 if (mode == AudioSystem::MODE_NORMAL ||
461 (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
462 mSavedRoute = r;
463 r |= mForcedRoute;
464 LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
465 }
The Android Open Source Project27629322009-01-09 17:51:23 -0800466 mHardwareStatus = AUDIO_HW_SET_ROUTING;
467 err = mAudioHardware->setRouting(mode, r);
468 }
469 mHardwareStatus = AUDIO_HW_IDLE;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700470 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700471 return err;
472}
473
474uint32_t AudioFlinger::getRouting(int mode) const
475{
476 uint32_t routes = 0;
477 if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800478 if (mode == AudioSystem::MODE_NORMAL ||
479 (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
480 routes = mSavedRoute;
481 } else {
482 mHardwareStatus = AUDIO_HW_GET_ROUTING;
483 mAudioHardware->getRouting(mode, &routes);
484 mHardwareStatus = AUDIO_HW_IDLE;
485 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700486 } else {
487 LOGW("Illegal value: getRouting(%d)", mode);
488 }
489 return routes;
490}
491
492status_t AudioFlinger::setMode(int mode)
493{
494 // check calling permissions
495 if (!settingsAllowed()) {
496 return PERMISSION_DENIED;
497 }
498 if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
499 LOGW("Illegal value: setMode(%d)", mode);
500 return BAD_VALUE;
501 }
502
503 AutoMutex lock(mHardwareLock);
504 mHardwareStatus = AUDIO_HW_SET_MODE;
505 status_t ret = mAudioHardware->setMode(mode);
506 mHardwareStatus = AUDIO_HW_IDLE;
507 return ret;
508}
509
510int AudioFlinger::getMode() const
511{
512 int mode = AudioSystem::MODE_INVALID;
513 mHardwareStatus = AUDIO_HW_SET_MODE;
514 mAudioHardware->getMode(&mode);
515 mHardwareStatus = AUDIO_HW_IDLE;
516 return mode;
517}
518
519status_t AudioFlinger::setMicMute(bool state)
520{
521 // check calling permissions
522 if (!settingsAllowed()) {
523 return PERMISSION_DENIED;
524 }
525
526 AutoMutex lock(mHardwareLock);
527 mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
528 status_t ret = mAudioHardware->setMicMute(state);
529 mHardwareStatus = AUDIO_HW_IDLE;
530 return ret;
531}
532
533bool AudioFlinger::getMicMute() const
534{
535 bool state = AudioSystem::MODE_INVALID;
536 mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
537 mAudioHardware->getMicMute(&state);
538 mHardwareStatus = AUDIO_HW_IDLE;
539 return state;
540}
541
542status_t AudioFlinger::setMasterMute(bool muted)
543{
544 // check calling permissions
545 if (!settingsAllowed()) {
546 return PERMISSION_DENIED;
547 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800548 mHardwareMixerThread->setMasterMute(muted);
549#ifdef WITH_A2DP
550 mA2dpMixerThread->setMasterMute(muted);
551#endif
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700552 return NO_ERROR;
553}
554
555float AudioFlinger::masterVolume() const
556{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800557 return mHardwareMixerThread->masterVolume();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700558}
559
560bool AudioFlinger::masterMute() const
561{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800562 return mHardwareMixerThread->masterMute();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700563}
564
565status_t AudioFlinger::setStreamVolume(int stream, float value)
566{
567 // check calling permissions
568 if (!settingsAllowed()) {
569 return PERMISSION_DENIED;
570 }
571
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800572 if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700573 return BAD_VALUE;
574 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800575
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800576 mHardwareMixerThread->setStreamVolume(stream, value);
577#ifdef WITH_A2DP
578 mA2dpMixerThread->setStreamVolume(stream, value);
579#endif
580
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700581 status_t ret = NO_ERROR;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800582 if (stream == AudioSystem::VOICE_CALL ||
583 stream == AudioSystem::BLUETOOTH_SCO) {
584
585 if (stream == AudioSystem::VOICE_CALL) {
586 value = (float)AudioSystem::logToLinear(value)/100.0f;
587 } else { // (type == AudioSystem::BLUETOOTH_SCO)
588 value = 1.0f;
589 }
590
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700591 AutoMutex lock(mHardwareLock);
592 mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
593 ret = mAudioHardware->setVoiceVolume(value);
594 mHardwareStatus = AUDIO_HW_IDLE;
595 }
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800596
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700597 return ret;
598}
599
600status_t AudioFlinger::setStreamMute(int stream, bool muted)
601{
602 // check calling permissions
603 if (!settingsAllowed()) {
604 return PERMISSION_DENIED;
605 }
606
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800607 if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700608 return BAD_VALUE;
609 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800610
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800611#ifdef WITH_A2DP
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800612 mA2dpMixerThread->setStreamMute(stream, muted);
613#endif
614 if (stream == AudioSystem::MUSIC)
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800615 {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800616 AutoMutex lock(&mHardwareLock);
617 if (mForcedRoute != 0)
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800618 mMusicMuteSaved = muted;
619 else
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800620 mHardwareMixerThread->setStreamMute(stream, muted);
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800621 } else {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800622 mHardwareMixerThread->setStreamMute(stream, muted);
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800623 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800624
625
626
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700627 return NO_ERROR;
628}
629
630float AudioFlinger::streamVolume(int stream) const
631{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800632 if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700633 return 0.0f;
634 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800635 return mHardwareMixerThread->streamVolume(stream);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700636}
637
638bool AudioFlinger::streamMute(int stream) const
639{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800640 if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700641 return true;
642 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800643
644 if (stream == AudioSystem::MUSIC && mForcedRoute != 0)
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800645 {
646 return mMusicMuteSaved;
647 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800648 return mHardwareMixerThread->streamMute(stream);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700649}
650
651bool AudioFlinger::isMusicActive() const
652{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800653 #ifdef WITH_A2DP
654 if (isA2dpEnabled()) {
655 return mA2dpMixerThread->isMusicActive();
656 }
657 #endif
658 return mHardwareMixerThread->isMusicActive();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700659}
660
661status_t AudioFlinger::setParameter(const char* key, const char* value)
662{
The Android Open Source Project8a7a6752009-01-15 16:12:10 -0800663 status_t result, result2;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700664 AutoMutex lock(mHardwareLock);
665 mHardwareStatus = AUDIO_SET_PARAMETER;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800666
667 LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700668 result = mAudioHardware->setParameter(key, value);
The Android Open Source Project8a7a6752009-01-15 16:12:10 -0800669 if (mA2dpAudioInterface) {
670 result2 = mA2dpAudioInterface->setParameter(key, value);
671 if (result2)
672 result = result2;
673 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700674 mHardwareStatus = AUDIO_HW_IDLE;
675 return result;
676}
677
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800678size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
679{
680 return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
681}
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800682
683void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
684{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800685
686 LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800687 Mutex::Autolock _l(mLock);
688
689 sp<IBinder> binder = client->asBinder();
690 if (mNotificationClients.indexOf(binder) < 0) {
691 LOGV("Adding notification client %p", binder.get());
692 binder->linkToDeath(this);
693 mNotificationClients.add(binder);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800694 client->a2dpEnabledChanged(isA2dpEnabled());
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800695 }
696}
697
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800698void AudioFlinger::binderDied(const wp<IBinder>& who) {
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800699
700 LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800701 Mutex::Autolock _l(mLock);
702
703 IBinder *binder = who.unsafe_get();
704
705 if (binder != NULL) {
706 int index = mNotificationClients.indexOf(binder);
707 if (index >= 0) {
708 LOGV("Removing notification client %p", binder);
709 mNotificationClients.removeAt(index);
710 }
711 }
712}
713
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800714void AudioFlinger::handleOutputSwitch()
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800715{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800716 if (mA2dpEnabled != mA2dpEnabledReq)
717 {
718 Mutex::Autolock _l(mLock);
719
720 if (mA2dpEnabled != mA2dpEnabledReq)
721 {
722 mA2dpEnabled = mA2dpEnabledReq;
723 SortedVector < sp<MixerThread::Track> > tracks;
724 SortedVector < wp<MixerThread::Track> > activeTracks;
725
726 // We hold mA2dpMixerThread mLock already
727 Mutex::Autolock _l(mHardwareMixerThread->mLock);
728
729 // Transfer tracks playing on MUSIC stream from one mixer to the other
730 if (mA2dpEnabled) {
731 mHardwareMixerThread->getTracks(tracks, activeTracks);
732 mA2dpMixerThread->putTracks(tracks, activeTracks);
733 } else {
734 mA2dpMixerThread->getTracks(tracks, activeTracks);
735 mHardwareMixerThread->putTracks(tracks, activeTracks);
736 }
737
738 // Notify AudioSystem of the A2DP activation/deactivation
739 size_t size = mNotificationClients.size();
740 for (size_t i = 0; i < size; i++) {
741 sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
742 if (binder != NULL) {
743 LOGV("Notifying output change to client %p", binder.get());
744 sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
745 client->a2dpEnabledChanged(mA2dpEnabled);
746 }
747 }
748
749 mHardwareMixerThread->wakeUp();
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800750 }
751 }
752}
753
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700754void AudioFlinger::removeClient(pid_t pid)
755{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800756 LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700757 Mutex::Autolock _l(mLock);
758 mClients.removeItem(pid);
759}
760
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800761void AudioFlinger::wakeUp()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700762{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -0800763 mHardwareMixerThread->wakeUp();
764#ifdef WITH_A2DP
765 mA2dpMixerThread->wakeUp();
766#endif // WITH_A2DP
767}
768
769bool AudioFlinger::isA2dpEnabled() const
770{
771 return mA2dpEnabledReq;
772}
773
774void AudioFlinger::handleForcedSpeakerRoute(int command)
775{
776 switch(command) {
777 case ACTIVE_TRACK_ADDED:
778 {
779 AutoMutex lock(mHardwareLock);
780 if (mForcedSpeakerCount++ == 0) {
781 mRouteRestoreTime = 0;
782 mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
783 if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
784 LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
785 mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
786 mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
787 mAudioHardware->setMasterVolume(0);
788 usleep(mHardwareMixerThread->latency()*1000);
789 mHardwareStatus = AUDIO_HW_SET_ROUTING;
790 mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
791 mHardwareStatus = AUDIO_HW_IDLE;
792 // delay track start so that audio hardware has time to siwtch routes
793 usleep(kStartSleepTime);
794 mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
795 mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
796 mHardwareStatus = AUDIO_HW_IDLE;
797 }
798 mForcedRoute = AudioSystem::ROUTE_SPEAKER;
799 }
800 LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
801 }
802 break;
803 case ACTIVE_TRACK_REMOVED:
804 {
805 AutoMutex lock(mHardwareLock);
806 if (mForcedSpeakerCount > 0){
807 if (--mForcedSpeakerCount == 0) {
808 mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
809 }
810 LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
811 } else {
812 LOGE("mForcedSpeakerCount is already zero");
813 }
814 }
815 break;
816 case CHECK_ROUTE_RESTORE_TIME:
817 case FORCE_ROUTE_RESTORE:
818 if (mRouteRestoreTime) {
819 AutoMutex lock(mHardwareLock);
820 if (mRouteRestoreTime &&
821 (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
822 mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
823 mForcedRoute = 0;
824 if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
825 mHardwareStatus = AUDIO_HW_SET_ROUTING;
826 mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
827 mHardwareStatus = AUDIO_HW_IDLE;
828 LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
829 }
830 mRouteRestoreTime = 0;
831 }
832 }
833 break;
834 }
835}
836
837
838// ----------------------------------------------------------------------------
839
840AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
841 : Thread(false),
842 mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType),
843 mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
844 mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
845 mInWrite(false)
846{
847 mSampleRate = output->sampleRate();
848 mChannelCount = output->channelCount();
849
850 // FIXME - Current mixer implementation only supports stereo output
851 if (mChannelCount == 1) {
852 LOGE("Invalid audio hardware channel count");
853 }
854
855 mFormat = output->format();
856 mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
857 mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
858
859 // FIXME - Current mixer implementation only supports stereo output: Always
860 // Allocate a stereo buffer even if HW output is mono.
861 mMixBuffer = new int16_t[mFrameCount * 2];
862 memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
863}
864
865AudioFlinger::MixerThread::~MixerThread()
866{
867 delete [] mMixBuffer;
868 delete mAudioMixer;
869}
870
871status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
872{
873 dumpInternals(fd, args);
874 dumpTracks(fd, args);
875 return NO_ERROR;
876}
877
878status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
879{
880 const size_t SIZE = 256;
881 char buffer[SIZE];
882 String8 result;
883
884 snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
885 result.append(buffer);
886 result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
887 for (size_t i = 0; i < mTracks.size(); ++i) {
888 wp<Track> wTrack = mTracks[i];
889 if (wTrack != 0) {
890 sp<Track> track = wTrack.promote();
891 if (track != 0) {
892 track->dump(buffer, SIZE);
893 result.append(buffer);
894 }
895 }
896 }
897
898 snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
899 result.append(buffer);
900 result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
901 for (size_t i = 0; i < mActiveTracks.size(); ++i) {
902 wp<Track> wTrack = mTracks[i];
903 if (wTrack != 0) {
904 sp<Track> track = wTrack.promote();
905 if (track != 0) {
906 track->dump(buffer, SIZE);
907 result.append(buffer);
908 }
909 }
910 }
911 write(fd, result.string(), result.size());
912 return NO_ERROR;
913}
914
915status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
916{
917 const size_t SIZE = 256;
918 char buffer[SIZE];
919 String8 result;
920
921 snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
922 result.append(buffer);
923 snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
924 result.append(buffer);
925 snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
926 result.append(buffer);
927 snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
928 result.append(buffer);
929 snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
930 result.append(buffer);
931 snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
932 result.append(buffer);
933 snprintf(buffer, SIZE, "standby: %d\n", mStandby);
934 result.append(buffer);
935 write(fd, result.string(), result.size());
936 return NO_ERROR;
937}
938
939// Thread virtuals
940bool AudioFlinger::MixerThread::threadLoop()
941{
942 unsigned long sleepTime = kBufferRecoveryInUsecs;
943 int16_t* curBuf = mMixBuffer;
944 Vector< sp<Track> > tracksToRemove;
945 size_t enabledTracks = 0;
946 nsecs_t standbyTime = systemTime();
947 size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
948 nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
949
950#ifdef WITH_A2DP
951 bool outputTrackActive = false;
952#endif
953
954 do {
955 enabledTracks = 0;
956 { // scope for the mLock
957
958 Mutex::Autolock _l(mLock);
959
960#ifdef WITH_A2DP
961 if (mOutputType == AudioSystem::AUDIO_OUTPUT_A2DP) {
962 mAudioFlinger->handleOutputSwitch();
963 }
964 if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
965 if (outputTrackActive) {
966 mOutputTrack->stop();
967 outputTrackActive = false;
968 }
969 }
970#endif
971
972 const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
973
974 // put audio hardware into standby after short delay
975 if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
976 // wait until we have something to do...
977 LOGV("Audio hardware entering standby, output %d\n", mOutputType);
978// mAudioFlinger->mHardwareStatus = AUDIO_HW_STANDBY;
979 if (!mStandby) {
980 mOutput->standby();
981 mStandby = true;
982 }
983
984#ifdef WITH_A2DP
985 if (outputTrackActive) {
986 mOutputTrack->stop();
987 outputTrackActive = false;
988 }
989#endif
990 if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
991 mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
992 }
993// mHardwareStatus = AUDIO_HW_IDLE;
994 // we're about to wait, flush the binder command buffer
995 IPCThreadState::self()->flushCommands();
996 mWaitWorkCV.wait(mLock);
997 LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
998 standbyTime = systemTime() + kStandbyTimeInNsecs;
999 continue;
1000 }
1001
1002 // Forced route to speaker is handled by hardware mixer thread
1003 if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
1004 mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
1005 }
1006
1007 // find out which tracks need to be processed
1008 size_t count = activeTracks.size();
1009 for (size_t i=0 ; i<count ; i++) {
1010 sp<Track> t = activeTracks[i].promote();
1011 if (t == 0) continue;
1012
1013 Track* const track = t.get();
1014 audio_track_cblk_t* cblk = track->cblk();
1015
1016 // The first time a track is added we wait
1017 // for all its buffers to be filled before processing it
1018 mAudioMixer->setActiveTrack(track->name());
1019 if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
1020 !track->isPaused())
1021 {
1022 //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
1023
1024 // compute volume for this track
1025 int16_t left, right;
1026 if (track->isMuted() || mMasterMute || track->isPausing()) {
1027 left = right = 0;
1028 if (track->isPausing()) {
1029 LOGV("paused(%d)", track->name());
1030 track->setPaused();
1031 }
1032 } else {
1033 float typeVolume = mStreamTypes[track->type()].volume;
1034 float v = mMasterVolume * typeVolume;
1035 float v_clamped = v * cblk->volume[0];
1036 if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
1037 left = int16_t(v_clamped);
1038 v_clamped = v * cblk->volume[1];
1039 if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
1040 right = int16_t(v_clamped);
1041 }
1042
1043 // XXX: these things DON'T need to be done each time
1044 mAudioMixer->setBufferProvider(track);
1045 mAudioMixer->enable(AudioMixer::MIXING);
1046
1047 int param;
1048 if ( track->mFillingUpStatus == Track::FS_FILLED) {
1049 // no ramp for the first volume setting
1050 track->mFillingUpStatus = Track::FS_ACTIVE;
1051 if (track->mState == TrackBase::RESUMING) {
1052 track->mState = TrackBase::ACTIVE;
1053 param = AudioMixer::RAMP_VOLUME;
1054 } else {
1055 param = AudioMixer::VOLUME;
1056 }
1057 } else {
1058 param = AudioMixer::RAMP_VOLUME;
1059 }
1060 mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
1061 mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
1062 mAudioMixer->setParameter(
1063 AudioMixer::TRACK,
1064 AudioMixer::FORMAT, track->format());
1065 mAudioMixer->setParameter(
1066 AudioMixer::TRACK,
1067 AudioMixer::CHANNEL_COUNT, track->channelCount());
1068 mAudioMixer->setParameter(
1069 AudioMixer::RESAMPLE,
1070 AudioMixer::SAMPLE_RATE,
1071 int(cblk->sampleRate));
1072
1073 // reset retry count
1074 track->mRetryCount = kMaxTrackRetries;
1075 enabledTracks++;
1076 } else {
1077 //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
1078 if (track->isStopped()) {
1079 track->reset();
1080 }
1081 if (track->isTerminated() || track->isStopped() || track->isPaused()) {
1082 // We have consumed all the buffers of this track.
1083 // Remove it from the list of active tracks.
1084 LOGV("remove(%d) from active list", track->name());
1085 tracksToRemove.add(track);
1086 } else {
1087 // No buffers for this track. Give it a few chances to
1088 // fill a buffer, then remove it from active list.
1089 if (--(track->mRetryCount) <= 0) {
1090 LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
1091 tracksToRemove.add(track);
1092 }
1093 }
1094 // LOGV("disable(%d)", track->name());
1095 mAudioMixer->disable(AudioMixer::MIXING);
1096 }
1097 }
1098
1099 // remove all the tracks that need to be...
1100 count = tracksToRemove.size();
1101 if (UNLIKELY(count)) {
1102 for (size_t i=0 ; i<count ; i++) {
1103 const sp<Track>& track = tracksToRemove[i];
1104 removeActiveTrack(track);
1105 if (track->isTerminated()) {
1106 mTracks.remove(track);
1107 deleteTrackName(track->mName);
1108 }
1109 }
1110 }
1111 }
1112
1113 if (LIKELY(enabledTracks)) {
1114 // mix buffers...
1115 mAudioMixer->process(curBuf);
1116
1117#ifdef WITH_A2DP
1118 if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
1119 if (!outputTrackActive) {
1120 LOGV("starting output track in mixer for output %d", mOutputType);
1121 mOutputTrack->start();
1122 outputTrackActive = true;
1123 }
1124 mOutputTrack->write(curBuf, mFrameCount);
1125 }
1126#endif
1127
1128 // output audio to hardware
1129 mLastWriteTime = systemTime();
1130 mInWrite = true;
1131 mOutput->write(curBuf, mixBufferSize);
1132 mNumWrites++;
1133 mInWrite = false;
1134 mStandby = false;
1135 nsecs_t temp = systemTime();
1136 standbyTime = temp + kStandbyTimeInNsecs;
1137 nsecs_t delta = temp - mLastWriteTime;
1138 if (delta > maxPeriod) {
1139 LOGW("write blocked for %llu msecs", ns2ms(delta));
1140 mNumDelayedWrites++;
1141 }
1142 sleepTime = kBufferRecoveryInUsecs;
1143 } else {
1144#ifdef WITH_A2DP
1145 if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
1146 if (outputTrackActive) {
1147 mOutputTrack->write(curBuf, 0);
1148 if (mOutputTrack->bufferQueueEmpty()) {
1149 mOutputTrack->stop();
1150 outputTrackActive = false;
1151 } else {
1152 standbyTime = systemTime() + kStandbyTimeInNsecs;
1153 }
1154 }
1155 }
1156#endif
1157 // There was nothing to mix this round, which means all
1158 // active tracks were late. Sleep a little bit to give
1159 // them another chance. If we're too late, the audio
1160 // hardware will zero-fill for us.
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001161 //LOGV("no buffers - usleep(%lu)", sleepTime);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001162 usleep(sleepTime);
1163 if (sleepTime < kMaxBufferRecoveryInUsecs) {
1164 sleepTime += kBufferRecoveryInUsecs;
1165 }
1166 }
1167
1168 // finally let go of all our tracks, without the lock held
1169 // since we can't guarantee the destructors won't acquire that
1170 // same lock.
1171 tracksToRemove.clear();
1172 } while (true);
1173
1174 return false;
1175}
1176
1177status_t AudioFlinger::MixerThread::readyToRun()
1178{
1179 if (mSampleRate == 0) {
1180 LOGE("No working audio driver found.");
1181 return NO_INIT;
1182 }
1183 LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
1184 return NO_ERROR;
1185}
1186
1187void AudioFlinger::MixerThread::onFirstRef()
1188{
1189 const size_t SIZE = 256;
1190 char buffer[SIZE];
1191
1192 snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
1193
1194 run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
1195}
1196
1197
1198sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack(
1199 const sp<AudioFlinger::Client>& client,
1200 int streamType,
1201 uint32_t sampleRate,
1202 int format,
1203 int channelCount,
1204 int frameCount,
1205 const sp<IMemory>& sharedBuffer,
1206 status_t *status)
1207{
1208 sp<Track> track;
1209 status_t lStatus;
1210
1211 // Resampler implementation limits input sampling rate to 2 x output sampling rate.
1212 if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
1213 LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
1214 lStatus = BAD_VALUE;
1215 goto Exit;
1216 }
1217
1218 {
1219 Mutex::Autolock _l(mLock);
1220
1221 if (mSampleRate == 0) {
1222 LOGE("Audio driver not initialized.");
1223 lStatus = NO_INIT;
1224 goto Exit;
1225 }
1226
1227 track = new Track(this, client, streamType, sampleRate, format,
1228 channelCount, frameCount, sharedBuffer);
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001229 if (track->getCblk() == NULL) {
1230 track.clear();
1231 lStatus = NO_MEMORY;
1232 goto Exit;
1233 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001234 mTracks.add(track);
1235 lStatus = NO_ERROR;
1236 }
1237
1238Exit:
1239 if(status) {
1240 *status = lStatus;
1241 }
1242 return track;
1243}
1244
1245void AudioFlinger::MixerThread::getTracks(
1246 SortedVector < sp<Track> >& tracks,
1247 SortedVector < wp<Track> >& activeTracks)
1248{
1249 size_t size = mTracks.size();
1250 LOGV ("MixerThread::getTracks() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size());
1251 for (size_t i = 0; i < size; i++) {
1252 sp<Track> t = mTracks[i];
1253 if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
1254 tracks.add(t);
1255 int j = mActiveTracks.indexOf(t);
1256 if (j >= 0) {
1257 t = mActiveTracks[j].promote();
1258 if (t != NULL) {
1259 activeTracks.add(t);
1260 }
1261 }
1262 }
1263 }
1264
1265 size = activeTracks.size();
1266 for (size_t i = 0; i < size; i++) {
1267 removeActiveTrack(activeTracks[i]);
1268 }
1269
1270 size = tracks.size();
1271 for (size_t i = 0; i < size; i++) {
1272 sp<Track> t = tracks[i];
1273 mTracks.remove(t);
1274 deleteTrackName(t->name());
1275 }
1276}
1277
1278void AudioFlinger::MixerThread::putTracks(
1279 SortedVector < sp<Track> >& tracks,
1280 SortedVector < wp<Track> >& activeTracks)
1281{
1282
1283 LOGV ("MixerThread::putTracks() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size());
1284
1285 size_t size = tracks.size();
1286 for (size_t i = 0; i < size ; i++) {
1287 sp<Track> t = tracks[i];
1288 int name = getTrackName();
1289
1290 if (name < 0) return;
1291
1292 t->mName = name;
1293 t->mMixerThread = this;
1294 mTracks.add(t);
1295
1296 int j = activeTracks.indexOf(t);
1297 if (j >= 0) {
1298 addActiveTrack(t);
1299 }
1300 }
1301}
1302
1303uint32_t AudioFlinger::MixerThread::sampleRate() const
1304{
1305 return mSampleRate;
1306}
1307
1308int AudioFlinger::MixerThread::channelCount() const
1309{
1310 return mChannelCount;
1311}
1312
1313int AudioFlinger::MixerThread::format() const
1314{
1315 return mFormat;
1316}
1317
1318size_t AudioFlinger::MixerThread::frameCount() const
1319{
1320 return mFrameCount;
1321}
1322
1323uint32_t AudioFlinger::MixerThread::latency() const
1324{
1325 if (mOutput) {
1326 return mOutput->latency();
1327 }
1328 else {
1329 return 0;
1330 }
1331}
1332
1333status_t AudioFlinger::MixerThread::setMasterVolume(float value)
1334{
1335 mMasterVolume = value;
1336 return NO_ERROR;
1337}
1338
1339status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
1340{
1341 mMasterMute = muted;
1342 return NO_ERROR;
1343}
1344
1345float AudioFlinger::MixerThread::masterVolume() const
1346{
1347 return mMasterVolume;
1348}
1349
1350bool AudioFlinger::MixerThread::masterMute() const
1351{
1352 return mMasterMute;
1353}
1354
1355status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
1356{
1357 mStreamTypes[stream].volume = value;
1358 return NO_ERROR;
1359}
1360
1361status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
1362{
1363 mStreamTypes[stream].mute = muted;
1364 return NO_ERROR;
1365}
1366
1367float AudioFlinger::MixerThread::streamVolume(int stream) const
1368{
1369 return mStreamTypes[stream].volume;
1370}
1371
1372bool AudioFlinger::MixerThread::streamMute(int stream) const
1373{
1374 return mStreamTypes[stream].mute;
1375}
1376
1377bool AudioFlinger::MixerThread::isMusicActive() const
1378{
1379 size_t count = mActiveTracks.size();
1380 for (size_t i = 0 ; i < count ; ++i) {
1381 sp<Track> t = mActiveTracks[i].promote();
1382 if (t == 0) continue;
1383 Track* const track = t.get();
1384 if (t->mStreamType == AudioSystem::MUSIC)
1385 return true;
1386 }
1387 return false;
1388}
1389
1390status_t AudioFlinger::MixerThread::addTrack(const sp<Track>& track)
1391{
1392 status_t status = ALREADY_EXISTS;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001393 Mutex::Autolock _l(mLock);
1394
1395 // here the track could be either new, or restarted
1396 // in both cases "unstop" the track
1397 if (track->isPaused()) {
1398 track->mState = TrackBase::RESUMING;
1399 LOGV("PAUSED => RESUMING (%d)", track->name());
1400 } else {
1401 track->mState = TrackBase::ACTIVE;
1402 LOGV("? => ACTIVE (%d)", track->name());
1403 }
1404 // set retry count for buffer fill
1405 track->mRetryCount = kMaxTrackStartupRetries;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001406 if (mActiveTracks.indexOf(track) < 0) {
1407 // the track is newly added, make sure it fills up all its
1408 // buffers before playing. This is to ensure the client will
1409 // effectively get the latency it requested.
1410 track->mFillingUpStatus = Track::FS_FILLING;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001411 track->mResetDone = false;
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001412 addActiveTrack(track);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001413 status = NO_ERROR;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001414 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001415
1416 LOGV("mWaitWorkCV.broadcast");
1417 mWaitWorkCV.broadcast();
1418
1419 return status;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001420}
1421
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001422void AudioFlinger::MixerThread::removeTrack(wp<Track> track, int name)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001423{
1424 Mutex::Autolock _l(mLock);
1425 sp<Track> t = track.promote();
1426 if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
1427 remove_track_l(track, name);
1428 }
1429}
1430
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001431void AudioFlinger::MixerThread::remove_track_l(wp<Track> track, int name)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001432{
1433 sp<Track> t = track.promote();
1434 if (t!=NULL) {
1435 t->reset();
1436 }
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001437 deleteTrackName(name);
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001438 removeActiveTrack(track);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001439 mWaitWorkCV.broadcast();
1440}
1441
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001442void AudioFlinger::MixerThread::destroyTrack(const sp<Track>& track)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001443{
1444 // NOTE: We're acquiring a strong reference on the track before
1445 // acquiring the lock, this is to make sure removing it from
1446 // mTracks won't cause the destructor to be called while the lock is
1447 // held (note that technically, 'track' could be a reference to an item
1448 // in mTracks, which is why we need to do this).
1449 sp<Track> keep(track);
1450 Mutex::Autolock _l(mLock);
1451 track->mState = TrackBase::TERMINATED;
1452 if (mActiveTracks.indexOf(track) < 0) {
1453 LOGV("remove track (%d) and delete from mixer", track->name());
1454 mTracks.remove(track);
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001455 deleteTrackName(keep->name());
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001456 }
1457}
1458
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001459
1460void AudioFlinger::MixerThread::addActiveTrack(const wp<Track>& t)
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001461{
1462 mActiveTracks.add(t);
1463
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001464 // Force routing to speaker for certain stream types
1465 // The forced routing to speaker is managed by hardware mixer
1466 if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
1467 sp<Track> track = t.promote();
1468 if (track == NULL) return;
1469
1470 if (streamForcedToSpeaker(track->type())) {
1471 mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
1472 }
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001473 }
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001474}
1475
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001476void AudioFlinger::MixerThread::removeActiveTrack(const wp<Track>& t)
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001477{
1478 mActiveTracks.remove(t);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001479
1480 // Force routing to speaker for certain stream types
1481 // The forced routing to speaker is managed by hardware mixer
1482 if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
1483 sp<Track> track = t.promote();
1484 if (track == NULL) return;
1485
1486 if (streamForcedToSpeaker(track->type())) {
1487 mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
1488 }
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001489 }
The Android Open Source Projecte41dd752009-01-22 00:13:42 -08001490}
1491
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001492int AudioFlinger::MixerThread::getTrackName()
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001493{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001494 return mAudioMixer->getTrackName();
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001495}
1496
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001497void AudioFlinger::MixerThread::deleteTrackName(int name)
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001498{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001499 mAudioMixer->deleteTrackName(name);
1500}
1501
1502size_t AudioFlinger::MixerThread::getOutputFrameCount()
1503{
1504 return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001505}
1506
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001507// ----------------------------------------------------------------------------
1508
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001509AudioFlinger::MixerThread::TrackBase::TrackBase(
1510 const sp<MixerThread>& mixerThread,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001511 const sp<Client>& client,
1512 int streamType,
1513 uint32_t sampleRate,
1514 int format,
1515 int channelCount,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001516 int frameCount,
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001517 uint32_t flags,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001518 const sp<IMemory>& sharedBuffer)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001519 : RefBase(),
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001520 mMixerThread(mixerThread),
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001521 mClient(client),
1522 mStreamType(streamType),
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001523 mFrameCount(0),
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001524 mState(IDLE),
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001525 mClientTid(-1),
1526 mFormat(format),
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001527 mFlags(flags & ~SYSTEM_FLAGS_MASK)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001528{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001529 mName = mixerThread->getTrackName();
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001530 LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001531 if (mName < 0) {
1532 LOGE("no more track names availlable");
1533 return;
1534 }
1535
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001536 LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
1537
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001538 // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001539 size_t size = sizeof(audio_track_cblk_t);
1540 size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
1541 if (sharedBuffer == 0) {
1542 size += bufferSize;
1543 }
1544
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001545 if (client != NULL) {
1546 mCblkMemory = client->heap()->allocate(size);
1547 if (mCblkMemory != 0) {
1548 mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
1549 if (mCblk) { // construct the shared structure in-place.
1550 new(mCblk) audio_track_cblk_t();
1551 // clear all buffers
1552 mCblk->frameCount = frameCount;
1553 mCblk->sampleRate = sampleRate;
1554 mCblk->channels = channelCount;
1555 if (sharedBuffer == 0) {
1556 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
1557 memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
1558 // Force underrun condition to avoid false underrun callback until first data is
1559 // written to buffer
1560 mCblk->flowControlFlag = 1;
1561 } else {
1562 mBuffer = sharedBuffer->pointer();
1563 }
1564 mBufferEnd = (uint8_t *)mBuffer + bufferSize;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001565 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001566 } else {
1567 LOGE("not enough memory for AudioTrack size=%u", size);
1568 client->heap()->dump("AudioTrack");
1569 return;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001570 }
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001571 } else {
1572 mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
1573 if (mCblk) { // construct the shared structure in-place.
1574 new(mCblk) audio_track_cblk_t();
1575 // clear all buffers
1576 mCblk->frameCount = frameCount;
1577 mCblk->sampleRate = sampleRate;
1578 mCblk->channels = channelCount;
1579 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
1580 memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
1581 // Force underrun condition to avoid false underrun callback until first data is
1582 // written to buffer
1583 mCblk->flowControlFlag = 1;
1584 mBufferEnd = (uint8_t *)mBuffer + bufferSize;
1585 }
1586 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001587}
1588
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001589AudioFlinger::MixerThread::TrackBase::~TrackBase()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001590{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001591 if (mCblk) {
1592 mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
1593 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001594 mCblkMemory.clear(); // and free the shared memory
1595 mClient.clear();
1596}
1597
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001598void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001599{
1600 buffer->raw = 0;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001601 mFrameCount = buffer->frameCount;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001602 step();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001603 buffer->frameCount = 0;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001604}
1605
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001606bool AudioFlinger::MixerThread::TrackBase::step() {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001607 bool result;
1608 audio_track_cblk_t* cblk = this->cblk();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001609
1610 result = cblk->stepServer(mFrameCount);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001611 if (!result) {
1612 LOGV("stepServer failed acquiring cblk mutex");
1613 mFlags |= STEPSERVER_FAILED;
1614 }
1615 return result;
1616}
1617
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001618void AudioFlinger::MixerThread::TrackBase::reset() {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001619 audio_track_cblk_t* cblk = this->cblk();
1620
1621 cblk->user = 0;
1622 cblk->server = 0;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001623 cblk->userBase = 0;
1624 cblk->serverBase = 0;
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001625 mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001626 LOGV("TrackBase::reset");
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001627}
1628
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001629sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001630{
1631 return mCblkMemory;
1632}
1633
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001634int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001635 return mCblk->sampleRate;
1636}
1637
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001638int AudioFlinger::MixerThread::TrackBase::channelCount() const {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001639 return mCblk->channels;
1640}
1641
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001642void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001643 audio_track_cblk_t* cblk = this->cblk();
1644 int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
1645 int16_t *bufferEnd = bufferStart + frames * cblk->channels;
1646
1647 // Check validity of returned pointer in case the track control block would have been corrupted.
1648 if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) {
1649 LOGW("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \
1650 server %d, serverBase %d, user %d, userBase %d",
1651 bufferStart, bufferEnd, mBuffer, mBufferEnd,
1652 cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
1653 return 0;
1654 }
1655
1656 return bufferStart;
1657}
1658
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001659// ----------------------------------------------------------------------------
1660
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001661AudioFlinger::MixerThread::Track::Track(
1662 const sp<MixerThread>& mixerThread,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001663 const sp<Client>& client,
1664 int streamType,
1665 uint32_t sampleRate,
1666 int format,
1667 int channelCount,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001668 int frameCount,
1669 const sp<IMemory>& sharedBuffer)
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001670 : TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001671{
1672 mVolume[0] = 1.0f;
1673 mVolume[1] = 1.0f;
1674 mMute = false;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001675 mSharedBuffer = sharedBuffer;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001676}
1677
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001678AudioFlinger::MixerThread::Track::~Track()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001679{
1680 wp<Track> weak(this); // never create a strong ref from the dtor
1681 mState = TERMINATED;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001682 mMixerThread->removeTrack(weak, mName);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001683}
1684
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001685void AudioFlinger::MixerThread::Track::destroy()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001686{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001687 mMixerThread->destroyTrack(this);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001688}
1689
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001690void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001691{
1692 snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
1693 mName - AudioMixer::TRACK0,
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001694 (mClient == NULL) ? getpid() : mClient->pid(),
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001695 mStreamType,
1696 mFormat,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001697 mCblk->channels,
1698 mFrameCount,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001699 mState,
1700 mMute,
1701 mFillingUpStatus,
1702 mCblk->sampleRate,
1703 mCblk->volume[0],
1704 mCblk->volume[1],
1705 mCblk->server,
1706 mCblk->user);
1707}
1708
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001709status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001710{
1711 audio_track_cblk_t* cblk = this->cblk();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001712 uint32_t framesReady;
1713 uint32_t framesReq = buffer->frameCount;
1714
1715 // Check if last stepServer failed, try to step now
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001716 if (mFlags & TrackBase::STEPSERVER_FAILED) {
1717 if (!step()) goto getNextBuffer_exit;
1718 LOGV("stepServer recovered");
1719 mFlags &= ~TrackBase::STEPSERVER_FAILED;
1720 }
1721
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001722 framesReady = cblk->framesReady();
1723
1724 if (LIKELY(framesReady)) {
1725 uint32_t s = cblk->server;
1726 uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
1727
1728 bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
1729 if (framesReq > framesReady) {
1730 framesReq = framesReady;
1731 }
1732 if (s + framesReq > bufferEnd) {
1733 framesReq = bufferEnd - s;
1734 }
1735
1736 buffer->raw = getBuffer(s, framesReq);
1737 if (buffer->raw == 0) goto getNextBuffer_exit;
1738
1739 buffer->frameCount = framesReq;
1740 return NO_ERROR;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001741 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001742
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001743getNextBuffer_exit:
1744 buffer->raw = 0;
1745 buffer->frameCount = 0;
1746 return NOT_ENOUGH_DATA;
1747}
1748
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001749bool AudioFlinger::MixerThread::Track::isReady() const {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001750 if (mFillingUpStatus != FS_FILLING) return true;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001751
1752 if (mCblk->framesReady() >= mCblk->frameCount ||
1753 mCblk->forceReady) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001754 mFillingUpStatus = FS_FILLED;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001755 mCblk->forceReady = 0;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001756 LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001757 return true;
1758 }
1759 return false;
1760}
1761
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001762status_t AudioFlinger::MixerThread::Track::start()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001763{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001764 LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
1765 mMixerThread->addTrack(this);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001766 return NO_ERROR;
1767}
1768
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001769void AudioFlinger::MixerThread::Track::stop()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001770{
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001771 LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
1772 Mutex::Autolock _l(mMixerThread->mLock);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001773 if (mState > STOPPED) {
1774 mState = STOPPED;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001775 // If the track is not active (PAUSED and buffers full), flush buffers
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001776 if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001777 reset();
1778 }
1779 LOGV("(> STOPPED) => STOPPED (%d)", mName);
1780 }
1781}
1782
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001783void AudioFlinger::MixerThread::Track::pause()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001784{
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001785 LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001786 Mutex::Autolock _l(mMixerThread->mLock);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001787 if (mState == ACTIVE || mState == RESUMING) {
1788 mState = PAUSING;
1789 LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
1790 }
1791}
1792
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001793void AudioFlinger::MixerThread::Track::flush()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001794{
1795 LOGV("flush(%d)", mName);
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001796 Mutex::Autolock _l(mMixerThread->mLock);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001797 if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
1798 return;
1799 }
1800 // No point remaining in PAUSED state after a flush => go to
1801 // STOPPED state
1802 mState = STOPPED;
1803
1804 // NOTE: reset() will reset cblk->user and cblk->server with
1805 // the risk that at the same time, the AudioMixer is trying to read
1806 // data. In this case, getNextBuffer() would return a NULL pointer
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001807 // as audio buffer => the AudioMixer code MUST always test that pointer
1808 // returned by getNextBuffer() is not NULL!
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001809 reset();
1810}
1811
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001812void AudioFlinger::MixerThread::Track::reset()
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001813{
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001814 // Do not reset twice to avoid discarding data written just after a flush and before
1815 // the audioflinger thread detects the track is stopped.
1816 if (!mResetDone) {
1817 TrackBase::reset();
1818 // Force underrun condition to avoid false underrun callback until first data is
1819 // written to buffer
1820 mCblk->flowControlFlag = 1;
1821 mCblk->forceReady = 0;
1822 mFillingUpStatus = FS_FILLING;
1823 mResetDone = true;
1824 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001825}
1826
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001827void AudioFlinger::MixerThread::Track::mute(bool muted)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001828{
1829 mMute = muted;
1830}
1831
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001832void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001833{
1834 mVolume[0] = left;
1835 mVolume[1] = right;
1836}
1837
1838// ----------------------------------------------------------------------------
1839
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001840AudioFlinger::MixerThread::RecordTrack::RecordTrack(
1841 const sp<MixerThread>& mixerThread,
1842 const sp<Client>& client,
1843 int streamType,
1844 uint32_t sampleRate,
1845 int format,
1846 int channelCount,
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001847 int frameCount,
1848 uint32_t flags)
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001849 : TrackBase(mixerThread, client, streamType, sampleRate, format,
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08001850 channelCount, frameCount, flags, 0),
1851 mOverflow(false)
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08001852{
1853}
1854
1855AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
1856{
1857 mMixerThread->deleteTrackName(mName);
1858}
1859
1860status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
1861{
1862 audio_track_cblk_t* cblk = this->cblk();
1863 uint32_t framesAvail;
1864 uint32_t framesReq = buffer->frameCount;
1865
1866 // Check if last stepServer failed, try to step now
1867 if (mFlags & TrackBase::STEPSERVER_FAILED) {
1868 if (!step()) goto getNextBuffer_exit;
1869 LOGV("stepServer recovered");
1870 mFlags &= ~TrackBase::STEPSERVER_FAILED;
1871 }
1872
1873 framesAvail = cblk->framesAvailable_l();
1874
1875 if (LIKELY(framesAvail)) {
1876 uint32_t s = cblk->server;
1877 uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
1878
1879 if (framesReq > framesAvail) {
1880 framesReq = framesAvail;
1881 }
1882 if (s + framesReq > bufferEnd) {
1883 framesReq = bufferEnd - s;
1884 }
1885
1886 buffer->raw = getBuffer(s, framesReq);
1887 if (buffer->raw == 0) goto getNextBuffer_exit;
1888
1889 buffer->frameCount = framesReq;
1890 return NO_ERROR;
1891 }
1892
1893getNextBuffer_exit:
1894 buffer->raw = 0;
1895 buffer->frameCount = 0;
1896 return NOT_ENOUGH_DATA;
1897}
1898
1899status_t AudioFlinger::MixerThread::RecordTrack::start()
1900{
1901 return mMixerThread->mAudioFlinger->startRecord(this);
1902}
1903
1904void AudioFlinger::MixerThread::RecordTrack::stop()
1905{
1906 mMixerThread->mAudioFlinger->stopRecord(this);
1907 TrackBase::reset();
1908 // Force overerrun condition to avoid false overrun callback until first data is
1909 // read from buffer
1910 mCblk->flowControlFlag = 1;
1911}
1912
1913
1914// ----------------------------------------------------------------------------
1915
1916AudioFlinger::MixerThread::OutputTrack::OutputTrack(
1917 const sp<MixerThread>& mixerThread,
1918 uint32_t sampleRate,
1919 int format,
1920 int channelCount,
1921 int frameCount)
1922 : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
1923 mOutputMixerThread(mixerThread)
1924{
1925
1926 mCblk->out = 1;
1927 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
1928 mCblk->volume[0] = mCblk->volume[1] = 0x1000;
1929 mOutBuffer.frameCount = 0;
1930 mCblk->bufferTimeoutMs = 10;
1931
1932 LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
1933 mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
1934
1935}
1936
1937AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
1938{
1939 stop();
1940}
1941
1942status_t AudioFlinger::MixerThread::OutputTrack::start()
1943{
1944 status_t status = Track::start();
1945
1946 mRetryCount = 127;
1947 return status;
1948}
1949
1950void AudioFlinger::MixerThread::OutputTrack::stop()
1951{
1952 Track::stop();
1953 clearBufferQueue();
1954 mOutBuffer.frameCount = 0;
1955}
1956
1957void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
1958{
1959 Buffer *pInBuffer;
1960 Buffer inBuffer;
1961 uint32_t channels = mCblk->channels;
1962
1963 inBuffer.frameCount = frames;
1964 inBuffer.i16 = data;
1965
1966 if (mCblk->user == 0) {
1967 if (mOutputMixerThread->isMusicActive()) {
1968 mCblk->forceReady = 1;
1969 LOGV("OutputTrack::start() force ready");
1970 } else if (mCblk->frameCount > frames){
1971 if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
1972 uint32_t startFrames = (mCblk->frameCount - frames);
1973 LOGV("OutputTrack::start() write %d frames", startFrames);
1974 pInBuffer = new Buffer;
1975 pInBuffer->mBuffer = new int16_t[startFrames * channels];
1976 pInBuffer->frameCount = startFrames;
1977 pInBuffer->i16 = pInBuffer->mBuffer;
1978 memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
1979 mBufferQueue.add(pInBuffer);
1980 } else {
1981 LOGW ("OutputTrack::write() no more buffers");
1982 }
1983 }
1984 }
1985
1986 while (1) {
1987 // First write pending buffers, then new data
1988 if (mBufferQueue.size()) {
1989 pInBuffer = mBufferQueue.itemAt(0);
1990 } else {
1991 pInBuffer = &inBuffer;
1992 }
1993
1994 if (pInBuffer->frameCount == 0) {
1995 break;
1996 }
1997
1998 if (mOutBuffer.frameCount == 0) {
1999 mOutBuffer.frameCount = pInBuffer->frameCount;
2000 if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
2001 break;
2002 }
2003 }
2004
2005 uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
2006 memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
2007 mCblk->stepUser(outFrames);
2008 pInBuffer->frameCount -= outFrames;
2009 pInBuffer->i16 += outFrames * channels;
2010 mOutBuffer.frameCount -= outFrames;
2011 mOutBuffer.i16 += outFrames * channels;
2012
2013 if (pInBuffer->frameCount == 0) {
2014 if (mBufferQueue.size()) {
2015 mBufferQueue.removeAt(0);
2016 delete [] pInBuffer->mBuffer;
2017 delete pInBuffer;
2018 } else {
2019 break;
2020 }
2021 }
2022 }
2023
2024 // If we could not write all frames, allocate a buffer and queue it for next time.
2025 if (inBuffer.frameCount) {
2026 if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
2027 pInBuffer = new Buffer;
2028 pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
2029 pInBuffer->frameCount = inBuffer.frameCount;
2030 pInBuffer->i16 = pInBuffer->mBuffer;
2031 memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
2032 mBufferQueue.add(pInBuffer);
2033 } else {
2034 LOGW("OutputTrack::write() no more buffers");
2035 }
2036 }
2037
2038 // Calling write() with a 0 length buffer, means that no more data will be written:
2039 // If no more buffers are pending, fill output track buffer to make sure it is started
2040 // by output mixer.
2041 if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
2042 frames = mCblk->frameCount - mCblk->user;
2043 pInBuffer = new Buffer;
2044 pInBuffer->mBuffer = new int16_t[frames * channels];
2045 pInBuffer->frameCount = frames;
2046 pInBuffer->i16 = pInBuffer->mBuffer;
2047 memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
2048 mBufferQueue.add(pInBuffer);
2049 }
2050
2051}
2052
2053status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
2054{
2055 int active;
2056 int timeout = 0;
2057 status_t result;
2058 audio_track_cblk_t* cblk = mCblk;
2059 uint32_t framesReq = buffer->frameCount;
2060
2061 LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
2062 buffer->frameCount = 0;
2063
2064 uint32_t framesAvail = cblk->framesAvailable();
2065
2066 if (framesAvail == 0) {
2067 return AudioTrack::NO_MORE_BUFFERS;
2068 }
2069
2070 if (framesReq > framesAvail) {
2071 framesReq = framesAvail;
2072 }
2073
2074 uint32_t u = cblk->user;
2075 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
2076
2077 if (u + framesReq > bufferEnd) {
2078 framesReq = bufferEnd - u;
2079 }
2080
2081 buffer->frameCount = framesReq;
2082 buffer->raw = (void *)cblk->buffer(u);
2083 return NO_ERROR;
2084}
2085
2086
2087void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
2088{
2089 size_t size = mBufferQueue.size();
2090 Buffer *pBuffer;
2091
2092 for (size_t i = 0; i < size; i++) {
2093 pBuffer = mBufferQueue.itemAt(i);
2094 delete [] pBuffer->mBuffer;
2095 delete pBuffer;
2096 }
2097 mBufferQueue.clear();
2098}
2099
2100// ----------------------------------------------------------------------------
2101
2102AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
2103 : RefBase(),
2104 mAudioFlinger(audioFlinger),
2105 mMemoryDealer(new MemoryDealer(1024*1024)),
2106 mPid(pid)
2107{
2108 // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
2109}
2110
2111AudioFlinger::Client::~Client()
2112{
2113 mAudioFlinger->removeClient(mPid);
2114}
2115
2116const sp<MemoryDealer>& AudioFlinger::Client::heap() const
2117{
2118 return mMemoryDealer;
2119}
2120
2121// ----------------------------------------------------------------------------
2122
2123AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002124 : BnAudioTrack(),
2125 mTrack(track)
2126{
2127}
2128
2129AudioFlinger::TrackHandle::~TrackHandle() {
2130 // just stop the track on deletion, associated resources
2131 // will be freed from the main thread once all pending buffers have
2132 // been played. Unless it's not in the active track list, in which
2133 // case we free everything now...
2134 mTrack->destroy();
2135}
2136
2137status_t AudioFlinger::TrackHandle::start() {
2138 return mTrack->start();
2139}
2140
2141void AudioFlinger::TrackHandle::stop() {
2142 mTrack->stop();
2143}
2144
2145void AudioFlinger::TrackHandle::flush() {
2146 mTrack->flush();
2147}
2148
2149void AudioFlinger::TrackHandle::mute(bool e) {
2150 mTrack->mute(e);
2151}
2152
2153void AudioFlinger::TrackHandle::pause() {
2154 mTrack->pause();
2155}
2156
2157void AudioFlinger::TrackHandle::setVolume(float left, float right) {
2158 mTrack->setVolume(left, right);
2159}
2160
2161sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
2162 return mTrack->getCblk();
2163}
2164
2165status_t AudioFlinger::TrackHandle::onTransact(
2166 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
2167{
2168 return BnAudioTrack::onTransact(code, data, reply, flags);
2169}
2170
2171// ----------------------------------------------------------------------------
2172
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002173sp<IAudioRecord> AudioFlinger::openRecord(
2174 pid_t pid,
2175 int streamType,
2176 uint32_t sampleRate,
2177 int format,
2178 int channelCount,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002179 int frameCount,
2180 uint32_t flags,
2181 status_t *status)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002182{
2183 sp<AudioRecordThread> thread;
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002184 sp<MixerThread::RecordTrack> recordTrack;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002185 sp<RecordHandle> recordHandle;
2186 sp<Client> client;
2187 wp<Client> wclient;
2188 AudioStreamIn* input = 0;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002189 int inFrameCount;
2190 size_t inputBufferSize;
2191 status_t lStatus;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002192
2193 // check calling permissions
2194 if (!recordingAllowed()) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002195 lStatus = PERMISSION_DENIED;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002196 goto Exit;
2197 }
2198
2199 if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
2200 LOGE("invalid stream type");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002201 lStatus = BAD_VALUE;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002202 goto Exit;
2203 }
2204
2205 if (sampleRate > MAX_SAMPLE_RATE) {
2206 LOGE("Sample rate out of range");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002207 lStatus = BAD_VALUE;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002208 goto Exit;
2209 }
2210
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002211 if (mAudioRecordThread == 0) {
2212 LOGE("Audio record thread not started");
2213 lStatus = NO_INIT;
2214 goto Exit;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002215 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002216
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002217
2218 // Check that audio input stream accepts requested audio parameters
2219 inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
2220 if (inputBufferSize == 0) {
2221 lStatus = BAD_VALUE;
2222 LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002223 goto Exit;
2224 }
2225
2226 // add client to list
2227 {
2228 Mutex::Autolock _l(mLock);
2229 wclient = mClients.valueFor(pid);
2230 if (wclient != NULL) {
2231 client = wclient.promote();
2232 } else {
2233 client = new Client(this, pid);
2234 mClients.add(pid, client);
2235 }
2236 }
2237
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002238 // frameCount must be a multiple of input buffer size
2239 inFrameCount = inputBufferSize/channelCount/sizeof(short);
2240 frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
2241
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002242 // create new record track and pass to record thread
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002243 recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002244 format, channelCount, frameCount, flags);
2245 if (recordTrack->getCblk() == NULL) {
2246 recordTrack.clear();
2247 lStatus = NO_MEMORY;
2248 goto Exit;
2249 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002250
2251 // return to handle to client
2252 recordHandle = new RecordHandle(recordTrack);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002253 lStatus = NO_ERROR;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002254
2255Exit:
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002256 if (status) {
2257 *status = lStatus;
2258 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002259 return recordHandle;
2260}
2261
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002262status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002263 if (mAudioRecordThread != 0) {
2264 return mAudioRecordThread->start(recordTrack);
2265 }
2266 return NO_INIT;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002267}
2268
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002269void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002270 if (mAudioRecordThread != 0) {
2271 mAudioRecordThread->stop(recordTrack);
2272 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002273}
2274
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002275// ----------------------------------------------------------------------------
2276
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002277AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002278 : BnAudioRecord(),
2279 mRecordTrack(recordTrack)
2280{
2281}
2282
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002283AudioFlinger::RecordHandle::~RecordHandle() {
2284 stop();
2285}
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002286
2287status_t AudioFlinger::RecordHandle::start() {
2288 LOGV("RecordHandle::start()");
2289 return mRecordTrack->start();
2290}
2291
2292void AudioFlinger::RecordHandle::stop() {
2293 LOGV("RecordHandle::stop()");
2294 mRecordTrack->stop();
2295}
2296
2297sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
2298 return mRecordTrack->getCblk();
2299}
2300
2301status_t AudioFlinger::RecordHandle::onTransact(
2302 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
2303{
2304 return BnAudioRecord::onTransact(code, data, reply, flags);
2305}
2306
2307// ----------------------------------------------------------------------------
2308
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002309AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
2310 mAudioHardware(audioHardware),
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002311 mActive(false)
2312{
2313}
2314
2315AudioFlinger::AudioRecordThread::~AudioRecordThread()
2316{
2317}
2318
2319bool AudioFlinger::AudioRecordThread::threadLoop()
2320{
2321 LOGV("AudioRecordThread: start record loop");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002322 AudioBufferProvider::Buffer buffer;
2323 int inBufferSize = 0;
2324 int inFrameCount = 0;
2325 AudioStreamIn* input = 0;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002326
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002327 mActive = 0;
2328
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002329 // start recording
2330 while (!exitPending()) {
2331 if (!mActive) {
2332 mLock.lock();
2333 if (!mActive && !exitPending()) {
2334 LOGV("AudioRecordThread: loop stopping");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002335 if (input) {
2336 delete input;
2337 input = 0;
2338 }
2339 mRecordTrack.clear();
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002340 mStopped.signal();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002341
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002342 mWaitWorkCV.wait(mLock);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002343
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002344 LOGV("AudioRecordThread: loop starting");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002345 if (mRecordTrack != 0) {
2346 input = mAudioHardware->openInputStream(mRecordTrack->format(),
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002347 mRecordTrack->channelCount(),
2348 mRecordTrack->sampleRate(),
2349 &mStartStatus,
2350 (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002351 if (input != 0) {
2352 inBufferSize = input->bufferSize();
2353 inFrameCount = inBufferSize/input->frameSize();
2354 }
2355 } else {
2356 mStartStatus = NO_INIT;
2357 }
2358 if (mStartStatus !=NO_ERROR) {
2359 LOGW("record start failed, status %d", mStartStatus);
2360 mActive = false;
2361 mRecordTrack.clear();
2362 }
2363 mWaitWorkCV.signal();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002364 }
2365 mLock.unlock();
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002366 } else if (mRecordTrack != 0) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002367
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002368 buffer.frameCount = inFrameCount;
2369 if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
2370 LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002371 ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
2372 if (bytesRead < 0) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002373 LOGE("Error reading audio input");
2374 sleep(1);
2375 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002376 mRecordTrack->releaseBuffer(&buffer);
2377 mRecordTrack->overflow();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002378 }
2379
2380 // client isn't retrieving buffers fast enough
2381 else {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002382 if (!mRecordTrack->setOverflow())
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002383 LOGW("AudioRecordThread: buffer overflow");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002384 // Release the processor for a while before asking for a new buffer.
2385 // This will give the application more chance to read from the buffer and
2386 // clear the overflow.
2387 usleep(5000);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002388 }
2389 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002390 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002391
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002392
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002393 if (input) {
2394 delete input;
2395 }
2396 mRecordTrack.clear();
2397
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002398 return false;
2399}
2400
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002401status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002402{
2403 LOGV("AudioRecordThread::start");
2404 AutoMutex lock(&mLock);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002405 mActive = true;
2406 // If starting the active track, just reset mActive in case a stop
2407 // was pending and exit
2408 if (recordTrack == mRecordTrack.get()) return NO_ERROR;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002409
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002410 if (mRecordTrack != 0) return -EBUSY;
2411
2412 mRecordTrack = recordTrack;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002413
2414 // signal thread to start
2415 LOGV("Signal record thread");
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002416 mWaitWorkCV.signal();
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002417 mWaitWorkCV.wait(mLock);
2418 LOGV("Record started, status %d", mStartStatus);
2419 return mStartStatus;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002420}
2421
The Android Open Source Projectac65e0b2009-02-13 12:57:50 -08002422void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002423 LOGV("AudioRecordThread::stop");
2424 AutoMutex lock(&mLock);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002425 if (mActive && (recordTrack == mRecordTrack.get())) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002426 mActive = false;
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002427 mStopped.wait(mLock);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002428 }
2429}
2430
2431void AudioFlinger::AudioRecordThread::exit()
2432{
2433 LOGV("AudioRecordThread::exit");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08002434 {
2435 AutoMutex lock(&mLock);
2436 requestExit();
2437 mWaitWorkCV.signal();
2438 }
2439 requestExitAndWait();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002440}
2441
The Android Open Source Projectd2bd26d2009-02-19 10:57:31 -08002442status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
2443{
2444 const size_t SIZE = 256;
2445 char buffer[SIZE];
2446 String8 result;
2447 pid_t pid = 0;
2448
2449 if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
2450 snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
2451 result.append(buffer);
2452 } else {
2453 result.append("No record client\n");
2454 }
2455 write(fd, result.string(), result.size());
2456 return NO_ERROR;
2457}
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002458
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07002459status_t AudioFlinger::onTransact(
2460 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
2461{
2462 return BnAudioFlinger::onTransact(code, data, reply, flags);
2463}
2464
2465// ----------------------------------------------------------------------------
2466void AudioFlinger::instantiate() {
2467 defaultServiceManager()->addService(
2468 String16("media.audio_flinger"), new AudioFlinger());
2469}
2470
2471}; // namespace android