diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp index 2432cacb6e..741d084baa 100644 --- a/media/libaudioclient/AudioRecord.cpp +++ b/media/libaudioclient/AudioRecord.cpp @@ -69,8 +69,7 @@ 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), - mPortId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE) { } @@ -97,10 +96,9 @@ AudioRecord::AudioRecord( mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), - mProxy(NULL), - mPortId(AUDIO_PORT_HANDLE_NONE) + mProxy(NULL) { - mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, + (void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags, uid, pid, pAttributes, selectedDeviceId); } @@ -151,6 +149,11 @@ 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", @@ -170,7 +173,8 @@ status_t AudioRecord::set( case TRANSFER_CALLBACK: if (cbf == NULL) { ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL"); - return BAD_VALUE; + status = BAD_VALUE; + goto exit; } break; case TRANSFER_OBTAIN: @@ -178,14 +182,16 @@ status_t AudioRecord::set( break; default: ALOGE("Invalid transfer type %d", transferType); - return BAD_VALUE; + status = BAD_VALUE; + goto exit; } mTransfer = transferType; // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { ALOGE("Track already in use"); - return INVALID_OPERATION; + status = INVALID_OPERATION; + goto exit; } if (pAttributes == NULL) { @@ -209,16 +215,18 @@ 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); - return BAD_VALUE; + status = BAD_VALUE; + goto exit; } mFormat = format; if (!audio_is_input_channel(channelMask)) { ALOGE("Invalid channel mask %#x", channelMask); - return BAD_VALUE; + status = BAD_VALUE; + goto exit; } mChannelMask = channelMask; - uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); + channelCount = audio_channel_count_from_in_mask(channelMask); mChannelCount = channelCount; if (audio_is_linear_pcm(format)) { @@ -227,28 +235,24 @@ status_t AudioRecord::set( mFrameSize = sizeof(uint8_t); } - // mFrameCount is initialized in openRecord_l + // mFrameCount is initialized in createRecord_l mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; - // mNotificationFramesAct is initialized in openRecord_l + // mNotificationFramesAct is initialized in createRecord_l - if (sessionId == AUDIO_SESSION_ALLOCATE) { - mSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); - } else { - mSessionId = sessionId; - } + mSessionId = sessionId; ALOGV("set(): mSessionId %d", mSessionId); - int callingpid = IPCThreadState::self()->getCallingPid(); - int mypid = getpid(); - if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) { + callingPid = IPCThreadState::self()->getCallingPid(); + 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; } @@ -263,7 +267,7 @@ status_t AudioRecord::set( } // create the IAudioRecord - status_t status = openRecord_l(0 /*epoch*/, mOpPackageName); + status = createRecord_l(0 /*epoch*/, mOpPackageName); if (status != NO_ERROR) { if (mAudioRecordThread != 0) { @@ -271,10 +275,9 @@ status_t AudioRecord::set( mAudioRecordThread->requestExitAndWait(); mAudioRecordThread.clear(); } - return status; + goto exit; } - mStatus = NO_ERROR; mUserData = user; // TODO: add audio hardware input latency here mLatency = (1000LL * mFrameCount) / mSampleRate; @@ -289,7 +292,9 @@ status_t AudioRecord::set( mFramesRead = 0; mFramesReadServerOffset = 0; - return NO_ERROR; +exit: + mStatus = status; + return status; } // ------------------------------------------------------------------------- @@ -540,70 +545,29 @@ const char * AudioRecord::convertTransferToText(transfer_type transferType) { } // must be called with mLock held -status_t AudioRecord::openRecord_l(const Modulo &epoch, const String16& opPackageName) +status_t AudioRecord::createRecord_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"); - return NO_INIT; + status = NO_INIT; + goto exit; } - 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 = @@ -622,66 +586,41 @@ status_t AudioRecord::openRecord_l(const Modulo &epoch, const String16 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 } } - // 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; + 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; if (mFlags & AUDIO_INPUT_FLAG_FAST) { if (mAudioRecordThread != 0) { - tid = mAudioRecordThread->getTid(); + input.clientInfo.clientTid = mAudioRecordThread->getTid(); } } + input.opPackageName = opPackageName; - 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); + 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); if (status != NO_ERROR) { ALOGE("AudioFlinger could not create record track, status: %d", status); - break; + goto exit; } ALOG_ASSERT(record != 0); @@ -689,41 +628,41 @@ status_t AudioRecord::openRecord_l(const Modulo &epoch, const String16 // so we are no longer responsible for releasing it. mAwaitBoost = false; - 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 - } + if (output.flags & AUDIO_INPUT_FLAG_FAST) { + ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu", + mReqFrameCount, output.frameCount); + mAwaitBoost = true; } - mFlags = flags; + mFlags = output.flags; + mRoutedDeviceId = output.selectedDeviceId; + mSessionId = output.sessionId; + mSampleRate = output.sampleRate; - if (iMem == 0) { + if (output.cblk == 0) { ALOGE("Could not get control block"); - return NO_INIT; + status = NO_INIT; + goto exit; } - void *iMemPointer = iMem->pointer(); + iMemPointer = output.cblk ->pointer(); if (iMemPointer == NULL) { ALOGE("Could not get control block pointer"); - return NO_INIT; + status = NO_INIT; + goto exit; } - audio_track_cblk_t* cblk = static_cast(iMemPointer); + 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 (bufferMem == 0) { + if (output.buffers == 0) { buffers = cblk + 1; } else { - buffers = bufferMem->pointer(); + buffers = output.buffers->pointer(); if (buffers == NULL) { ALOGE("Could not get buffer pointer"); - return NO_INIT; + status = NO_INIT; + goto exit; } } @@ -733,43 +672,42 @@ status_t AudioRecord::openRecord_l(const Modulo &epoch, const String16 mDeathNotifier.clear(); } mAudioRecord = record; - mCblkMemory = iMem; - mBufferMemory = bufferMem; + mCblkMemory = output.cblk; + mBufferMemory = output.buffers; IPCThreadState::self()->flushCommands(); mCblk = cblk; - // 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); + // 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); } - frameCount = temp; // Make sure that application is notified with sufficient margin before overrun. // The computation is done on server side. - if (mNotificationFramesReq > 0 && notificationFrames != mNotificationFramesReq) { + if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) { ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu", - mNotificationFramesReq, notificationFrames, frameCount); + mNotificationFramesReq, output.notificationFrameCount, output.frameCount); } - mNotificationFramesAct = (uint32_t) notificationFrames; - + mNotificationFramesAct = (uint32_t)output.notificationFrameCount; //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation - if (mDeviceCallback != 0 && mInput != input) { + if (mDeviceCallback != 0 && mInput != output.inputId) { if (mInput != AUDIO_IO_HANDLE_NONE) { AudioSystem::removeAudioDeviceCallback(this, mInput); } - AudioSystem::addAudioDeviceCallback(this, input); + AudioSystem::addAudioDeviceCallback(this, output.inputId); } // We retain a copy of the I/O handle, but don't own the reference - mInput = input; + mInput = output.inputId; mRefreshRemaining = true; - mFrameCount = frameCount; + mFrameCount = output.frameCount; // If IAudioRecord is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). - if (frameCount > mReqFrameCount) { - mReqFrameCount = frameCount; + if (mFrameCount > mReqFrameCount) { + mReqFrameCount = mFrameCount; } // update proxy @@ -780,17 +718,9 @@ status_t AudioRecord::openRecord_l(const Modulo &epoch, const String16 mDeathNotifier = new DeathNotifier(this); IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this); - 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; - } +exit: + mStatus = status; + // sp track destructor will cause releaseOutput() to be called by AudioFlinger return status; } @@ -1222,12 +1152,12 @@ status_t AudioRecord::restoreRecord_l(const char *from) mFlags = mOrigFlags; - // if the new IAudioRecord is created, openRecord_l() will modify the + // if the new IAudioRecord is created, createRecord_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 = openRecord_l(position, mOpPackageName); + status_t result = createRecord_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 5cf2bdbb16..5db60f37d4 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -30,7 +30,7 @@ namespace android { enum { CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION, - OPEN_RECORD, + CREATE_RECORD, SAMPLE_RATE, RESERVED, // obsolete, was CHANNEL_COUNT FORMAT, @@ -130,102 +130,39 @@ public: return track; } - 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) + virtual sp createRecord(const CreateRecordInput& input, + CreateRecordOutput& output, + status_t *status) { Parcel data, reply; sp record; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - 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; + + if (status == nullptr) { + return record; } - 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); + + input.writeToParcel(&data); + + status_t lStatus = remote()->transact(CREATE_RECORD, data, &reply); if (lStatus != NO_ERROR) { - 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(); - } + ALOGE("createRecord transaction error %d", lStatus); + *status = DEAD_OBJECT; + return record; } - if (status != NULL) { - *status = lStatus; + *status = reply.readInt32(); + if (*status != NO_ERROR) { + ALOGE("createRecord returned error %d", *status); + return record; } + + record = interface_cast(reply.readStrongBinder()); + if (record == 0) { + ALOGE("createRecord returned a NULL IAudioRecord with status OK"); + *status = DEAD_OBJECT; + return record; + } + output.readFromParcel(&reply); return record; } @@ -905,7 +842,7 @@ status_t BnAudioFlinger::onTransact( // TODO should select more wisely the items from the list switch (code) { case CREATE_TRACK: - case OPEN_RECORD: + case CREATE_RECORD: case SET_MASTER_VOLUME: case SET_MASTER_MUTE: case SET_STREAM_VOLUME: @@ -948,37 +885,29 @@ status_t BnAudioFlinger::onTransact( output.writeToParcel(reply); return NO_ERROR; } break; - case OPEN_RECORD: { + case CREATE_RECORD: { CHECK_INTERFACE(IAudioFlinger, data, reply); - 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); + + 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); + 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)); - reply->writeStrongBinder(IInterface::asBinder(cblk)); - reply->writeStrongBinder(IInterface::asBinder(buffers)); + output.writeToParcel(reply); 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 50ce78fffc..7572671383 100644 --- a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl +++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl @@ -16,6 +16,7 @@ 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 108e326ba2..247af9eafa 100644 --- a/media/libaudioclient/include/media/AudioClient.h +++ b/media/libaudioclient/include/media/AudioClient.h @@ -19,12 +19,13 @@ #define ANDROID_AUDIO_CLIENT_H #include +#include #include #include namespace android { -class AudioClient { +class AudioClient : public Parcelable { public: AudioClient() : clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {} @@ -34,7 +35,7 @@ class AudioClient { pid_t clientTid; String16 packageName; - status_t readFromParcel(Parcel *parcel) { + status_t readFromParcel(const Parcel *parcel) override { clientUid = parcel->readInt32(); clientPid = parcel->readInt32(); clientTid = parcel->readInt32(); @@ -42,7 +43,7 @@ class AudioClient { return NO_ERROR; } - status_t writeToParcel(Parcel *parcel) const { + status_t writeToParcel(Parcel *parcel) const override { 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 51596a21a6..00c2a88d9c 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 openRecord_l(const Modulo &epoch, const String16& opPackageName); + status_t createRecord_l(const Modulo &epoch, const String16& opPackageName); // FIXME enum is faster than strcmp() for parameter 'from' status_t restoreRecord_l(const char *from); @@ -682,7 +682,6 @@ 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 66601da016..24a6e22ed6 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 openRecord(), + // Client must successfully hand off the handle reference to AudioFlinger via createRecord(), // 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 9061c268aa..57d9778774 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -50,9 +51,9 @@ public: * when calling createTrack() including arguments that will be updated by AudioFlinger * and returned in CreateTrackOutput object */ - class CreateTrackInput { + class CreateTrackInput : public Parcelable { public: - status_t readFromParcel(Parcel *parcel) { + 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) { @@ -63,7 +64,9 @@ public: if (parcel->read(&config, sizeof(audio_config_t)) != NO_ERROR) { return DEAD_OBJECT; } - (void)clientInfo.readFromParcel(parcel); + if (clientInfo.readFromParcel(parcel) != NO_ERROR) { + return DEAD_OBJECT; + } if (parcel->readInt32() != 0) { sharedBuffer = interface_cast(parcel->readStrongBinder()); if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) { @@ -82,7 +85,7 @@ public: return NO_ERROR; } - status_t writeToParcel(Parcel *parcel) const { + status_t writeToParcel(Parcel *parcel) const override { /* input arguments*/ (void)parcel->write(&attr, sizeof(audio_attributes_t)); (void)parcel->write(&config, sizeof(audio_config_t)); @@ -125,9 +128,9 @@ public: * when calling createTrack() including arguments that were passed as I/O for update by * CreateTrackInput. */ - class CreateTrackOutput { + class CreateTrackOutput : public Parcelable { public: - status_t readFromParcel(Parcel *parcel) { + status_t readFromParcel(const Parcel *parcel) override { /* input/output arguments*/ (void)parcel->read(&flags, sizeof(audio_output_flags_t)); frameCount = parcel->readInt64(); @@ -144,7 +147,7 @@ public: return NO_ERROR; } - status_t writeToParcel(Parcel *parcel) const { + status_t writeToParcel(Parcel *parcel) const override { /* input/output arguments*/ (void)parcel->write(&flags, sizeof(audio_output_flags_t)); (void)parcel->writeInt64(frameCount); @@ -176,6 +179,140 @@ 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) @@ -186,26 +323,9 @@ public: CreateTrackOutput& 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; + virtual sp createRecord(const CreateRecordInput& input, + CreateRecordOutput& output, + status_t *status) = 0; // FIXME Surprisingly, format/latency don't work for input handles diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 9cb0357f5e..aeb32bba34 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -674,7 +674,11 @@ 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; @@ -1568,120 +1572,144 @@ void AudioFlinger::requestLogMerge() { // ---------------------------------------------------------------------------- -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 AudioFlinger::createRecord(const CreateRecordInput& input, + CreateRecordOutput& output, + status_t *status) { sp recordTrack; sp recordHandle; sp client; status_t lStatus; - audio_session_t lSessionId; + audio_session_t sessionId = input.sessionId; + audio_port_handle_t portId; - cblk.clear(); - buffers.clear(); + output.cblk.clear(); + output.buffers.clear(); - bool updatePid = (pid == -1); + bool updatePid = (input.clientInfo.clientPid == -1); const uid_t callingUid = IPCThreadState::self()->getCallingUid(); + uid_t clientUid = input.clientInfo.clientUid; if (!isTrustedCallingUid(callingUid)) { - ALOGW_IF((uid_t)clientUid != callingUid, - "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid); + ALOGW_IF(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(pid != -1 && pid != callingPid, + ALOGW_IF(clientPid != -1 && clientPid != callingPid, "%s uid %d pid %d tried to pass itself off as pid %d", - __func__, callingUid, callingPid, pid); - pid = callingPid; + __func__, callingUid, callingPid, clientPid); + clientPid = callingPid; } // check calling permissions - if (!recordingAllowed(opPackageName, tid, clientUid)) { - ALOGE("openRecord() permission denied: recording not allowed"); + if (!recordingAllowed(input.opPackageName, input.clientInfo.clientTid, clientUid)) { + ALOGE("createRecord() permission denied: recording not allowed"); lStatus = PERMISSION_DENIED; goto Exit; } - - // further sample rate checks are performed by createRecordTrack_l() - if (sampleRate == 0) { - ALOGE("openRecord() invalid sample rate %u", sampleRate); + // 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); lStatus = BAD_VALUE; goto Exit; } - // 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); + // 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); lStatus = BAD_VALUE; goto Exit; } - // further channel mask checks are performed by createRecordTrack_l() - if (!audio_is_input_channel(channelMask)) { - ALOGE("openRecord() invalid channel mask %#x", channelMask); + 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.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(input); + RecordThread *thread = checkRecordThread_l(output.inputId); if (thread == NULL) { - ALOGE("openRecord() checkRecordThread_l failed"); + ALOGE("createRecord() checkRecordThread_l failed"); lStatus = BAD_VALUE; goto Exit; } - client = registerPid(pid); + ALOGV("createRecord() lSessionId: %d input %d", sessionId, output.inputId); - 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); + output.sampleRate = input.config.sample_rate; + output.frameCount = input.frameCount; + output.notificationFrameCount = input.notificationFrameCount; - recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask, - frameCount, lSessionId, notificationFrames, - clientUid, flags, tid, &lStatus, portId); + 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)); - 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); - } + // 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 (lStatus != NO_ERROR) { + recordTrack.clear(); + goto Exit; + } + + // 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); } + 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 @@ -1691,17 +1719,8 @@ sp AudioFlinger::openRecord( 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 506420c015..bc73ffdcf4 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -118,23 +118,9 @@ public: CreateTrackOutput& 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 sp createRecord(const CreateRecordInput& input, + CreateRecordOutput& output, + status_t *status); 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 b2a1e18a57..7636df6760 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 sampleRate, + uint32_t *pSampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t *pFrameCount, audio_session_t sessionId, - size_t *notificationFrames, + size_t *pNotificationFrameCount, uid_t uid, audio_input_flags_t *flags, pid_t tid, @@ -6721,16 +6721,30 @@ 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 output stream flags + // Check if requested flags are compatible with input stream flags if ((*flags & inputFlags) != *flags) { ALOGW("createRecordTrack_l(): mismatch between requested flags (%08x) and" " input flags (%08x)", @@ -6785,12 +6799,20 @@ 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 - *notificationFrames = mFrameCount; + notificationFrameCount = 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 @@ -6809,17 +6831,12 @@ sp AudioFlinger::RecordThread::createRe const size_t minFrameCount = maxNotificationFrames * max(kMinNotifications, minNotificationsByMs); frameCount = max(frameCount, minFrameCount); - if (*notificationFrames == 0 || *notificationFrames > maxNotificationFrames) { - *notificationFrames = maxNotificationFrames; + if (notificationFrameCount == 0 || notificationFrameCount > maxNotificationFrames) { + notificationFrameCount = maxNotificationFrames; } } *pFrameCount = frameCount; - - lStatus = initCheck(); - if (lStatus != NO_ERROR) { - ALOGE("createRecordTrack_l() audio driver not initialized"); - goto Exit; - } + *pNotificationFrameCount = notificationFrameCount; { // scope for mLock Mutex::Autolock _l(mLock); diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index c7b60d6d19..17f26c5f03 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1327,12 +1327,12 @@ public: sp createRecordTrack_l( const sp& client, - uint32_t sampleRate, + uint32_t *pSampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t *pFrameCount, audio_session_t sessionId, - size_t *notificationFrames, + size_t *pNotificationFrameCount, uid_t uid, audio_input_flags_t *flags, pid_t tid, diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index d4ce0b4348..a3ea756d28 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 - // openRecord(), and then adjusted as needed + // createRecord(), and then adjusted as needed const audio_session_t mSessionId; uid_t mUid;