Revert "refactor AudioRecord and AudioFlinger openRecord()"

This reverts commit 3e1acc0c58.

bug: 70388312

Change-Id: I6782d6eceeece1bad998b02af26c0119da70a13d
gugelfrei
Eric Laurent 7 years ago
parent 3e1acc0c58
commit 0aa3c6eba0

@ -69,7 +69,8 @@ AudioRecord::AudioRecord(const String16 &opPackageName)
: mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName), : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
mSessionId(AUDIO_SESSION_ALLOCATE), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE) mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE)
{ {
} }
@ -96,9 +97,10 @@ AudioRecord::AudioRecord(
mSessionId(AUDIO_SESSION_ALLOCATE), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT), mPreviousSchedulingGroup(SP_DEFAULT),
mProxy(NULL) mProxy(NULL),
mPortId(AUDIO_PORT_HANDLE_NONE)
{ {
(void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags, notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
uid, pid, pAttributes, selectedDeviceId); uid, pid, pAttributes, selectedDeviceId);
} }
@ -149,11 +151,6 @@ status_t AudioRecord::set(
const audio_attributes_t* pAttributes, const audio_attributes_t* pAttributes,
audio_port_handle_t selectedDeviceId) audio_port_handle_t selectedDeviceId)
{ {
status_t status = NO_ERROR;
uint32_t channelCount;
pid_t callingPid;
pid_t myPid;
ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s " "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
"uid %d, pid %d", "uid %d, pid %d",
@ -173,8 +170,7 @@ status_t AudioRecord::set(
case TRANSFER_CALLBACK: case TRANSFER_CALLBACK:
if (cbf == NULL) { if (cbf == NULL) {
ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL"); ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL");
status = BAD_VALUE; return BAD_VALUE;
goto exit;
} }
break; break;
case TRANSFER_OBTAIN: case TRANSFER_OBTAIN:
@ -182,16 +178,14 @@ status_t AudioRecord::set(
break; break;
default: default:
ALOGE("Invalid transfer type %d", transferType); ALOGE("Invalid transfer type %d", transferType);
status = BAD_VALUE; return BAD_VALUE;
goto exit;
} }
mTransfer = transferType; mTransfer = transferType;
// invariant that mAudioRecord != 0 is true only after set() returns successfully // invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) { if (mAudioRecord != 0) {
ALOGE("Track already in use"); ALOGE("Track already in use");
status = INVALID_OPERATION; return INVALID_OPERATION;
goto exit;
} }
if (pAttributes == NULL) { if (pAttributes == NULL) {
@ -215,18 +209,16 @@ status_t AudioRecord::set(
// AudioFlinger capture only supports linear PCM // AudioFlinger capture only supports linear PCM
if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
ALOGE("Format %#x is not linear pcm", format); ALOGE("Format %#x is not linear pcm", format);
status = BAD_VALUE; return BAD_VALUE;
goto exit;
} }
mFormat = format; mFormat = format;
if (!audio_is_input_channel(channelMask)) { if (!audio_is_input_channel(channelMask)) {
ALOGE("Invalid channel mask %#x", channelMask); ALOGE("Invalid channel mask %#x", channelMask);
status = BAD_VALUE; return BAD_VALUE;
goto exit;
} }
mChannelMask = channelMask; mChannelMask = channelMask;
channelCount = audio_channel_count_from_in_mask(channelMask); uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
mChannelCount = channelCount; mChannelCount = channelCount;
if (audio_is_linear_pcm(format)) { if (audio_is_linear_pcm(format)) {
@ -235,24 +227,28 @@ status_t AudioRecord::set(
mFrameSize = sizeof(uint8_t); mFrameSize = sizeof(uint8_t);
} }
// mFrameCount is initialized in createRecord_l // mFrameCount is initialized in openRecord_l
mReqFrameCount = frameCount; mReqFrameCount = frameCount;
mNotificationFramesReq = notificationFrames; mNotificationFramesReq = notificationFrames;
// mNotificationFramesAct is initialized in createRecord_l // mNotificationFramesAct is initialized in openRecord_l
mSessionId = sessionId; if (sessionId == AUDIO_SESSION_ALLOCATE) {
mSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
} else {
mSessionId = sessionId;
}
ALOGV("set(): mSessionId %d", mSessionId); ALOGV("set(): mSessionId %d", mSessionId);
callingPid = IPCThreadState::self()->getCallingPid(); int callingpid = IPCThreadState::self()->getCallingPid();
myPid = getpid(); int mypid = getpid();
if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) { if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) {
mClientUid = IPCThreadState::self()->getCallingUid(); mClientUid = IPCThreadState::self()->getCallingUid();
} else { } else {
mClientUid = uid; mClientUid = uid;
} }
if (pid == -1 || (callingPid != myPid)) { if (pid == -1 || (callingpid != mypid)) {
mClientPid = callingPid; mClientPid = callingpid;
} else { } else {
mClientPid = pid; mClientPid = pid;
} }
@ -267,7 +263,7 @@ status_t AudioRecord::set(
} }
// create the IAudioRecord // create the IAudioRecord
status = createRecord_l(0 /*epoch*/, mOpPackageName); status_t status = openRecord_l(0 /*epoch*/, mOpPackageName);
if (status != NO_ERROR) { if (status != NO_ERROR) {
if (mAudioRecordThread != 0) { if (mAudioRecordThread != 0) {
@ -275,9 +271,10 @@ status_t AudioRecord::set(
mAudioRecordThread->requestExitAndWait(); mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear(); mAudioRecordThread.clear();
} }
goto exit; return status;
} }
mStatus = NO_ERROR;
mUserData = user; mUserData = user;
// TODO: add audio hardware input latency here // TODO: add audio hardware input latency here
mLatency = (1000LL * mFrameCount) / mSampleRate; mLatency = (1000LL * mFrameCount) / mSampleRate;
@ -292,9 +289,7 @@ status_t AudioRecord::set(
mFramesRead = 0; mFramesRead = 0;
mFramesReadServerOffset = 0; mFramesReadServerOffset = 0;
exit: return NO_ERROR;
mStatus = status;
return status;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -545,29 +540,70 @@ const char * AudioRecord::convertTransferToText(transfer_type transferType) {
} }
// must be called with mLock held // must be called with mLock held
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName) status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
{ {
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
IAudioFlinger::CreateRecordInput input;
IAudioFlinger::CreateRecordOutput output;
audio_session_t originalSessionId;
sp<media::IAudioRecord> record;
void *iMemPointer;
audio_track_cblk_t* cblk;
status_t status;
if (audioFlinger == 0) { if (audioFlinger == 0) {
ALOGE("Could not get audioflinger"); ALOGE("Could not get audioflinger");
status = NO_INIT; return NO_INIT;
goto exit;
} }
audio_io_handle_t input;
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted. // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
// After fast request is denied, we will request again if IAudioRecord is re-created. // After fast request is denied, we will request again if IAudioRecord is re-created.
status_t status;
// Not a conventional loop, but a retry loop for at most two iterations total.
// Try first maybe with FAST flag then try again without FAST flag if that fails.
// Exits loop normally via a return at the bottom, or with error via a break.
// The sp<> references will be dropped when re-entering scope.
// The lack of indentation is deliberate, to reduce code churn and ease merges.
for (;;) {
audio_config_base_t config = {
.sample_rate = mSampleRate,
.channel_mask = mChannelMask,
.format = mFormat
};
mRoutedDeviceId = mSelectedDeviceId;
status = AudioSystem::getInputForAttr(&mAttributes, &input,
mSessionId,
// FIXME compare to AudioTrack
mClientPid,
mClientUid,
&config,
mFlags, &mRoutedDeviceId, &mPortId);
if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
"format %#x, channel mask %#x, flags %#x",
mSessionId, mAttributes.source, mSampleRate, mFormat, mChannelMask, mFlags);
return BAD_VALUE;
}
// Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
// we must release it ourselves if anything goes wrong. // we must release it ourselves if anything goes wrong.
#if 0
size_t afFrameCount;
status = AudioSystem::getFrameCount(input, &afFrameCount);
if (status != NO_ERROR) {
ALOGE("getFrameCount(input=%d) status %d", input, status);
break;
}
#endif
uint32_t afSampleRate;
status = AudioSystem::getSamplingRate(input, &afSampleRate);
if (status != NO_ERROR) {
ALOGE("getSamplingRate(input=%d) status %d", input, status);
break;
}
if (mSampleRate == 0) {
mSampleRate = afSampleRate;
}
// Client can only express a preference for FAST. Server will perform additional tests. // Client can only express a preference for FAST. Server will perform additional tests.
if (mFlags & AUDIO_INPUT_FLAG_FAST) { if (mFlags & AUDIO_INPUT_FLAG_FAST) {
bool useCaseAllowed = bool useCaseAllowed =
@ -586,41 +622,66 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String
if (!useCaseAllowed) { if (!useCaseAllowed) {
ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
convertTransferToText(mTransfer)); convertTransferToText(mTransfer));
}
// sample rates must also match
bool sampleRateAllowed = mSampleRate == afSampleRate;
if (!sampleRateAllowed) {
ALOGW("AUDIO_INPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz",
mSampleRate, afSampleRate);
}
bool fastAllowed = useCaseAllowed && sampleRateAllowed;
if (!fastAllowed) {
mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST | mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
AUDIO_INPUT_FLAG_RAW)); AUDIO_INPUT_FLAG_RAW));
AudioSystem::releaseInput(input, mSessionId);
continue; // retry
} }
} }
input.attr = mAttributes; // The notification frame count is the period between callbacks, as suggested by the client
input.config.sample_rate = mSampleRate; // but moderated by the server. For record, the calculations are done entirely on server side.
input.config.channel_mask = mChannelMask; size_t notificationFrames = mNotificationFramesReq;
input.config.format = mFormat; size_t frameCount = mReqFrameCount;
input.clientInfo.clientUid = mClientUid;
input.clientInfo.clientPid = mClientPid; audio_input_flags_t flags = mFlags;
input.clientInfo.clientTid = -1;
pid_t tid = -1;
if (mFlags & AUDIO_INPUT_FLAG_FAST) { if (mFlags & AUDIO_INPUT_FLAG_FAST) {
if (mAudioRecordThread != 0) { if (mAudioRecordThread != 0) {
input.clientInfo.clientTid = mAudioRecordThread->getTid(); tid = mAudioRecordThread->getTid();
} }
} }
input.opPackageName = opPackageName;
input.flags = mFlags; size_t temp = frameCount; // temp may be replaced by a revised value of frameCount,
// The notification frame count is the period between callbacks, as suggested by the client // but we will still need the original value also
// but moderated by the server. For record, the calculations are done entirely on server side. audio_session_t originalSessionId = mSessionId;
input.frameCount = mReqFrameCount;
input.notificationFrameCount = mNotificationFramesReq; sp<IMemory> iMem; // for cblk
input.selectedDeviceId = mSelectedDeviceId; sp<IMemory> bufferMem;
input.sessionId = mSessionId; sp<media::IAudioRecord> record = audioFlinger->openRecord(input,
originalSessionId = mSessionId; mSampleRate,
mFormat,
record = audioFlinger->createRecord(input, mChannelMask,
output, opPackageName,
&status); &temp,
&flags,
mClientPid,
tid,
mClientUid,
&mSessionId,
&notificationFrames,
iMem,
bufferMem,
&status,
mPortId);
ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
"session ID changed from %d to %d", originalSessionId, mSessionId);
if (status != NO_ERROR) { if (status != NO_ERROR) {
ALOGE("AudioFlinger could not create record track, status: %d", status); ALOGE("AudioFlinger could not create record track, status: %d", status);
goto exit; break;
} }
ALOG_ASSERT(record != 0); ALOG_ASSERT(record != 0);
@ -628,41 +689,41 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String
// so we are no longer responsible for releasing it. // so we are no longer responsible for releasing it.
mAwaitBoost = false; mAwaitBoost = false;
if (output.flags & AUDIO_INPUT_FLAG_FAST) { if (mFlags & AUDIO_INPUT_FLAG_FAST) {
ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu", if (flags & AUDIO_INPUT_FLAG_FAST) {
mReqFrameCount, output.frameCount); ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu", frameCount, temp);
mAwaitBoost = true; mAwaitBoost = true;
} else {
ALOGW("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", frameCount, temp);
mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
AUDIO_INPUT_FLAG_RAW));
continue; // retry
}
} }
mFlags = output.flags; mFlags = flags;
mRoutedDeviceId = output.selectedDeviceId;
mSessionId = output.sessionId;
mSampleRate = output.sampleRate;
if (output.cblk == 0) { if (iMem == 0) {
ALOGE("Could not get control block"); ALOGE("Could not get control block");
status = NO_INIT; return NO_INIT;
goto exit;
} }
iMemPointer = output.cblk ->pointer(); void *iMemPointer = iMem->pointer();
if (iMemPointer == NULL) { if (iMemPointer == NULL) {
ALOGE("Could not get control block pointer"); ALOGE("Could not get control block pointer");
status = NO_INIT; return NO_INIT;
goto exit;
} }
cblk = static_cast<audio_track_cblk_t*>(iMemPointer); audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
// Starting address of buffers in shared memory. // Starting address of buffers in shared memory.
// The buffers are either immediately after the control block, // The buffers are either immediately after the control block,
// or in a separate area at discretion of server. // or in a separate area at discretion of server.
void *buffers; void *buffers;
if (output.buffers == 0) { if (bufferMem == 0) {
buffers = cblk + 1; buffers = cblk + 1;
} else { } else {
buffers = output.buffers->pointer(); buffers = bufferMem->pointer();
if (buffers == NULL) { if (buffers == NULL) {
ALOGE("Could not get buffer pointer"); ALOGE("Could not get buffer pointer");
status = NO_INIT; return NO_INIT;
goto exit;
} }
} }
@ -672,42 +733,43 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String
mDeathNotifier.clear(); mDeathNotifier.clear();
} }
mAudioRecord = record; mAudioRecord = record;
mCblkMemory = output.cblk; mCblkMemory = iMem;
mBufferMemory = output.buffers; mBufferMemory = bufferMem;
IPCThreadState::self()->flushCommands(); IPCThreadState::self()->flushCommands();
mCblk = cblk; mCblk = cblk;
// note that output.frameCount is the (possibly revised) value of mReqFrameCount // note that temp is the (possibly revised) value of frameCount
if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) { if (temp < frameCount || (frameCount == 0 && temp == 0)) {
ALOGW("Requested frameCount %zu but received frameCount %zu", ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp);
mReqFrameCount, output.frameCount);
} }
frameCount = temp;
// Make sure that application is notified with sufficient margin before overrun. // Make sure that application is notified with sufficient margin before overrun.
// The computation is done on server side. // The computation is done on server side.
if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) { if (mNotificationFramesReq > 0 && notificationFrames != mNotificationFramesReq) {
ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu", ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu",
mNotificationFramesReq, output.notificationFrameCount, output.frameCount); mNotificationFramesReq, notificationFrames, frameCount);
} }
mNotificationFramesAct = (uint32_t)output.notificationFrameCount; mNotificationFramesAct = (uint32_t) notificationFrames;
//mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
if (mDeviceCallback != 0 && mInput != output.inputId) { if (mDeviceCallback != 0 && mInput != input) {
if (mInput != AUDIO_IO_HANDLE_NONE) { if (mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mInput); AudioSystem::removeAudioDeviceCallback(this, mInput);
} }
AudioSystem::addAudioDeviceCallback(this, output.inputId); AudioSystem::addAudioDeviceCallback(this, input);
} }
// We retain a copy of the I/O handle, but don't own the reference // We retain a copy of the I/O handle, but don't own the reference
mInput = output.inputId; mInput = input;
mRefreshRemaining = true; mRefreshRemaining = true;
mFrameCount = output.frameCount; mFrameCount = frameCount;
// If IAudioRecord is re-created, don't let the requested frameCount // If IAudioRecord is re-created, don't let the requested frameCount
// decrease. This can confuse clients that cache frameCount(). // decrease. This can confuse clients that cache frameCount().
if (mFrameCount > mReqFrameCount) { if (frameCount > mReqFrameCount) {
mReqFrameCount = mFrameCount; mReqFrameCount = frameCount;
} }
// update proxy // update proxy
@ -718,9 +780,17 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String
mDeathNotifier = new DeathNotifier(this); mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this); IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
exit: return NO_ERROR;
mStatus = status;
// sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger // End of retry loop.
// The lack of indentation is deliberate, to reduce code churn and ease merges.
}
// Arrive here on error, via a break
AudioSystem::releaseInput(input, mSessionId);
if (status == NO_ERROR) {
status = NO_INIT;
}
return status; return status;
} }
@ -1152,12 +1222,12 @@ status_t AudioRecord::restoreRecord_l(const char *from)
mFlags = mOrigFlags; mFlags = mOrigFlags;
// if the new IAudioRecord is created, createRecord_l() will modify the // if the new IAudioRecord is created, openRecord_l() will modify the
// following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory. // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
// It will also delete the strong references on previous IAudioRecord and IMemory // It will also delete the strong references on previous IAudioRecord and IMemory
Modulo<uint32_t> position(mProxy->getPosition()); Modulo<uint32_t> position(mProxy->getPosition());
mNewPosition = position + mUpdatePeriod; mNewPosition = position + mUpdatePeriod;
status_t result = createRecord_l(position, mOpPackageName); status_t result = openRecord_l(position, mOpPackageName);
if (result == NO_ERROR) { if (result == NO_ERROR) {
if (mActive) { if (mActive) {
// callback thread or sync event hasn't changed // callback thread or sync event hasn't changed

@ -30,7 +30,7 @@ namespace android {
enum { enum {
CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION, CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION,
CREATE_RECORD, OPEN_RECORD,
SAMPLE_RATE, SAMPLE_RATE,
RESERVED, // obsolete, was CHANNEL_COUNT RESERVED, // obsolete, was CHANNEL_COUNT
FORMAT, FORMAT,
@ -130,39 +130,102 @@ public:
return track; return track;
} }
virtual sp<media::IAudioRecord> createRecord(const CreateRecordInput& input, virtual sp<media::IAudioRecord> openRecord(
CreateRecordOutput& output, audio_io_handle_t input,
status_t *status) uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *pFrameCount,
audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
audio_session_t *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers,
status_t *status,
audio_port_handle_t portId)
{ {
Parcel data, reply; Parcel data, reply;
sp<media::IAudioRecord> record; sp<media::IAudioRecord> record;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) input);
if (status == nullptr) { data.writeInt32(sampleRate);
return record; data.writeInt32(format);
data.writeInt32(channelMask);
data.writeString16(opPackageName);
size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt64(frameCount);
audio_input_flags_t lFlags = flags != NULL ? *flags : AUDIO_INPUT_FLAG_NONE;
data.writeInt32(lFlags);
data.writeInt32((int32_t) pid);
data.writeInt32((int32_t) tid);
data.writeInt32((int32_t) clientUid);
audio_session_t lSessionId = AUDIO_SESSION_ALLOCATE;
if (sessionId != NULL) {
lSessionId = *sessionId;
} }
data.writeInt32(lSessionId);
input.writeToParcel(&data); data.writeInt64(notificationFrames != NULL ? *notificationFrames : 0);
data.writeInt32(portId);
status_t lStatus = remote()->transact(CREATE_RECORD, data, &reply); cblk.clear();
buffers.clear();
status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
if (lStatus != NO_ERROR) { if (lStatus != NO_ERROR) {
ALOGE("createRecord transaction error %d", lStatus); ALOGE("openRecord error: %s", strerror(-lStatus));
*status = DEAD_OBJECT; } else {
return record; frameCount = reply.readInt64();
} if (pFrameCount != NULL) {
*status = reply.readInt32(); *pFrameCount = frameCount;
if (*status != NO_ERROR) { }
ALOGE("createRecord returned error %d", *status); lFlags = (audio_input_flags_t)reply.readInt32();
return record; if (flags != NULL) {
*flags = lFlags;
}
lSessionId = (audio_session_t) reply.readInt32();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
size_t lNotificationFrames = (size_t) reply.readInt64();
if (notificationFrames != NULL) {
*notificationFrames = lNotificationFrames;
}
lStatus = reply.readInt32();
record = interface_cast<media::IAudioRecord>(reply.readStrongBinder());
cblk = interface_cast<IMemory>(reply.readStrongBinder());
if (cblk != 0 && cblk->pointer() == NULL) {
cblk.clear();
}
buffers = interface_cast<IMemory>(reply.readStrongBinder());
if (buffers != 0 && buffers->pointer() == NULL) {
buffers.clear();
}
if (lStatus == NO_ERROR) {
if (record == 0) {
ALOGE("openRecord should have returned an IAudioRecord");
lStatus = UNKNOWN_ERROR;
} else if (cblk == 0) {
ALOGE("openRecord should have returned a cblk");
lStatus = NO_MEMORY;
}
// buffers is permitted to be 0
} else {
if (record != 0 || cblk != 0 || buffers != 0) {
ALOGE("openRecord returned an IAudioRecord, cblk, "
"or buffers but with status %d", lStatus);
}
}
if (lStatus != NO_ERROR) {
record.clear();
cblk.clear();
buffers.clear();
}
} }
if (status != NULL) {
record = interface_cast<media::IAudioRecord>(reply.readStrongBinder()); *status = lStatus;
if (record == 0) {
ALOGE("createRecord returned a NULL IAudioRecord with status OK");
*status = DEAD_OBJECT;
return record;
} }
output.readFromParcel(&reply);
return record; return record;
} }
@ -842,7 +905,7 @@ status_t BnAudioFlinger::onTransact(
// TODO should select more wisely the items from the list // TODO should select more wisely the items from the list
switch (code) { switch (code) {
case CREATE_TRACK: case CREATE_TRACK:
case CREATE_RECORD: case OPEN_RECORD:
case SET_MASTER_VOLUME: case SET_MASTER_VOLUME:
case SET_MASTER_MUTE: case SET_MASTER_MUTE:
case SET_STREAM_VOLUME: case SET_STREAM_VOLUME:
@ -885,29 +948,37 @@ status_t BnAudioFlinger::onTransact(
output.writeToParcel(reply); output.writeToParcel(reply);
return NO_ERROR; return NO_ERROR;
} break; } break;
case CREATE_RECORD: { case OPEN_RECORD: {
CHECK_INTERFACE(IAudioFlinger, data, reply); CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
CreateRecordInput input; uint32_t sampleRate = data.readInt32();
if (input.readFromParcel((Parcel*)&data) != NO_ERROR) { audio_format_t format = (audio_format_t) data.readInt32();
reply->writeInt32(DEAD_OBJECT); audio_channel_mask_t channelMask = data.readInt32();
return NO_ERROR; const String16& opPackageName = data.readString16();
} size_t frameCount = data.readInt64();
audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
status_t status; pid_t pid = (pid_t) data.readInt32();
CreateRecordOutput output; pid_t tid = (pid_t) data.readInt32();
int clientUid = data.readInt32();
sp<media::IAudioRecord> record = createRecord(input, audio_session_t sessionId = (audio_session_t) data.readInt32();
output, size_t notificationFrames = data.readInt64();
&status); audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
sp<IMemory> cblk;
sp<IMemory> buffers;
status_t status = NO_ERROR;
sp<media::IAudioRecord> record = openRecord(input,
sampleRate, format, channelMask, opPackageName, &frameCount, &flags,
pid, tid, clientUid, &sessionId, &notificationFrames, cblk, buffers,
&status, portId);
LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
reply->writeInt64(frameCount);
reply->writeInt32(flags);
reply->writeInt32(sessionId);
reply->writeInt64(notificationFrames);
reply->writeInt32(status); reply->writeInt32(status);
if (status != NO_ERROR) {
return NO_ERROR;
}
reply->writeStrongBinder(IInterface::asBinder(record)); reply->writeStrongBinder(IInterface::asBinder(record));
output.writeToParcel(reply); reply->writeStrongBinder(IInterface::asBinder(cblk));
reply->writeStrongBinder(IInterface::asBinder(buffers));
return NO_ERROR; return NO_ERROR;
} break; } break;
case SAMPLE_RATE: { case SAMPLE_RATE: {

@ -16,7 +16,6 @@
package android.media; package android.media;
/* Native code must specify namespace media (media::IAudioRecord) when referring to this class */
interface IAudioRecord { interface IAudioRecord {
/* After it's created the track is not active. Call start() to /* After it's created the track is not active. Call start() to

@ -19,13 +19,12 @@
#define ANDROID_AUDIO_CLIENT_H #define ANDROID_AUDIO_CLIENT_H
#include <binder/Parcel.h> #include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <system/audio.h> #include <system/audio.h>
#include <utils/String16.h> #include <utils/String16.h>
namespace android { namespace android {
class AudioClient : public Parcelable { class AudioClient {
public: public:
AudioClient() : AudioClient() :
clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {} clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {}
@ -35,7 +34,7 @@ class AudioClient : public Parcelable {
pid_t clientTid; pid_t clientTid;
String16 packageName; String16 packageName;
status_t readFromParcel(const Parcel *parcel) override { status_t readFromParcel(Parcel *parcel) {
clientUid = parcel->readInt32(); clientUid = parcel->readInt32();
clientPid = parcel->readInt32(); clientPid = parcel->readInt32();
clientTid = parcel->readInt32(); clientTid = parcel->readInt32();
@ -43,7 +42,7 @@ class AudioClient : public Parcelable {
return NO_ERROR; return NO_ERROR;
} }
status_t writeToParcel(Parcel *parcel) const override { status_t writeToParcel(Parcel *parcel) const {
parcel->writeInt32(clientUid); parcel->writeInt32(clientUid);
parcel->writeInt32(clientPid); parcel->writeInt32(clientPid);
parcel->writeInt32(clientTid); parcel->writeInt32(clientTid);

@ -570,7 +570,7 @@ private:
// caller must hold lock on mLock for all _l methods // caller must hold lock on mLock for all _l methods
status_t createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName); status_t openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);
// FIXME enum is faster than strcmp() for parameter 'from' // FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreRecord_l(const char *from); status_t restoreRecord_l(const char *from);
@ -682,6 +682,7 @@ private:
// May not match the app selection depending on other // May not match the app selection depending on other
// activity and connected devices // activity and connected devices
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback; wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
audio_port_handle_t mPortId; // unique ID allocated by audio policy
}; };

@ -231,7 +231,7 @@ public:
audio_stream_type_t stream, audio_stream_type_t stream,
audio_session_t session); audio_session_t session);
// Client must successfully hand off the handle reference to AudioFlinger via createRecord(), // Client must successfully hand off the handle reference to AudioFlinger via openRecord(),
// or release it with releaseInput(). // or release it with releaseInput().
static status_t getInputForAttr(const audio_attributes_t *attr, static status_t getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input, audio_io_handle_t *input,

@ -25,7 +25,6 @@
#include <utils/Errors.h> #include <utils/Errors.h>
#include <binder/IInterface.h> #include <binder/IInterface.h>
#include <binder/Parcel.h> #include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <media/AudioClient.h> #include <media/AudioClient.h>
#include <media/IAudioTrack.h> #include <media/IAudioTrack.h>
#include <media/IAudioFlingerClient.h> #include <media/IAudioFlingerClient.h>
@ -51,9 +50,9 @@ public:
* when calling createTrack() including arguments that will be updated by AudioFlinger * when calling createTrack() including arguments that will be updated by AudioFlinger
* and returned in CreateTrackOutput object * and returned in CreateTrackOutput object
*/ */
class CreateTrackInput : public Parcelable { class CreateTrackInput {
public: public:
status_t readFromParcel(const Parcel *parcel) override { status_t readFromParcel(Parcel *parcel) {
/* input arguments*/ /* input arguments*/
memset(&attr, 0, sizeof(audio_attributes_t)); memset(&attr, 0, sizeof(audio_attributes_t));
if (parcel->read(&attr, sizeof(audio_attributes_t)) != NO_ERROR) { if (parcel->read(&attr, sizeof(audio_attributes_t)) != NO_ERROR) {
@ -64,9 +63,7 @@ public:
if (parcel->read(&config, sizeof(audio_config_t)) != NO_ERROR) { if (parcel->read(&config, sizeof(audio_config_t)) != NO_ERROR) {
return DEAD_OBJECT; return DEAD_OBJECT;
} }
if (clientInfo.readFromParcel(parcel) != NO_ERROR) { (void)clientInfo.readFromParcel(parcel);
return DEAD_OBJECT;
}
if (parcel->readInt32() != 0) { if (parcel->readInt32() != 0) {
sharedBuffer = interface_cast<IMemory>(parcel->readStrongBinder()); sharedBuffer = interface_cast<IMemory>(parcel->readStrongBinder());
if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) { if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) {
@ -85,7 +82,7 @@ public:
return NO_ERROR; return NO_ERROR;
} }
status_t writeToParcel(Parcel *parcel) const override { status_t writeToParcel(Parcel *parcel) const {
/* input arguments*/ /* input arguments*/
(void)parcel->write(&attr, sizeof(audio_attributes_t)); (void)parcel->write(&attr, sizeof(audio_attributes_t));
(void)parcel->write(&config, sizeof(audio_config_t)); (void)parcel->write(&config, sizeof(audio_config_t));
@ -128,9 +125,9 @@ public:
* when calling createTrack() including arguments that were passed as I/O for update by * when calling createTrack() including arguments that were passed as I/O for update by
* CreateTrackInput. * CreateTrackInput.
*/ */
class CreateTrackOutput : public Parcelable { class CreateTrackOutput {
public: public:
status_t readFromParcel(const Parcel *parcel) override { status_t readFromParcel(Parcel *parcel) {
/* input/output arguments*/ /* input/output arguments*/
(void)parcel->read(&flags, sizeof(audio_output_flags_t)); (void)parcel->read(&flags, sizeof(audio_output_flags_t));
frameCount = parcel->readInt64(); frameCount = parcel->readInt64();
@ -147,7 +144,7 @@ public:
return NO_ERROR; return NO_ERROR;
} }
status_t writeToParcel(Parcel *parcel) const override { status_t writeToParcel(Parcel *parcel) const {
/* input/output arguments*/ /* input/output arguments*/
(void)parcel->write(&flags, sizeof(audio_output_flags_t)); (void)parcel->write(&flags, sizeof(audio_output_flags_t));
(void)parcel->writeInt64(frameCount); (void)parcel->writeInt64(frameCount);
@ -179,140 +176,6 @@ public:
audio_io_handle_t outputId; audio_io_handle_t outputId;
}; };
/* CreateRecordInput contains all input arguments sent by AudioRecord to AudioFlinger
* when calling createRecord() including arguments that will be updated by AudioFlinger
* and returned in CreateRecordOutput object
*/
class CreateRecordInput : public Parcelable {
public:
status_t readFromParcel(const Parcel *parcel) override {
/* input arguments*/
memset(&attr, 0, sizeof(audio_attributes_t));
if (parcel->read(&attr, sizeof(audio_attributes_t)) != NO_ERROR) {
return DEAD_OBJECT;
}
attr.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE -1] = '\0';
memset(&config, 0, sizeof(audio_config_base_t));
if (parcel->read(&config, sizeof(audio_config_base_t)) != NO_ERROR) {
return DEAD_OBJECT;
}
if (clientInfo.readFromParcel(parcel) != NO_ERROR) {
return DEAD_OBJECT;
}
opPackageName = parcel->readString16();
/* input/output arguments*/
(void)parcel->read(&flags, sizeof(audio_input_flags_t));
frameCount = parcel->readInt64();
notificationFrameCount = parcel->readInt64();
(void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
(void)parcel->read(&sessionId, sizeof(audio_session_t));
return NO_ERROR;
}
status_t writeToParcel(Parcel *parcel) const override {
/* input arguments*/
(void)parcel->write(&attr, sizeof(audio_attributes_t));
(void)parcel->write(&config, sizeof(audio_config_base_t));
(void)clientInfo.writeToParcel(parcel);
(void)parcel->writeString16(opPackageName);
/* input/output arguments*/
(void)parcel->write(&flags, sizeof(audio_input_flags_t));
(void)parcel->writeInt64(frameCount);
(void)parcel->writeInt64(notificationFrameCount);
(void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
(void)parcel->write(&sessionId, sizeof(audio_session_t));
return NO_ERROR;
}
/* input */
audio_attributes_t attr;
audio_config_base_t config;
AudioClient clientInfo;
String16 opPackageName;
/* input/output */
audio_input_flags_t flags;
size_t frameCount;
size_t notificationFrameCount;
audio_port_handle_t selectedDeviceId;
audio_session_t sessionId;
};
/* CreateRecordOutput contains all output arguments returned by AudioFlinger to AudioRecord
* when calling createRecord() including arguments that were passed as I/O for update by
* CreateRecordInput.
*/
class CreateRecordOutput : public Parcelable {
public:
status_t readFromParcel(const Parcel *parcel) override {
/* input/output arguments*/
(void)parcel->read(&flags, sizeof(audio_input_flags_t));
frameCount = parcel->readInt64();
notificationFrameCount = parcel->readInt64();
(void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
(void)parcel->read(&sessionId, sizeof(audio_session_t));
/* output arguments*/
sampleRate = parcel->readUint32();
(void)parcel->read(&inputId, sizeof(audio_io_handle_t));
if (parcel->readInt32() != 0) {
cblk = interface_cast<IMemory>(parcel->readStrongBinder());
if (cblk == 0 || cblk->pointer() == NULL) {
return BAD_VALUE;
}
}
if (parcel->readInt32() != 0) {
buffers = interface_cast<IMemory>(parcel->readStrongBinder());
if (buffers == 0 || buffers->pointer() == NULL) {
return BAD_VALUE;
}
}
return NO_ERROR;
}
status_t writeToParcel(Parcel *parcel) const override {
/* input/output arguments*/
(void)parcel->write(&flags, sizeof(audio_input_flags_t));
(void)parcel->writeInt64(frameCount);
(void)parcel->writeInt64(notificationFrameCount);
(void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
(void)parcel->write(&sessionId, sizeof(audio_session_t));
/* output arguments*/
(void)parcel->writeUint32(sampleRate);
(void)parcel->write(&inputId, sizeof(audio_io_handle_t));
if (cblk != 0) {
(void)parcel->writeInt32(1);
(void)parcel->writeStrongBinder(IInterface::asBinder(cblk));
} else {
(void)parcel->writeInt32(0);
}
if (buffers != 0) {
(void)parcel->writeInt32(1);
(void)parcel->writeStrongBinder(IInterface::asBinder(buffers));
} else {
(void)parcel->writeInt32(0);
}
return NO_ERROR;
}
/* input/output */
audio_input_flags_t flags;
size_t frameCount;
size_t notificationFrameCount;
audio_port_handle_t selectedDeviceId;
audio_session_t sessionId;
/* output */
uint32_t sampleRate;
audio_io_handle_t inputId;
sp<IMemory> cblk;
sp<IMemory> buffers;
};
// invariant on exit for all APIs that return an sp<>: // invariant on exit for all APIs that return an sp<>:
// (return value != 0) == (*status == NO_ERROR) // (return value != 0) == (*status == NO_ERROR)
@ -323,9 +186,26 @@ public:
CreateTrackOutput& output, CreateTrackOutput& output,
status_t *status) = 0; status_t *status) = 0;
virtual sp<media::IAudioRecord> createRecord(const CreateRecordInput& input, virtual sp<media::IAudioRecord> openRecord(
CreateRecordOutput& output, // On successful return, AudioFlinger takes over the handle
status_t *status) = 0; // reference and will release it when the track is destroyed.
// However on failure, the client is responsible for release.
audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
const String16& callingPackage,
size_t *pFrameCount,
audio_input_flags_t *flags,
pid_t pid,
pid_t tid, // -1 means unused, otherwise must be valid non-0
int clientUid,
audio_session_t *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers, // return value 0 means it follows cblk
status_t *status,
audio_port_handle_t portId) = 0;
// FIXME Surprisingly, format/latency don't work for input handles // FIXME Surprisingly, format/latency don't work for input handles

@ -674,11 +674,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
audio_session_t sessionId = input.sessionId; audio_session_t sessionId = input.sessionId;
if (sessionId == AUDIO_SESSION_ALLOCATE) { if (sessionId == AUDIO_SESSION_ALLOCATE) {
sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
} else if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
lStatus = BAD_VALUE;
goto Exit;
} }
output.sessionId = sessionId; output.sessionId = sessionId;
output.outputId = AUDIO_IO_HANDLE_NONE; output.outputId = AUDIO_IO_HANDLE_NONE;
output.selectedDeviceId = input.selectedDeviceId; output.selectedDeviceId = input.selectedDeviceId;
@ -1572,144 +1568,120 @@ void AudioFlinger::requestLogMerge() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
sp<media::IAudioRecord> AudioFlinger::createRecord(const CreateRecordInput& input, sp<media::IAudioRecord> AudioFlinger::openRecord(
CreateRecordOutput& output, audio_io_handle_t input,
status_t *status) uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *frameCount,
audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
audio_session_t *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers,
status_t *status,
audio_port_handle_t portId)
{ {
sp<RecordThread::RecordTrack> recordTrack; sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle; sp<RecordHandle> recordHandle;
sp<Client> client; sp<Client> client;
status_t lStatus; status_t lStatus;
audio_session_t sessionId = input.sessionId; audio_session_t lSessionId;
audio_port_handle_t portId;
output.cblk.clear(); cblk.clear();
output.buffers.clear(); buffers.clear();
bool updatePid = (input.clientInfo.clientPid == -1); bool updatePid = (pid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid(); const uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t clientUid = input.clientInfo.clientUid;
if (!isTrustedCallingUid(callingUid)) { if (!isTrustedCallingUid(callingUid)) {
ALOGW_IF(clientUid != callingUid, ALOGW_IF((uid_t)clientUid != callingUid,
"%s uid %d tried to pass itself off as %d", "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
__FUNCTION__, callingUid, clientUid);
clientUid = callingUid; clientUid = callingUid;
updatePid = true; updatePid = true;
} }
pid_t clientPid = input.clientInfo.clientPid;
if (updatePid) { if (updatePid) {
const pid_t callingPid = IPCThreadState::self()->getCallingPid(); const pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW_IF(clientPid != -1 && clientPid != callingPid, ALOGW_IF(pid != -1 && pid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d", "%s uid %d pid %d tried to pass itself off as pid %d",
__func__, callingUid, callingPid, clientPid); __func__, callingUid, callingPid, pid);
clientPid = callingPid; pid = callingPid;
} }
// check calling permissions // check calling permissions
if (!recordingAllowed(input.opPackageName, input.clientInfo.clientTid, clientUid)) { if (!recordingAllowed(opPackageName, tid, clientUid)) {
ALOGE("createRecord() permission denied: recording not allowed"); ALOGE("openRecord() permission denied: recording not allowed");
lStatus = PERMISSION_DENIED; lStatus = PERMISSION_DENIED;
goto Exit; goto Exit;
} }
// we don't yet support anything other than linear PCM
if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) { // further sample rate checks are performed by createRecordTrack_l()
ALOGE("createRecord() invalid format %#x", input.config.format); if (sampleRate == 0) {
ALOGE("openRecord() invalid sample rate %u", sampleRate);
lStatus = BAD_VALUE; lStatus = BAD_VALUE;
goto Exit; goto Exit;
} }
// further channel mask checks are performed by createRecordTrack_l() // we don't yet support anything other than linear PCM
if (!audio_is_input_channel(input.config.channel_mask)) { if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
ALOGE("createRecord() invalid channel mask %#x", input.config.channel_mask); ALOGE("openRecord() invalid format %#x", format);
lStatus = BAD_VALUE; lStatus = BAD_VALUE;
goto Exit; goto Exit;
} }
if (sessionId == AUDIO_SESSION_ALLOCATE) { // further channel mask checks are performed by createRecordTrack_l()
sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); if (!audio_is_input_channel(channelMask)) {
} else if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) { ALOGE("openRecord() invalid channel mask %#x", channelMask);
lStatus = BAD_VALUE; lStatus = BAD_VALUE;
goto Exit; goto Exit;
} }
output.sessionId = sessionId;
output.inputId = AUDIO_IO_HANDLE_NONE;
output.selectedDeviceId = input.selectedDeviceId;
output.flags = input.flags;
client = registerPid(clientPid);
// Not a conventional loop, but a retry loop for at most two iterations total.
// Try first maybe with FAST flag then try again without FAST flag if that fails.
// Exits loop via break on no error of got exit on error
// The sp<> references will be dropped when re-entering scope.
// The lack of indentation is deliberate, to reduce code churn and ease merges.
for (;;) {
lStatus = AudioSystem::getInputForAttr(&input.attr, &output.inputId,
sessionId,
// FIXME compare to AudioTrack
clientPid,
clientUid,
&input.config,
output.flags, &output.selectedDeviceId, &portId);
{ {
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mLock);
RecordThread *thread = checkRecordThread_l(output.inputId); RecordThread *thread = checkRecordThread_l(input);
if (thread == NULL) { if (thread == NULL) {
ALOGE("createRecord() checkRecordThread_l failed"); ALOGE("openRecord() checkRecordThread_l failed");
lStatus = BAD_VALUE; lStatus = BAD_VALUE;
goto Exit; goto Exit;
} }
ALOGV("createRecord() lSessionId: %d input %d", sessionId, output.inputId); client = registerPid(pid);
output.sampleRate = input.config.sample_rate;
output.frameCount = input.frameCount;
output.notificationFrameCount = input.notificationFrameCount;
recordTrack = thread->createRecordTrack_l(client, &output.sampleRate,
input.config.format, input.config.channel_mask,
&output.frameCount, sessionId,
&output.notificationFrameCount,
clientUid, &output.flags,
input.clientInfo.clientTid,
&lStatus, portId);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
// lStatus == BAD_TYPE means FAST flag was rejected: request a new input from if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
// audio policy manager without FAST constraint if (audio_unique_id_get_use(*sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
if (lStatus == BAD_TYPE) { lStatus = BAD_VALUE;
AudioSystem::releaseInput(output.inputId, sessionId); goto Exit;
recordTrack.clear(); }
continue; lSessionId = *sessionId;
} else {
// if no audio session id is provided, create one here
lSessionId = (audio_session_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
if (sessionId != NULL) {
*sessionId = lSessionId;
}
} }
ALOGV("openRecord() lSessionId: %d input %d", lSessionId, input);
if (lStatus != NO_ERROR) { recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
recordTrack.clear(); frameCount, lSessionId, notificationFrames,
goto Exit; clientUid, flags, tid, &lStatus, portId);
} LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
// Check if one effect chain was awaiting for an AudioRecord to be created on this if (lStatus == NO_ERROR) {
// session and move it to this thread. // Check if one effect chain was awaiting for an AudioRecord to be created on this
sp<EffectChain> chain = getOrphanEffectChain_l(sessionId); // session and move it to this thread.
if (chain != 0) { sp<EffectChain> chain = getOrphanEffectChain_l(lSessionId);
Mutex::Autolock _l(thread->mLock); if (chain != 0) {
thread->addEffectChain_l(chain); Mutex::Autolock _l(thread->mLock);
thread->addEffectChain_l(chain);
}
} }
break;
} }
// End of retry loop.
// The lack of indentation is deliberate, to reduce code churn and ease merges.
}
output.cblk = recordTrack->getCblk();
output.buffers = recordTrack->getBuffers();
// return handle to client
recordHandle = new RecordHandle(recordTrack);
Exit:
if (lStatus != NO_ERROR) { if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the RecordTrack so that the // remove local strong reference to Client before deleting the RecordTrack so that the
// Client destructor is called by the TrackBase destructor with mClientLock held // Client destructor is called by the TrackBase destructor with mClientLock held
@ -1719,8 +1691,17 @@ Exit:
Mutex::Autolock _cl(mClientLock); Mutex::Autolock _cl(mClientLock);
client.clear(); client.clear();
} }
recordTrack.clear();
goto Exit;
} }
cblk = recordTrack->getCblk();
buffers = recordTrack->getBuffers();
// return handle to client
recordHandle = new RecordHandle(recordTrack);
Exit:
*status = lStatus; *status = lStatus;
return recordHandle; return recordHandle;
} }

@ -118,9 +118,23 @@ public:
CreateTrackOutput& output, CreateTrackOutput& output,
status_t *status); status_t *status);
virtual sp<media::IAudioRecord> createRecord(const CreateRecordInput& input, virtual sp<media::IAudioRecord> openRecord(
CreateRecordOutput& output, audio_io_handle_t input,
status_t *status); uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *pFrameCount,
audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
audio_session_t *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers,
status_t *status /*non-NULL*/,
audio_port_handle_t portId);
virtual uint32_t sampleRate(audio_io_handle_t ioHandle) const; virtual uint32_t sampleRate(audio_io_handle_t ioHandle) const;
virtual audio_format_t format(audio_io_handle_t output) const; virtual audio_format_t format(audio_io_handle_t output) const;

@ -6708,12 +6708,12 @@ void AudioFlinger::RecordThread::inputStandBy()
// RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held // RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held
sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l( sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
const sp<AudioFlinger::Client>& client, const sp<AudioFlinger::Client>& client,
uint32_t *pSampleRate, uint32_t sampleRate,
audio_format_t format, audio_format_t format,
audio_channel_mask_t channelMask, audio_channel_mask_t channelMask,
size_t *pFrameCount, size_t *pFrameCount,
audio_session_t sessionId, audio_session_t sessionId,
size_t *pNotificationFrameCount, size_t *notificationFrames,
uid_t uid, uid_t uid,
audio_input_flags_t *flags, audio_input_flags_t *flags,
pid_t tid, pid_t tid,
@ -6721,30 +6721,16 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
audio_port_handle_t portId) audio_port_handle_t portId)
{ {
size_t frameCount = *pFrameCount; size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
sp<RecordTrack> track; sp<RecordTrack> track;
status_t lStatus; status_t lStatus;
audio_input_flags_t inputFlags = mInput->flags; audio_input_flags_t inputFlags = mInput->flags;
audio_input_flags_t requestedFlags = *flags;
uint32_t sampleRate;
lStatus = initCheck();
if (lStatus != NO_ERROR) {
ALOGE("createRecordTrack_l() audio driver not initialized");
goto Exit;
}
if (*pSampleRate == 0) {
*pSampleRate = mSampleRate;
}
sampleRate = *pSampleRate;
// special case for FAST flag considered OK if fast capture is present // special case for FAST flag considered OK if fast capture is present
if (hasFastCapture()) { if (hasFastCapture()) {
inputFlags = (audio_input_flags_t)(inputFlags | AUDIO_INPUT_FLAG_FAST); inputFlags = (audio_input_flags_t)(inputFlags | AUDIO_INPUT_FLAG_FAST);
} }
// Check if requested flags are compatible with input stream flags // Check if requested flags are compatible with output stream flags
if ((*flags & inputFlags) != *flags) { if ((*flags & inputFlags) != *flags) {
ALOGW("createRecordTrack_l(): mismatch between requested flags (%08x) and" ALOGW("createRecordTrack_l(): mismatch between requested flags (%08x) and"
" input flags (%08x)", " input flags (%08x)",
@ -6799,20 +6785,12 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
} }
} }
// If FAST or RAW flags were corrected, ask caller to request new input from audio policy
if ((*flags & AUDIO_INPUT_FLAG_FAST) !=
(requestedFlags & AUDIO_INPUT_FLAG_FAST)) {
*flags = (audio_input_flags_t) (*flags & ~(AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW));
lStatus = BAD_TYPE;
goto Exit;
}
// compute track buffer size in frames, and suggest the notification frame count // compute track buffer size in frames, and suggest the notification frame count
if (*flags & AUDIO_INPUT_FLAG_FAST) { if (*flags & AUDIO_INPUT_FLAG_FAST) {
// fast track: frame count is exactly the pipe depth // fast track: frame count is exactly the pipe depth
frameCount = mPipeFramesP2; frameCount = mPipeFramesP2;
// ignore requested notificationFrames, and always notify exactly once every HAL buffer // ignore requested notificationFrames, and always notify exactly once every HAL buffer
notificationFrameCount = mFrameCount; *notificationFrames = mFrameCount;
} else { } else {
// not fast track: max notification period is resampled equivalent of one HAL buffer time // not fast track: max notification period is resampled equivalent of one HAL buffer time
// or 20 ms if there is a fast capture // or 20 ms if there is a fast capture
@ -6831,12 +6809,17 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
const size_t minFrameCount = maxNotificationFrames * const size_t minFrameCount = maxNotificationFrames *
max(kMinNotifications, minNotificationsByMs); max(kMinNotifications, minNotificationsByMs);
frameCount = max(frameCount, minFrameCount); frameCount = max(frameCount, minFrameCount);
if (notificationFrameCount == 0 || notificationFrameCount > maxNotificationFrames) { if (*notificationFrames == 0 || *notificationFrames > maxNotificationFrames) {
notificationFrameCount = maxNotificationFrames; *notificationFrames = maxNotificationFrames;
} }
} }
*pFrameCount = frameCount; *pFrameCount = frameCount;
*pNotificationFrameCount = notificationFrameCount;
lStatus = initCheck();
if (lStatus != NO_ERROR) {
ALOGE("createRecordTrack_l() audio driver not initialized");
goto Exit;
}
{ // scope for mLock { // scope for mLock
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mLock);

@ -1327,12 +1327,12 @@ public:
sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l( sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l(
const sp<AudioFlinger::Client>& client, const sp<AudioFlinger::Client>& client,
uint32_t *pSampleRate, uint32_t sampleRate,
audio_format_t format, audio_format_t format,
audio_channel_mask_t channelMask, audio_channel_mask_t channelMask,
size_t *pFrameCount, size_t *pFrameCount,
audio_session_t sessionId, audio_session_t sessionId,
size_t *pNotificationFrameCount, size_t *notificationFrames,
uid_t uid, uid_t uid,
audio_input_flags_t *flags, audio_input_flags_t *flags,
pid_t tid, pid_t tid,

@ -192,7 +192,7 @@ protected:
// where for AudioTrack (but not AudioRecord), // where for AudioTrack (but not AudioRecord),
// 8-bit PCM samples are stored as 16-bit // 8-bit PCM samples are stored as 16-bit
const size_t mFrameCount;// size of track buffer given at createTrack() or const size_t mFrameCount;// size of track buffer given at createTrack() or
// createRecord(), and then adjusted as needed // openRecord(), and then adjusted as needed
const audio_session_t mSessionId; const audio_session_t mSessionId;
uid_t mUid; uid_t mUid;

Loading…
Cancel
Save