summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/AudioFlinger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger/AudioFlinger.cpp')
-rw-r--r--services/audioflinger/AudioFlinger.cpp428
1 files changed, 279 insertions, 149 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 33b19a4..13514fc 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -82,6 +82,7 @@ namespace android {
static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
static const char kHardwareLockedString[] = "Hardware lock is taken\n";
+static const char kClientLockedString[] = "Client lock is taken\n";
nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
@@ -104,6 +105,27 @@ static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
// ----------------------------------------------------------------------------
+const char *formatToString(audio_format_t format) {
+ switch(format) {
+ case AUDIO_FORMAT_PCM_SUB_8_BIT: return "pcm8";
+ case AUDIO_FORMAT_PCM_SUB_16_BIT: return "pcm16";
+ case AUDIO_FORMAT_PCM_SUB_32_BIT: return "pcm32";
+ case AUDIO_FORMAT_PCM_SUB_8_24_BIT: return "pcm8.24";
+ case AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED: return "pcm24";
+ case AUDIO_FORMAT_PCM_SUB_FLOAT: return "pcmfloat";
+ case AUDIO_FORMAT_MP3: return "mp3";
+ case AUDIO_FORMAT_AMR_NB: return "amr-nb";
+ case AUDIO_FORMAT_AMR_WB: return "amr-wb";
+ case AUDIO_FORMAT_AAC: return "aac";
+ case AUDIO_FORMAT_HE_AAC_V1: return "he-aac-v1";
+ case AUDIO_FORMAT_HE_AAC_V2: return "he-aac-v2";
+ case AUDIO_FORMAT_VORBIS: return "vorbis";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
const hw_module_t *mod;
@@ -138,6 +160,7 @@ out:
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mPrimaryHardwareDev(NULL),
+ mAudioHwDevs(NULL),
mHardwareStatus(AUDIO_HW_IDLE),
mMasterVolume(1.0f),
mMasterMute(false),
@@ -152,7 +175,7 @@ AudioFlinger::AudioFlinger()
char value[PROPERTY_VALUE_MAX];
bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
if (doLog) {
- mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters");
+ mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY);
}
#ifdef TEE_SINK
(void) property_get("ro.debuggable", value, "0");
@@ -162,12 +185,16 @@ AudioFlinger::AudioFlinger()
(void) property_get("af.tee", value, "0");
teeEnabled = atoi(value);
}
- if (teeEnabled & 1)
+ // FIXME symbolic constants here
+ if (teeEnabled & 1) {
mTeeSinkInputEnabled = true;
- if (teeEnabled & 2)
+ }
+ if (teeEnabled & 2) {
mTeeSinkOutputEnabled = true;
- if (teeEnabled & 4)
+ }
+ if (teeEnabled & 4) {
mTeeSinkTrackEnabled = true;
+ }
#endif
}
@@ -210,6 +237,18 @@ AudioFlinger::~AudioFlinger()
audio_hw_device_close(mAudioHwDevs.valueAt(i)->hwDevice());
delete mAudioHwDevs.valueAt(i);
}
+
+ // Tell media.log service about any old writers that still need to be unregistered
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+ if (binder != 0) {
+ sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+ for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+ sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
+ mUnregisteredWriters.pop();
+ mediaLogService->unregisterWriter(iMemory);
+ }
+ }
+
}
static const char * const audio_interfaces[] = {
@@ -249,7 +288,7 @@ AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
return NULL;
}
-void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpClients(int fd, const Vector<String16>& args __unused)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -271,17 +310,17 @@ void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
}
result.append("Global session refs:\n");
- result.append(" session pid count\n");
+ result.append(" session pid count\n");
for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
AudioSessionRef *r = mAudioSessionRefs[i];
- snprintf(buffer, SIZE, " %7d %3d %3d\n", r->mSessionid, r->mPid, r->mCnt);
+ snprintf(buffer, SIZE, " %7d %5d %5d\n", r->mSessionid, r->mPid, r->mCnt);
result.append(buffer);
}
write(fd, result.string(), result.size());
}
-void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args __unused)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -296,7 +335,7 @@ void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
write(fd, result.string(), result.size());
}
-void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args __unused)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -344,7 +383,16 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
write(fd, result.string(), result.size());
}
+ bool clientLocked = dumpTryLock(mClientLock);
+ if (!clientLocked) {
+ String8 result(kClientLockedString);
+ write(fd, result.string(), result.size());
+ }
dumpClients(fd, args);
+ if (clientLocked) {
+ mClientLock.unlock();
+ }
+
dumpInternals(fd, args);
// dump playback threads
@@ -388,8 +436,9 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
-sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)
+sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
{
+ Mutex::Autolock _cl(mClientLock);
// If pid is already in the mClients wp<> map, then use that entry
// (for which promote() is always != 0), otherwise create a new entry and Client.
sp<Client> client = mClients.valueFor(pid).promote();
@@ -403,16 +452,44 @@ sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)
sp<NBLog::Writer> AudioFlinger::newWriter_l(size_t size, const char *name)
{
+ // If there is no memory allocated for logs, return a dummy writer that does nothing
if (mLogMemoryDealer == 0) {
return new NBLog::Writer();
}
- sp<IMemory> shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
- sp<NBLog::Writer> writer = new NBLog::Writer(size, shared);
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
- if (binder != 0) {
- interface_cast<IMediaLogService>(binder)->registerWriter(shared, size, name);
+ // Similarly if we can't contact the media.log service, also return a dummy writer
+ if (binder == 0) {
+ return new NBLog::Writer();
+ }
+ sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+ sp<IMemory> shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
+ // If allocation fails, consult the vector of previously unregistered writers
+ // and garbage-collect one or more them until an allocation succeeds
+ if (shared == 0) {
+ Mutex::Autolock _l(mUnregisteredWritersLock);
+ for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+ {
+ // Pick the oldest stale writer to garbage-collect
+ sp<IMemory> iMemory(mUnregisteredWriters[0]->getIMemory());
+ mUnregisteredWriters.removeAt(0);
+ mediaLogService->unregisterWriter(iMemory);
+ // Now the media.log remote reference to IMemory is gone. When our last local
+ // reference to IMemory also drops to zero at end of this block,
+ // the IMemory destructor will deallocate the region from mLogMemoryDealer.
+ }
+ // Re-attempt the allocation
+ shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
+ if (shared != 0) {
+ goto success;
+ }
+ }
+ // Even after garbage-collecting all old writers, there is still not enough memory,
+ // so return a dummy writer
+ return new NBLog::Writer();
}
- return writer;
+success:
+ mediaLogService->registerWriter(shared, size, name);
+ return new NBLog::Writer(size, shared);
}
void AudioFlinger::unregisterWriter(const sp<NBLog::Writer>& writer)
@@ -424,13 +501,10 @@ void AudioFlinger::unregisterWriter(const sp<NBLog::Writer>& writer)
if (iMemory == 0) {
return;
}
- sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
- if (binder != 0) {
- interface_cast<IMediaLogService>(binder)->unregisterWriter(iMemory);
- // Now the media.log remote reference to IMemory is gone.
- // When our last local reference to IMemory also drops to zero,
- // the IMemory destructor will deallocate the region from mMemoryDealer.
- }
+ // Rather than removing the writer immediately, append it to a queue of old writers to
+ // be garbage-collected later. This allows us to continue to view old logs for a while.
+ Mutex::Autolock _l(mUnregisteredWritersLock);
+ mUnregisteredWriters.push(writer);
}
// IAudioFlinger interface
@@ -441,13 +515,12 @@ sp<IAudioTrack> AudioFlinger::createTrack(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- size_t frameCount,
+ size_t *frameCount,
IAudioFlinger::track_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t tid,
int *sessionId,
- String8& name,
int clientUid,
status_t *status)
{
@@ -465,10 +538,29 @@ sp<IAudioTrack> AudioFlinger::createTrack(
goto Exit;
}
- // client is responsible for conversion of 8-bit PCM to 16-bit PCM,
- // and we don't yet support 8.24 or 32-bit PCM
- if (audio_is_linear_pcm(format) && format != AUDIO_FORMAT_PCM_16_BIT) {
- ALOGE("createTrack() invalid format %d", format);
+ // further sample rate checks are performed by createTrack_l() depending on the thread type
+ if (sampleRate == 0) {
+ ALOGE("createTrack() invalid sample rate %u", sampleRate);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ // further channel mask checks are performed by createTrack_l() depending on the thread type
+ if (!audio_is_output_channel(channelMask)) {
+ ALOGE("createTrack() invalid channel mask %#x", channelMask);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ // further format checks are performed by createTrack_l() depending on the thread type
+ if (!audio_is_valid_format(format)) {
+ ALOGE("createTrack() invalid format %#x", format);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ if (sharedBuffer != 0 && sharedBuffer->pointer() == NULL) {
+ ALOGE("createTrack() sharedBuffer is non-0 but has NULL pointer()");
lStatus = BAD_VALUE;
goto Exit;
}
@@ -476,7 +568,6 @@ sp<IAudioTrack> AudioFlinger::createTrack(
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
- PlaybackThread *effectThread = NULL;
if (thread == NULL) {
ALOGE("no playback thread found for output handle %d", output);
lStatus = BAD_VALUE;
@@ -484,24 +575,23 @@ sp<IAudioTrack> AudioFlinger::createTrack(
}
pid_t pid = IPCThreadState::self()->getCallingPid();
+ client = registerPid(pid);
- client = registerPid_l(pid);
-
- ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
- if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
+ PlaybackThread *effectThread = NULL;
+ if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
+ lSessionId = *sessionId;
// check if an effect chain with the same session ID is present on another
// output thread and move it here.
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
if (mPlaybackThreads.keyAt(i) != output) {
- uint32_t sessions = t->hasAudioSession(*sessionId);
+ uint32_t sessions = t->hasAudioSession(lSessionId);
if (sessions & PlaybackThread::EFFECT_SESSION) {
effectThread = t.get();
break;
}
}
}
- lSessionId = *sessionId;
} else {
// if no audio session id is provided, create one here
lSessionId = nextUniqueId();
@@ -519,6 +609,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
if (lStatus == NO_ERROR && effectThread != NULL) {
+ // no risk of deadlock because AudioFlinger::mLock is held
Mutex::Autolock _dl(thread->mLock);
Mutex::Autolock _sl(effectThread->mLock);
moveEffectChain_l(lSessionId, effectThread, thread, true);
@@ -538,23 +629,23 @@ sp<IAudioTrack> AudioFlinger::createTrack(
}
}
}
+
}
- if (lStatus == NO_ERROR) {
- // s for server's pid, n for normal mixer name, f for fast index
- name = String8::format("s:%d;n:%d;f:%d", getpid_cached, track->name() - AudioMixer::TRACK0,
- track->fastIndex());
- trackHandle = new TrackHandle(track);
- } else {
- // remove local strong reference to Client before deleting the Track so that the Client
- // destructor is called by the TrackBase destructor with mLock held
+
+ if (lStatus != NO_ERROR) {
+ // remove local strong reference to Client before deleting the Track so that the
+ // Client destructor is called by the TrackBase destructor with mClientLock held
+ Mutex::Autolock _cl(mClientLock);
client.clear();
track.clear();
+ goto Exit;
}
+ // return handle to client
+ trackHandle = new TrackHandle(track);
+
Exit:
- if (status != NULL) {
- *status = lStatus;
- }
+ *status = lStatus;
return trackHandle;
}
@@ -796,7 +887,7 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
AutoMutex lock(mLock);
PlaybackThread *thread = NULL;
- if (output) {
+ if (output != AUDIO_IO_HANDLE_NONE) {
thread = checkPlaybackThread_l(output);
if (thread == NULL) {
return BAD_VALUE;
@@ -845,7 +936,7 @@ float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t o
AutoMutex lock(mLock);
float volume;
- if (output) {
+ if (output != AUDIO_IO_HANDLE_NONE) {
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread == NULL) {
return 0.0f;
@@ -878,8 +969,8 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
return PERMISSION_DENIED;
}
- // ioHandle == 0 means the parameters are global to the audio hardware interface
- if (ioHandle == 0) {
+ // AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
+ if (ioHandle == AUDIO_IO_HANDLE_NONE) {
Mutex::Autolock _l(mLock);
status_t final_result = NO_ERROR;
{
@@ -961,7 +1052,7 @@ String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& k
Mutex::Autolock _l(mLock);
- if (ioHandle == 0) {
+ if (ioHandle == AUDIO_IO_HANDLE_NONE) {
String8 out_s8;
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
@@ -1061,21 +1152,29 @@ status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrame
void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
{
-
Mutex::Autolock _l(mLock);
+ bool clientAdded = false;
+ {
+ Mutex::Autolock _cl(mClientLock);
- pid_t pid = IPCThreadState::self()->getCallingPid();
- if (mNotificationClients.indexOfKey(pid) < 0) {
- sp<NotificationClient> notificationClient = new NotificationClient(this,
- client,
- pid);
- ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ if (mNotificationClients.indexOfKey(pid) < 0) {
+ sp<NotificationClient> notificationClient = new NotificationClient(this,
+ client,
+ pid);
+ ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
- mNotificationClients.add(pid, notificationClient);
+ mNotificationClients.add(pid, notificationClient);
- sp<IBinder> binder = client->asBinder();
- binder->linkToDeath(notificationClient);
+ sp<IBinder> binder = client->asBinder();
+ binder->linkToDeath(notificationClient);
+ clientAdded = true;
+ }
+ }
+ // mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
+ // ThreadBase mutex and teh locknig order is ThreadBase::mLock then AudioFlinger::mClientLock.
+ if (clientAdded) {
// the config change is always sent from playback or record threads to avoid deadlock
// with AudioSystem::gLock
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -1091,8 +1190,10 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
void AudioFlinger::removeNotificationClient(pid_t pid)
{
Mutex::Autolock _l(mLock);
-
- mNotificationClients.removeItem(pid);
+ {
+ Mutex::Autolock _cl(mClientLock);
+ mNotificationClients.removeItem(pid);
+ }
ALOGV("%d died, releasing its sessions", pid);
size_t num = mAudioSessionRefs.size();
@@ -1115,17 +1216,18 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
}
}
-// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2)
+void AudioFlinger::audioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2)
{
+ Mutex::Autolock _l(mClientLock);
size_t size = mNotificationClients.size();
for (size_t i = 0; i < size; i++) {
- mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
- param2);
+ mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
+ ioHandle,
+ param2);
}
}
-// removeClient_l() must be called with AudioFlinger::mLock held
+// removeClient_l() must be called with AudioFlinger::mClientLock held
void AudioFlinger::removeClient_l(pid_t pid)
{
ALOGV("removeClient_l() pid %d, calling pid %d", pid,
@@ -1163,7 +1265,7 @@ AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
}
-// Client destructor must be called with AudioFlinger::mLock held
+// Client destructor must be called with AudioFlinger::mClientLock held
AudioFlinger::Client::~Client()
{
mAudioFlinger->removeClient_l(mPid);
@@ -1212,7 +1314,7 @@ AudioFlinger::NotificationClient::~NotificationClient()
{
}
-void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
+void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who __unused)
{
sp<NotificationClient> keep(this);
mAudioFlinger->removeNotificationClient(mPid);
@@ -1230,20 +1332,23 @@ sp<IAudioRecord> AudioFlinger::openRecord(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- size_t frameCount,
+ size_t *frameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
int *sessionId,
+ sp<IMemory>& cblk,
+ sp<IMemory>& buffers,
status_t *status)
{
sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
status_t lStatus;
- RecordThread *thread;
- size_t inFrameCount;
int lSessionId;
+ cblk.clear();
+ buffers.clear();
+
// check calling permissions
if (!recordingAllowed()) {
ALOGE("openRecord() permission denied: recording not allowed");
@@ -1251,16 +1356,31 @@ sp<IAudioRecord> AudioFlinger::openRecord(
goto Exit;
}
- if (format != AUDIO_FORMAT_PCM_16_BIT) {
- ALOGE("openRecord() invalid format %d", format);
+ // further sample rate checks are performed by createRecordTrack_l()
+ if (sampleRate == 0) {
+ ALOGE("openRecord() invalid sample rate %u", sampleRate);
lStatus = BAD_VALUE;
goto Exit;
}
- // add client to list
- { // scope for mLock
+ // we don't yet support anything other than 16-bit PCM
+ if (!(audio_is_valid_format(format) &&
+ audio_is_linear_pcm(format) && format == AUDIO_FORMAT_PCM_16_BIT)) {
+ ALOGE("openRecord() invalid format %#x", format);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ // further channel mask checks are performed by createRecordTrack_l()
+ if (!audio_is_input_channel(channelMask)) {
+ ALOGE("openRecord() invalid channel mask %#x", channelMask);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ {
Mutex::Autolock _l(mLock);
- thread = checkRecordThread_l(input);
+ RecordThread *thread = checkRecordThread_l(input);
if (thread == NULL) {
ALOGE("openRecord() checkRecordThread_l failed");
lStatus = BAD_VALUE;
@@ -1275,19 +1395,19 @@ sp<IAudioRecord> AudioFlinger::openRecord(
}
pid_t pid = IPCThreadState::self()->getCallingPid();
- client = registerPid_l(pid);
+ client = registerPid(pid);
- // If no audio session id is provided, create one here
- if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
+ if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
lSessionId = *sessionId;
} else {
+ // if no audio session id is provided, create one here
lSessionId = nextUniqueId();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
}
- // create new record track.
- // The record track uses one track in mHardwareMixerThread by convention.
+ ALOGV("openRecord() lSessionId: %d", lSessionId);
+
// TODO: the uid should be passed in as a parameter to openRecord
recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
frameCount, lSessionId,
@@ -1295,22 +1415,24 @@ sp<IAudioRecord> AudioFlinger::openRecord(
flags, tid, &lStatus);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
}
+
if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the RecordTrack so that the
- // Client destructor is called by the TrackBase destructor with mLock held
+ // Client destructor is called by the TrackBase destructor with mClientLock held
+ Mutex::Autolock _cl(mClientLock);
client.clear();
recordTrack.clear();
goto Exit;
}
- // return to handle to client
+ cblk = recordTrack->getCblk();
+ buffers = recordTrack->getBuffers();
+
+ // return handle to client
recordHandle = new RecordHandle(recordTrack);
- lStatus = NO_ERROR;
Exit:
- if (status) {
- *status = lStatus;
- }
+ *status = lStatus;
return recordHandle;
}
@@ -1451,18 +1573,15 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
- PlaybackThread *thread = NULL;
struct audio_config config;
+ memset(&config, 0, sizeof(config));
config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
- if (offloadInfo) {
+ if (offloadInfo != NULL) {
config.offload_info = *offloadInfo;
}
- audio_stream_out_t *outStream = NULL;
- AudioHwDevice *outHwDev;
-
ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
module,
(pDevices != NULL) ? *pDevices : 0,
@@ -1471,23 +1590,25 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
config.channel_mask,
flags);
ALOGV("openOutput(), offloadInfo %p version 0x%04x",
- offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version );
+ offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version);
- if (pDevices == NULL || *pDevices == 0) {
- return 0;
+ if (pDevices == NULL || *pDevices == AUDIO_DEVICE_NONE) {
+ return AUDIO_IO_HANDLE_NONE;
}
Mutex::Autolock _l(mLock);
- outHwDev = findSuitableHwDev_l(module, *pDevices);
- if (outHwDev == NULL)
- return 0;
+ AudioHwDevice *outHwDev = findSuitableHwDev_l(module, *pDevices);
+ if (outHwDev == NULL) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
audio_hw_device_t *hwDevHal = outHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+ audio_stream_out_t *outStream = NULL;
status_t status = hwDevHal->open_output_stream(hwDevHal,
id,
*pDevices,
@@ -1507,6 +1628,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
if (status == NO_ERROR && outStream != NULL) {
AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream, flags);
+ PlaybackThread *thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, output, id, *pDevices);
ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
@@ -1535,7 +1657,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
}
// notify client processes of the new output creation
- thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+ thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);
// the first primary output opened designates the primary hw device
if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -1550,7 +1672,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
return id;
}
- return 0;
+ return AUDIO_IO_HANDLE_NONE;
}
audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
@@ -1563,7 +1685,7 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
if (thread1 == NULL || thread2 == NULL) {
ALOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1,
output2);
- return 0;
+ return AUDIO_IO_HANDLE_NONE;
}
audio_io_handle_t id = nextUniqueId();
@@ -1571,7 +1693,7 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
// notify client processes of the new output creation
- thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+ thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);
return id;
}
@@ -1621,7 +1743,7 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
}
}
}
- audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL);
+ audioConfigChanged(AudioSystem::OUTPUT_CLOSED, output, NULL);
}
thread->exit();
// The thread entity (active unit of execution) is no longer running here,
@@ -1674,35 +1796,34 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask)
{
- status_t status;
- RecordThread *thread = NULL;
struct audio_config config;
+ memset(&config, 0, sizeof(config));
config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
uint32_t reqSamplingRate = config.sample_rate;
audio_format_t reqFormat = config.format;
- audio_channel_mask_t reqChannels = config.channel_mask;
- audio_stream_in_t *inStream = NULL;
- AudioHwDevice *inHwDev;
+ audio_channel_mask_t reqChannelMask = config.channel_mask;
- if (pDevices == NULL || *pDevices == 0) {
+ if (pDevices == NULL || *pDevices == AUDIO_DEVICE_NONE) {
return 0;
}
Mutex::Autolock _l(mLock);
- inHwDev = findSuitableHwDev_l(module, *pDevices);
- if (inHwDev == NULL)
+ AudioHwDevice *inHwDev = findSuitableHwDev_l(module, *pDevices);
+ if (inHwDev == NULL) {
return 0;
+ }
audio_hw_device_t *inHwHal = inHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
- status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
+ audio_stream_in_t *inStream = NULL;
+ status_t status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
&inStream);
- ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, "
+ ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %#x, Channels %x, "
"status %d",
inStream,
config.sample_rate,
@@ -1716,10 +1837,13 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
if (status == BAD_VALUE &&
reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
(config.sample_rate <= 2 * reqSamplingRate) &&
- (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+ (audio_channel_count_from_in_mask(config.channel_mask) <= FCC_2) &&
+ (audio_channel_count_from_in_mask(reqChannelMask) <= FCC_2)) {
+ // FIXME describe the change proposed by HAL (save old values so we can log them here)
ALOGV("openInput() reopening with proposed sampling rate and channel mask");
inStream = NULL;
status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream);
+ // FIXME log this new status; HAL should not propose any further changes
}
if (status == NO_ERROR && inStream != NULL) {
@@ -1734,16 +1858,17 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
TEE_SINK_OLD, // copy input using an existing pipe
} kind;
NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common),
- popcount(inStream->common.get_channels(&inStream->common)));
+ audio_channel_count_from_in_mask(
+ inStream->common.get_channels(&inStream->common)));
if (!mTeeSinkInputEnabled) {
kind = TEE_SINK_NO;
- } else if (format == Format_Invalid) {
+ } else if (!Format_isValid(format)) {
kind = TEE_SINK_NO;
} else if (mRecordTeeSink == 0) {
kind = TEE_SINK_NEW;
} else if (mRecordTeeSink->getStrongCount() != 1) {
kind = TEE_SINK_NO;
- } else if (format == mRecordTeeSink->format()) {
+ } else if (Format_isEqual(format, mRecordTeeSink->format())) {
kind = TEE_SINK_OLD;
} else {
kind = TEE_SINK_NEW;
@@ -1778,10 +1903,8 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
// pre processing modules
- thread = new RecordThread(this,
+ RecordThread *thread = new RecordThread(this,
input,
- reqSamplingRate,
- reqChannels,
id,
primaryOutputDevice_l(),
*pDevices
@@ -1798,11 +1921,11 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
*pFormat = config.format;
}
if (pChannelMask != NULL) {
- *pChannelMask = reqChannels;
+ *pChannelMask = reqChannelMask;
}
// notify client processes of the new input creation
- thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
+ thread->audioConfigChanged(AudioSystem::INPUT_OPENED);
return id;
}
@@ -1827,7 +1950,7 @@ status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
}
ALOGV("closeInput() %d", input);
- audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, NULL);
+ audioConfigChanged(AudioSystem::INPUT_CLOSED, input, NULL);
mRecordThreads.removeItem(input);
}
thread->exit();
@@ -1843,10 +1966,10 @@ status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
return NO_ERROR;
}
-status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
+status_t AudioFlinger::invalidateStream(audio_stream_type_t stream)
{
Mutex::Autolock _l(mLock);
- ALOGV("setStreamOutput() stream %d to output %d", stream, output);
+ ALOGV("invalidateStream() stream %d", stream);
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
@@ -1862,19 +1985,25 @@ int AudioFlinger::newAudioSessionId()
return nextUniqueId();
}
-void AudioFlinger::acquireAudioSessionId(int audioSession)
+void AudioFlinger::acquireAudioSessionId(int audioSession, pid_t pid)
{
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
- ALOGV("acquiring %d from %d", audioSession, caller);
-
- // Ignore requests received from processes not known as notification client. The request
- // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
- // called from a different pid leaving a stale session reference. Also we don't know how
- // to clear this reference if the client process dies.
- if (mNotificationClients.indexOfKey(caller) < 0) {
- ALOGV("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
- return;
+ ALOGV("acquiring %d from %d, for %d", audioSession, caller, pid);
+ if (pid != -1 && (caller == getpid_cached)) {
+ caller = pid;
+ }
+
+ {
+ Mutex::Autolock _cl(mClientLock);
+ // Ignore requests received from processes not known as notification client. The request
+ // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
+ // called from a different pid leaving a stale session reference. Also we don't know how
+ // to clear this reference if the client process dies.
+ if (mNotificationClients.indexOfKey(caller) < 0) {
+ ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
+ return;
+ }
}
size_t num = mAudioSessionRefs.size();
@@ -1890,11 +2019,14 @@ void AudioFlinger::acquireAudioSessionId(int audioSession)
ALOGV(" added new entry for %d", audioSession);
}
-void AudioFlinger::releaseAudioSessionId(int audioSession)
+void AudioFlinger::releaseAudioSessionId(int audioSession, pid_t pid)
{
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
- ALOGV("releasing %d from %d", audioSession, caller);
+ ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
+ if (pid != -1 && (caller == getpid_cached)) {
+ caller = pid;
+ }
size_t num = mAudioSessionRefs.size();
for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
@@ -1956,7 +2088,7 @@ void AudioFlinger::purgeStaleEffects_l() {
}
}
if (!found) {
- Mutex::Autolock _l (t->mLock);
+ Mutex::Autolock _l(t->mLock);
// remove all effects from the chain
while (ec->mEffects.size()) {
sp<EffectModule> effect = ec->mEffects[0];
@@ -1993,7 +2125,7 @@ AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(audio_io_handle_t
uint32_t AudioFlinger::nextUniqueId()
{
- return android_atomic_inc(&mNextUniqueId);
+ return (uint32_t) android_atomic_inc(&mNextUniqueId);
}
AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l() const
@@ -2023,7 +2155,7 @@ sp<AudioFlinger::SyncEvent> AudioFlinger::createSyncEvent(AudioSystem::sync_even
int triggerSession,
int listenerSession,
sync_event_callback_t callBack,
- void *cookie)
+ wp<RefBase> cookie)
{
Mutex::Autolock _l(mLock);
@@ -2185,7 +2317,7 @@ sp<IEffect> AudioFlinger::createEffect(
// return effect descriptor
*pDesc = desc;
- if (io == 0 && sessionId == AUDIO_SESSION_OUTPUT_MIX) {
+ if (io == AUDIO_IO_HANDLE_NONE && sessionId == AUDIO_SESSION_OUTPUT_MIX) {
// if the output returned by getOutputForEffect() is removed before we lock the
// mutex below, the call to checkPlaybackThread_l(io) below will detect it
// and we will exit safely
@@ -2200,7 +2332,7 @@ sp<IEffect> AudioFlinger::createEffect(
// If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
// because of code checking output when entering the function.
// Note: io is never 0 when creating an effect on an input
- if (io == 0) {
+ if (io == AUDIO_IO_HANDLE_NONE) {
if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
// output must be specified by AudioPolicyManager when using session
// AUDIO_SESSION_OUTPUT_STAGE
@@ -2225,7 +2357,7 @@ sp<IEffect> AudioFlinger::createEffect(
// If no output thread contains the requested session ID, default to
// first output. The effect chain will be moved to the correct output
// thread when a track with the same session ID is created
- if (io == 0 && mPlaybackThreads.size()) {
+ if (io == AUDIO_IO_HANDLE_NONE && mPlaybackThreads.size() > 0) {
io = mPlaybackThreads.keyAt(0);
}
ALOGV("createEffect() got io %d for effect %s", io, desc.name);
@@ -2240,7 +2372,7 @@ sp<IEffect> AudioFlinger::createEffect(
}
}
- sp<Client> client = registerPid_l(pid);
+ sp<Client> client = registerPid(pid);
// create effect on selected output thread
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
@@ -2251,9 +2383,7 @@ sp<IEffect> AudioFlinger::createEffect(
}
Exit:
- if (status != NULL) {
- *status = lStatus;
- }
+ *status = lStatus;
return handle;
}