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