diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp index 741d084baa..2432cacb6e 100644 --- a/media/libaudioclient/AudioRecord.cpp +++ b/media/libaudioclient/AudioRecord.cpp @@ -69,7 +69,8 @@ AudioRecord::AudioRecord(const String16 &opPackageName) : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName), mSessionId(AUDIO_SESSION_ALLOCATE), 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), mPreviousPriority(ANDROID_PRIORITY_NORMAL), 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, uid, pid, pAttributes, selectedDeviceId); } @@ -149,11 +151,6 @@ status_t AudioRecord::set( const audio_attributes_t* pAttributes, 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, " "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s " "uid %d, pid %d", @@ -173,8 +170,7 @@ status_t AudioRecord::set( case TRANSFER_CALLBACK: if (cbf == NULL) { ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL"); - status = BAD_VALUE; - goto exit; + return BAD_VALUE; } break; case TRANSFER_OBTAIN: @@ -182,16 +178,14 @@ status_t AudioRecord::set( break; default: ALOGE("Invalid transfer type %d", transferType); - status = BAD_VALUE; - goto exit; + return BAD_VALUE; } mTransfer = transferType; // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { ALOGE("Track already in use"); - status = INVALID_OPERATION; - goto exit; + return INVALID_OPERATION; } if (pAttributes == NULL) { @@ -215,18 +209,16 @@ status_t AudioRecord::set( // AudioFlinger capture only supports linear PCM if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { ALOGE("Format %#x is not linear pcm", format); - status = BAD_VALUE; - goto exit; + return BAD_VALUE; } mFormat = format; if (!audio_is_input_channel(channelMask)) { ALOGE("Invalid channel mask %#x", channelMask); - status = BAD_VALUE; - goto exit; + return BAD_VALUE; } mChannelMask = channelMask; - channelCount = audio_channel_count_from_in_mask(channelMask); + uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); mChannelCount = channelCount; if (audio_is_linear_pcm(format)) { @@ -235,24 +227,28 @@ status_t AudioRecord::set( mFrameSize = sizeof(uint8_t); } - // mFrameCount is initialized in createRecord_l + // mFrameCount is initialized in openRecord_l mReqFrameCount = frameCount; 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); - callingPid = IPCThreadState::self()->getCallingPid(); - myPid = getpid(); - if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) { + int callingpid = IPCThreadState::self()->getCallingPid(); + int mypid = getpid(); + if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) { mClientUid = IPCThreadState::self()->getCallingUid(); } else { mClientUid = uid; } - if (pid == -1 || (callingPid != myPid)) { - mClientPid = callingPid; + if (pid == -1 || (callingpid != mypid)) { + mClientPid = callingpid; } else { mClientPid = pid; } @@ -267,7 +263,7 @@ status_t AudioRecord::set( } // create the IAudioRecord - status = createRecord_l(0 /*epoch*/, mOpPackageName); + status_t status = openRecord_l(0 /*epoch*/, mOpPackageName); if (status != NO_ERROR) { if (mAudioRecordThread != 0) { @@ -275,9 +271,10 @@ status_t AudioRecord::set( mAudioRecordThread->requestExitAndWait(); mAudioRecordThread.clear(); } - goto exit; + return status; } + mStatus = NO_ERROR; mUserData = user; // TODO: add audio hardware input latency here mLatency = (1000LL * mFrameCount) / mSampleRate; @@ -292,9 +289,7 @@ status_t AudioRecord::set( mFramesRead = 0; mFramesReadServerOffset = 0; -exit: - mStatus = status; - return status; + return NO_ERROR; } // ------------------------------------------------------------------------- @@ -545,29 +540,70 @@ const char * AudioRecord::convertTransferToText(transfer_type transferType) { } // must be called with mLock held -status_t AudioRecord::createRecord_l(const Modulo &epoch, const String16& opPackageName) +status_t AudioRecord::openRecord_l(const Modulo &epoch, const String16& opPackageName) { const sp& audioFlinger = AudioSystem::get_audio_flinger(); - IAudioFlinger::CreateRecordInput input; - IAudioFlinger::CreateRecordOutput output; - audio_session_t originalSessionId; - sp record; - void *iMemPointer; - audio_track_cblk_t* cblk; - status_t status; - if (audioFlinger == 0) { ALOGE("Could not get audioflinger"); - status = NO_INIT; - goto exit; + return NO_INIT; } + audio_io_handle_t input; + // 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. + 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, // 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. if (mFlags & AUDIO_INPUT_FLAG_FAST) { bool useCaseAllowed = @@ -586,41 +622,66 @@ status_t AudioRecord::createRecord_l(const Modulo &epoch, const String if (!useCaseAllowed) { ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", 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 | AUDIO_INPUT_FLAG_RAW)); + AudioSystem::releaseInput(input, mSessionId); + continue; // retry } } - input.attr = mAttributes; - input.config.sample_rate = mSampleRate; - input.config.channel_mask = mChannelMask; - input.config.format = mFormat; - input.clientInfo.clientUid = mClientUid; - input.clientInfo.clientPid = mClientPid; - input.clientInfo.clientTid = -1; + // The notification frame count is the period between callbacks, as suggested by the client + // but moderated by the server. For record, the calculations are done entirely on server side. + size_t notificationFrames = mNotificationFramesReq; + size_t frameCount = mReqFrameCount; + + audio_input_flags_t flags = mFlags; + + pid_t tid = -1; if (mFlags & AUDIO_INPUT_FLAG_FAST) { if (mAudioRecordThread != 0) { - input.clientInfo.clientTid = mAudioRecordThread->getTid(); + tid = mAudioRecordThread->getTid(); } } - input.opPackageName = opPackageName; - input.flags = mFlags; - // The notification frame count is the period between callbacks, as suggested by the client - // but moderated by the server. For record, the calculations are done entirely on server side. - input.frameCount = mReqFrameCount; - input.notificationFrameCount = mNotificationFramesReq; - input.selectedDeviceId = mSelectedDeviceId; - input.sessionId = mSessionId; - originalSessionId = mSessionId; - - record = audioFlinger->createRecord(input, - output, - &status); + size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, + // but we will still need the original value also + audio_session_t originalSessionId = mSessionId; + + sp iMem; // for cblk + sp bufferMem; + sp record = audioFlinger->openRecord(input, + mSampleRate, + mFormat, + mChannelMask, + opPackageName, + &temp, + &flags, + mClientPid, + tid, + mClientUid, + &mSessionId, + ¬ificationFrames, + 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) { ALOGE("AudioFlinger could not create record track, status: %d", status); - goto exit; + break; } ALOG_ASSERT(record != 0); @@ -628,41 +689,41 @@ status_t AudioRecord::createRecord_l(const Modulo &epoch, const String // so we are no longer responsible for releasing it. mAwaitBoost = false; - if (output.flags & AUDIO_INPUT_FLAG_FAST) { - ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu", - mReqFrameCount, output.frameCount); - mAwaitBoost = true; + if (mFlags & AUDIO_INPUT_FLAG_FAST) { + if (flags & AUDIO_INPUT_FLAG_FAST) { + ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu", frameCount, temp); + 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; - mRoutedDeviceId = output.selectedDeviceId; - mSessionId = output.sessionId; - mSampleRate = output.sampleRate; + mFlags = flags; - if (output.cblk == 0) { + if (iMem == 0) { ALOGE("Could not get control block"); - status = NO_INIT; - goto exit; + return NO_INIT; } - iMemPointer = output.cblk ->pointer(); + void *iMemPointer = iMem->pointer(); if (iMemPointer == NULL) { ALOGE("Could not get control block pointer"); - status = NO_INIT; - goto exit; + return NO_INIT; } - cblk = static_cast(iMemPointer); + audio_track_cblk_t* cblk = static_cast(iMemPointer); // Starting address of buffers in shared memory. // The buffers are either immediately after the control block, // or in a separate area at discretion of server. void *buffers; - if (output.buffers == 0) { + if (bufferMem == 0) { buffers = cblk + 1; } else { - buffers = output.buffers->pointer(); + buffers = bufferMem->pointer(); if (buffers == NULL) { ALOGE("Could not get buffer pointer"); - status = NO_INIT; - goto exit; + return NO_INIT; } } @@ -672,42 +733,43 @@ status_t AudioRecord::createRecord_l(const Modulo &epoch, const String mDeathNotifier.clear(); } mAudioRecord = record; - mCblkMemory = output.cblk; - mBufferMemory = output.buffers; + mCblkMemory = iMem; + mBufferMemory = bufferMem; IPCThreadState::self()->flushCommands(); mCblk = cblk; - // note that output.frameCount is the (possibly revised) value of mReqFrameCount - if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) { - ALOGW("Requested frameCount %zu but received frameCount %zu", - mReqFrameCount, output.frameCount); + // note that temp is the (possibly revised) value of frameCount + if (temp < frameCount || (frameCount == 0 && temp == 0)) { + ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp); } + frameCount = temp; // Make sure that application is notified with sufficient margin before overrun. // 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", - 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 - if (mDeviceCallback != 0 && mInput != output.inputId) { + if (mDeviceCallback != 0 && mInput != input) { if (mInput != AUDIO_IO_HANDLE_NONE) { 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 - mInput = output.inputId; + mInput = input; mRefreshRemaining = true; - mFrameCount = output.frameCount; + mFrameCount = frameCount; // If IAudioRecord is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). - if (mFrameCount > mReqFrameCount) { - mReqFrameCount = mFrameCount; + if (frameCount > mReqFrameCount) { + mReqFrameCount = frameCount; } // update proxy @@ -718,9 +780,17 @@ status_t AudioRecord::createRecord_l(const Modulo &epoch, const String mDeathNotifier = new DeathNotifier(this); IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this); -exit: - mStatus = status; - // sp track destructor will cause releaseOutput() to be called by AudioFlinger + return NO_ERROR; + + // 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; } @@ -1152,12 +1222,12 @@ status_t AudioRecord::restoreRecord_l(const char *from) 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. // It will also delete the strong references on previous IAudioRecord and IMemory Modulo position(mProxy->getPosition()); mNewPosition = position + mUpdatePeriod; - status_t result = createRecord_l(position, mOpPackageName); + status_t result = openRecord_l(position, mOpPackageName); if (result == NO_ERROR) { if (mActive) { // callback thread or sync event hasn't changed diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 56ddd4f9e6..2976d08c0f 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -31,7 +31,7 @@ namespace android { enum { CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION, - CREATE_RECORD, + OPEN_RECORD, SAMPLE_RATE, RESERVED, // obsolete, was CHANNEL_COUNT FORMAT, @@ -131,39 +131,102 @@ public: return track; } - virtual sp createRecord(const CreateRecordInput& input, - CreateRecordOutput& output, - status_t *status) + virtual sp openRecord( + audio_io_handle_t input, + 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& cblk, + sp& buffers, + status_t *status, + audio_port_handle_t portId) { Parcel data, reply; sp record; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - - if (status == nullptr) { - return record; + data.writeInt32((int32_t) input); + data.writeInt32(sampleRate); + 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; } - - input.writeToParcel(&data); - - status_t lStatus = remote()->transact(CREATE_RECORD, data, &reply); + data.writeInt32(lSessionId); + data.writeInt64(notificationFrames != NULL ? *notificationFrames : 0); + data.writeInt32(portId); + cblk.clear(); + buffers.clear(); + status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply); if (lStatus != NO_ERROR) { - ALOGE("createRecord transaction error %d", lStatus); - *status = DEAD_OBJECT; - return record; - } - *status = reply.readInt32(); - if (*status != NO_ERROR) { - ALOGE("createRecord returned error %d", *status); - return record; + ALOGE("openRecord error: %s", strerror(-lStatus)); + } else { + frameCount = reply.readInt64(); + if (pFrameCount != NULL) { + *pFrameCount = frameCount; + } + lFlags = (audio_input_flags_t)reply.readInt32(); + 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(reply.readStrongBinder()); + cblk = interface_cast(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } + buffers = interface_cast(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(); + } } - - record = interface_cast(reply.readStrongBinder()); - if (record == 0) { - ALOGE("createRecord returned a NULL IAudioRecord with status OK"); - *status = DEAD_OBJECT; - return record; + if (status != NULL) { + *status = lStatus; } - output.readFromParcel(&reply); return record; } @@ -872,7 +935,7 @@ status_t BnAudioFlinger::onTransact( // TODO should select more wisely the items from the list switch (code) { case CREATE_TRACK: - case CREATE_RECORD: + case OPEN_RECORD: case SET_MASTER_VOLUME: case SET_MASTER_MUTE: case SET_MIC_MUTE: @@ -912,29 +975,37 @@ status_t BnAudioFlinger::onTransact( output.writeToParcel(reply); return NO_ERROR; } break; - case CREATE_RECORD: { + case OPEN_RECORD: { CHECK_INTERFACE(IAudioFlinger, data, reply); - - CreateRecordInput input; - if (input.readFromParcel((Parcel*)&data) != NO_ERROR) { - reply->writeInt32(DEAD_OBJECT); - return NO_ERROR; - } - - status_t status; - CreateRecordOutput output; - - sp record = createRecord(input, - output, - &status); - + audio_io_handle_t input = (audio_io_handle_t) data.readInt32(); + uint32_t sampleRate = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); + audio_channel_mask_t channelMask = data.readInt32(); + const String16& opPackageName = data.readString16(); + size_t frameCount = data.readInt64(); + audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); + pid_t pid = (pid_t) data.readInt32(); + pid_t tid = (pid_t) data.readInt32(); + int clientUid = data.readInt32(); + audio_session_t sessionId = (audio_session_t) data.readInt32(); + size_t notificationFrames = data.readInt64(); + audio_port_handle_t portId = (audio_port_handle_t) data.readInt32(); + sp cblk; + sp buffers; + status_t status = NO_ERROR; + sp record = openRecord(input, + sampleRate, format, channelMask, opPackageName, &frameCount, &flags, + pid, tid, clientUid, &sessionId, ¬ificationFrames, cblk, buffers, + &status, portId); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); + reply->writeInt64(frameCount); + reply->writeInt32(flags); + reply->writeInt32(sessionId); + reply->writeInt64(notificationFrames); reply->writeInt32(status); - if (status != NO_ERROR) { - return NO_ERROR; - } reply->writeStrongBinder(IInterface::asBinder(record)); - output.writeToParcel(reply); + reply->writeStrongBinder(IInterface::asBinder(cblk)); + reply->writeStrongBinder(IInterface::asBinder(buffers)); return NO_ERROR; } break; case SAMPLE_RATE: { diff --git a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl index 7572671383..50ce78fffc 100644 --- a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl +++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl @@ -16,7 +16,6 @@ package android.media; -/* Native code must specify namespace media (media::IAudioRecord) when referring to this class */ interface IAudioRecord { /* After it's created the track is not active. Call start() to diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h index 247af9eafa..108e326ba2 100644 --- a/media/libaudioclient/include/media/AudioClient.h +++ b/media/libaudioclient/include/media/AudioClient.h @@ -19,13 +19,12 @@ #define ANDROID_AUDIO_CLIENT_H #include -#include #include #include namespace android { -class AudioClient : public Parcelable { +class AudioClient { public: AudioClient() : clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {} @@ -35,7 +34,7 @@ class AudioClient : public Parcelable { pid_t clientTid; String16 packageName; - status_t readFromParcel(const Parcel *parcel) override { + status_t readFromParcel(Parcel *parcel) { clientUid = parcel->readInt32(); clientPid = parcel->readInt32(); clientTid = parcel->readInt32(); @@ -43,7 +42,7 @@ class AudioClient : public Parcelable { return NO_ERROR; } - status_t writeToParcel(Parcel *parcel) const override { + status_t writeToParcel(Parcel *parcel) const { parcel->writeInt32(clientUid); parcel->writeInt32(clientPid); parcel->writeInt32(clientTid); diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h index 00c2a88d9c..51596a21a6 100644 --- a/media/libaudioclient/include/media/AudioRecord.h +++ b/media/libaudioclient/include/media/AudioRecord.h @@ -570,7 +570,7 @@ private: // caller must hold lock on mLock for all _l methods - status_t createRecord_l(const Modulo &epoch, const String16& opPackageName); + status_t openRecord_l(const Modulo &epoch, const String16& opPackageName); // FIXME enum is faster than strcmp() for parameter 'from' status_t restoreRecord_l(const char *from); @@ -682,6 +682,7 @@ private: // May not match the app selection depending on other // activity and connected devices wp mDeviceCallback; + audio_port_handle_t mPortId; // unique ID allocated by audio policy }; diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index 24a6e22ed6..66601da016 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -231,7 +231,7 @@ public: audio_stream_type_t stream, 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(). static status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h index 57d9778774..9061c268aa 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -51,9 +50,9 @@ public: * when calling createTrack() including arguments that will be updated by AudioFlinger * and returned in CreateTrackOutput object */ - class CreateTrackInput : public Parcelable { + class CreateTrackInput { public: - status_t readFromParcel(const Parcel *parcel) override { + status_t readFromParcel(Parcel *parcel) { /* input arguments*/ memset(&attr, 0, sizeof(audio_attributes_t)); 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) { return DEAD_OBJECT; } - if (clientInfo.readFromParcel(parcel) != NO_ERROR) { - return DEAD_OBJECT; - } + (void)clientInfo.readFromParcel(parcel); if (parcel->readInt32() != 0) { sharedBuffer = interface_cast(parcel->readStrongBinder()); if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) { @@ -85,7 +82,7 @@ public: return NO_ERROR; } - status_t writeToParcel(Parcel *parcel) const override { + status_t writeToParcel(Parcel *parcel) const { /* input arguments*/ (void)parcel->write(&attr, sizeof(audio_attributes_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 * CreateTrackInput. */ - class CreateTrackOutput : public Parcelable { + class CreateTrackOutput { public: - status_t readFromParcel(const Parcel *parcel) override { + status_t readFromParcel(Parcel *parcel) { /* input/output arguments*/ (void)parcel->read(&flags, sizeof(audio_output_flags_t)); frameCount = parcel->readInt64(); @@ -147,7 +144,7 @@ public: return NO_ERROR; } - status_t writeToParcel(Parcel *parcel) const override { + status_t writeToParcel(Parcel *parcel) const { /* input/output arguments*/ (void)parcel->write(&flags, sizeof(audio_output_flags_t)); (void)parcel->writeInt64(frameCount); @@ -179,140 +176,6 @@ public: 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(parcel->readStrongBinder()); - if (cblk == 0 || cblk->pointer() == NULL) { - return BAD_VALUE; - } - } - if (parcel->readInt32() != 0) { - buffers = interface_cast(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 cblk; - sp buffers; - }; - // invariant on exit for all APIs that return an sp<>: // (return value != 0) == (*status == NO_ERROR) @@ -323,9 +186,26 @@ public: CreateTrackOutput& output, status_t *status) = 0; - virtual sp createRecord(const CreateRecordInput& input, - CreateRecordOutput& output, - status_t *status) = 0; + virtual sp openRecord( + // On successful return, AudioFlinger takes over the handle + // 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& cblk, + sp& 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 diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index aeb32bba34..9cb0357f5e 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -674,11 +674,7 @@ sp AudioFlinger::createTrack(const CreateTrackInput& input, audio_session_t sessionId = input.sessionId; if (sessionId == AUDIO_SESSION_ALLOCATE) { 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.outputId = AUDIO_IO_HANDLE_NONE; output.selectedDeviceId = input.selectedDeviceId; @@ -1572,144 +1568,120 @@ void AudioFlinger::requestLogMerge() { // ---------------------------------------------------------------------------- -sp AudioFlinger::createRecord(const CreateRecordInput& input, - CreateRecordOutput& output, - status_t *status) +sp AudioFlinger::openRecord( + audio_io_handle_t input, + 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& cblk, + sp& buffers, + status_t *status, + audio_port_handle_t portId) { sp recordTrack; sp recordHandle; sp client; status_t lStatus; - audio_session_t sessionId = input.sessionId; - audio_port_handle_t portId; + audio_session_t lSessionId; - output.cblk.clear(); - output.buffers.clear(); + cblk.clear(); + buffers.clear(); - bool updatePid = (input.clientInfo.clientPid == -1); + bool updatePid = (pid == -1); const uid_t callingUid = IPCThreadState::self()->getCallingUid(); - uid_t clientUid = input.clientInfo.clientUid; if (!isTrustedCallingUid(callingUid)) { - ALOGW_IF(clientUid != callingUid, - "%s uid %d tried to pass itself off as %d", - __FUNCTION__, callingUid, clientUid); + ALOGW_IF((uid_t)clientUid != callingUid, + "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid); clientUid = callingUid; updatePid = true; } - pid_t clientPid = input.clientInfo.clientPid; + if (updatePid) { 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", - __func__, callingUid, callingPid, clientPid); - clientPid = callingPid; + __func__, callingUid, callingPid, pid); + pid = callingPid; } // check calling permissions - if (!recordingAllowed(input.opPackageName, input.clientInfo.clientTid, clientUid)) { - ALOGE("createRecord() permission denied: recording not allowed"); + if (!recordingAllowed(opPackageName, tid, clientUid)) { + ALOGE("openRecord() permission denied: recording not allowed"); lStatus = PERMISSION_DENIED; 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)) { - ALOGE("createRecord() invalid format %#x", input.config.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; } - // further channel mask checks are performed by createRecordTrack_l() - if (!audio_is_input_channel(input.config.channel_mask)) { - ALOGE("createRecord() invalid channel mask %#x", input.config.channel_mask); + // we don't yet support anything other than linear PCM + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { + ALOGE("openRecord() invalid format %#x", format); lStatus = BAD_VALUE; goto Exit; } - if (sessionId == AUDIO_SESSION_ALLOCATE) { - sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); - } else if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) { + // 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; } - 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); - RecordThread *thread = checkRecordThread_l(output.inputId); + RecordThread *thread = checkRecordThread_l(input); if (thread == NULL) { - ALOGE("createRecord() checkRecordThread_l failed"); + ALOGE("openRecord() checkRecordThread_l failed"); lStatus = BAD_VALUE; goto Exit; } - ALOGV("createRecord() lSessionId: %d input %d", sessionId, output.inputId); - - 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)); + client = registerPid(pid); - // lStatus == BAD_TYPE means FAST flag was rejected: request a new input from - // audio policy manager without FAST constraint - if (lStatus == BAD_TYPE) { - AudioSystem::releaseInput(output.inputId, sessionId); - recordTrack.clear(); - continue; + if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) { + if (audio_unique_id_get_use(*sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) { + lStatus = BAD_VALUE; + goto Exit; + } + 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.clear(); - goto Exit; - } + recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask, + frameCount, lSessionId, notificationFrames, + 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 - // session and move it to this thread. - sp chain = getOrphanEffectChain_l(sessionId); - if (chain != 0) { - Mutex::Autolock _l(thread->mLock); - thread->addEffectChain_l(chain); + if (lStatus == NO_ERROR) { + // Check if one effect chain was awaiting for an AudioRecord to be created on this + // session and move it to this thread. + sp chain = getOrphanEffectChain_l(lSessionId); + if (chain != 0) { + 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) { // remove local strong reference to Client before deleting the RecordTrack so that the // Client destructor is called by the TrackBase destructor with mClientLock held @@ -1719,8 +1691,17 @@ Exit: Mutex::Autolock _cl(mClientLock); client.clear(); } + recordTrack.clear(); + goto Exit; } + cblk = recordTrack->getCblk(); + buffers = recordTrack->getBuffers(); + + // return handle to client + recordHandle = new RecordHandle(recordTrack); + +Exit: *status = lStatus; return recordHandle; } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index bc73ffdcf4..506420c015 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -118,9 +118,23 @@ public: CreateTrackOutput& output, status_t *status); - virtual sp createRecord(const CreateRecordInput& input, - CreateRecordOutput& output, - status_t *status); + virtual sp openRecord( + audio_io_handle_t input, + 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& cblk, + sp& buffers, + status_t *status /*non-NULL*/, + audio_port_handle_t portId); virtual uint32_t sampleRate(audio_io_handle_t ioHandle) const; virtual audio_format_t format(audio_io_handle_t output) const; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 7636df6760..b2a1e18a57 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -6708,12 +6708,12 @@ void AudioFlinger::RecordThread::inputStandBy() // RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held sp AudioFlinger::RecordThread::createRecordTrack_l( const sp& client, - uint32_t *pSampleRate, + uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t *pFrameCount, audio_session_t sessionId, - size_t *pNotificationFrameCount, + size_t *notificationFrames, uid_t uid, audio_input_flags_t *flags, pid_t tid, @@ -6721,30 +6721,16 @@ sp AudioFlinger::RecordThread::createRe audio_port_handle_t portId) { size_t frameCount = *pFrameCount; - size_t notificationFrameCount = *pNotificationFrameCount; sp track; status_t lStatus; 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 if (hasFastCapture()) { 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) { ALOGW("createRecordTrack_l(): mismatch between requested flags (%08x) and" " input flags (%08x)", @@ -6799,20 +6785,12 @@ sp 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 if (*flags & AUDIO_INPUT_FLAG_FAST) { // fast track: frame count is exactly the pipe depth frameCount = mPipeFramesP2; // ignore requested notificationFrames, and always notify exactly once every HAL buffer - notificationFrameCount = mFrameCount; + *notificationFrames = mFrameCount; } else { // not fast track: max notification period is resampled equivalent of one HAL buffer time // or 20 ms if there is a fast capture @@ -6831,12 +6809,17 @@ sp AudioFlinger::RecordThread::createRe const size_t minFrameCount = maxNotificationFrames * max(kMinNotifications, minNotificationsByMs); frameCount = max(frameCount, minFrameCount); - if (notificationFrameCount == 0 || notificationFrameCount > maxNotificationFrames) { - notificationFrameCount = maxNotificationFrames; + if (*notificationFrames == 0 || *notificationFrames > maxNotificationFrames) { + *notificationFrames = maxNotificationFrames; } } *pFrameCount = frameCount; - *pNotificationFrameCount = notificationFrameCount; + + lStatus = initCheck(); + if (lStatus != NO_ERROR) { + ALOGE("createRecordTrack_l() audio driver not initialized"); + goto Exit; + } { // scope for mLock Mutex::Autolock _l(mLock); diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 17f26c5f03..c7b60d6d19 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1327,12 +1327,12 @@ public: sp createRecordTrack_l( const sp& client, - uint32_t *pSampleRate, + uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t *pFrameCount, audio_session_t sessionId, - size_t *pNotificationFrameCount, + size_t *notificationFrames, uid_t uid, audio_input_flags_t *flags, pid_t tid, diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index a3ea756d28..d4ce0b4348 100644 --- a/services/audioflinger/TrackBase.h +++ b/services/audioflinger/TrackBase.h @@ -192,7 +192,7 @@ protected: // where for AudioTrack (but not AudioRecord), // 8-bit PCM samples are stored as 16-bit 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; uid_t mUid;