Loading media/libaudioclient/AudioRecord.cpp +92 −59 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <inttypes.h> #include <android-base/macros.h> #include <android-base/stringprintf.h> #include <sys/resource.h> #include <audio_utils/format.h> Loading @@ -40,6 +41,7 @@ namespace android { using ::android::base::StringPrintf; using android::content::AttributionSourceState; using aidl_utils::statusTFromBinderStatus; Loading Loading @@ -304,7 +306,6 @@ status_t AudioRecord::set( int32_t maxSharedAudioHistoryMs) { status_t status = NO_ERROR; uint32_t channelCount; const sp<IAudioRecordCallback> callbackHandle = callback.promote(); // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set. ALOGV("%s(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " Loading Loading @@ -336,80 +337,82 @@ status_t AudioRecord::set( mSelectedMicFieldDimension = microphoneFieldDimension; mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs; switch (transferType) { std::string errorMessage; // Copy the state variables early so they are available for error reporting. if (pAttributes == nullptr) { mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; mAttributes.source = inputSource; if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION || inputSource == AUDIO_SOURCE_CAMCORDER) { mAttributes.flags = static_cast<audio_flags_mask_t>( mAttributes.flags | AUDIO_FLAG_CAPTURE_PRIVATE); } } else { // stream type shouldn't be looked at, this track has audio attributes memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); ALOGV("%s: Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]", __func__, mAttributes.source, mAttributes.flags, mAttributes.tags); } mSampleRate = sampleRate; if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } mFormat = format; mChannelMask = channelMask; mSessionId = sessionId; ALOGV("%s: mSessionId %d", __func__, mSessionId); mOrigFlags = mFlags = flags; mTransfer = transferType; switch (mTransfer) { case TRANSFER_DEFAULT: if (callbackHandle == nullptr || threadCanCallJava) { transferType = TRANSFER_SYNC; mTransfer = TRANSFER_SYNC; } else { transferType = TRANSFER_CALLBACK; mTransfer = TRANSFER_CALLBACK; } break; case TRANSFER_CALLBACK: if (callbackHandle == nullptr) { ALOGE("%s(): Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__); errorMessage = StringPrintf( "%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__); status = BAD_VALUE; goto exit; goto error; } break; case TRANSFER_OBTAIN: case TRANSFER_SYNC: break; default: ALOGE("%s(): Invalid transfer type %d", __func__, transferType); errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer); status = BAD_VALUE; goto exit; goto error; } mTransfer = transferType; // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { ALOGE("%s(): Track already in use", __func__); errorMessage = StringPrintf("%s: Track already in use", __func__); status = INVALID_OPERATION; goto exit; goto error; } if (pAttributes == nullptr) { mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; mAttributes.source = inputSource; if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION || inputSource == AUDIO_SOURCE_CAMCORDER) { mAttributes.flags = static_cast<audio_flags_mask_t>( mAttributes.flags | AUDIO_FLAG_CAPTURE_PRIVATE); } } else { // stream type shouldn't be looked at, this track has audio attributes memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); ALOGV("%s(): Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]", __func__, mAttributes.source, mAttributes.flags, mAttributes.tags); } mSampleRate = sampleRate; // these below should probably come from the audioFlinger too... if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } // validate parameters // AudioFlinger capture only supports linear PCM if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { ALOGE("%s(): Format %#x is not linear pcm", __func__, format); if (!audio_is_valid_format(mFormat) || !audio_is_linear_pcm(mFormat)) { errorMessage = StringPrintf("%s: Format %#x is not linear pcm", __func__, mFormat); status = BAD_VALUE; goto exit; goto error; } mFormat = format; if (!audio_is_input_channel(channelMask)) { ALOGE("%s(): Invalid channel mask %#x", __func__, channelMask); if (!audio_is_input_channel(mChannelMask)) { errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask); status = BAD_VALUE; goto exit; goto error; } mChannelMask = channelMask; channelCount = audio_channel_count_from_in_mask(channelMask); mChannelCount = channelCount; if (audio_is_linear_pcm(format)) { mFrameSize = channelCount * audio_bytes_per_sample(format); mChannelCount = audio_channel_count_from_in_mask(mChannelMask); if (audio_is_linear_pcm(mFormat)) { mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat); } else { mFrameSize = sizeof(uint8_t); } Loading @@ -420,12 +423,7 @@ status_t AudioRecord::set( mNotificationFramesReq = notificationFrames; // mNotificationFramesAct is initialized in createRecord_l mSessionId = sessionId; ALOGV("%s(): mSessionId %d", __func__, mSessionId); mOrigFlags = mFlags = flags; mCallback = callbackHandle; if (mCallback != nullptr) { mAudioRecordThread = new AudioRecordThread(*this); mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO); Loading @@ -446,6 +444,7 @@ status_t AudioRecord::set( mAudioRecordThread->requestExitAndWait(); mAudioRecordThread.clear(); } // bypass error message to avoid logging twice (createRecord_l logs the error). goto exit; } Loading @@ -462,11 +461,14 @@ status_t AudioRecord::set( mFramesRead = 0; mFramesReadServerOffset = 0; exit: mStatus = status; error: if (status != NO_ERROR) { mMediaMetrics.markError(status, __FUNCTION__); ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str()); reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str()); } exit: mStatus = status; return status; } Loading Loading @@ -857,9 +859,10 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) status_t status; static const int32_t kMaxCreateAttempts = 3; int32_t remainingAttempts = kMaxCreateAttempts; std::string errorMessage; if (audioFlinger == 0) { ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId); errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId); status = NO_INIT; goto exit; } Loading Loading @@ -925,7 +928,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) break; } if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) { ALOGE("%s(%d): AudioFlinger could not create record track, status: %d", errorMessage = StringPrintf( "%s(%d): AudioFlinger could not create record track, status: %d", __func__, mPortId, status); goto exit; } Loading Loading @@ -959,7 +963,7 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) mServerSampleSize = audio_bytes_per_sample(mServerConfig.format); if (output.cblk == 0) { ALOGE("%s(%d): Could not get control block", __func__, mPortId); errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId); status = NO_INIT; goto exit; } Loading @@ -969,7 +973,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) // issue (e.g. by copying). iMemPointer = output.cblk ->unsecurePointer(); if (iMemPointer == NULL) { ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId); errorMessage = StringPrintf( "%s(%d): Could not get control block pointer", __func__, mPortId); status = NO_INIT; goto exit; } Loading @@ -988,7 +993,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) // issue (e.g. by copying). buffers = output.buffers->unsecurePointer(); if (buffers == NULL) { ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId); errorMessage = StringPrintf( "%s(%d): Could not get buffer pointer", __func__, mPortId); status = NO_INIT; goto exit; } Loading Loading @@ -1083,11 +1089,38 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) .record(); exit: if (status != NO_ERROR) { ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str()); reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str()); } mStatus = status; // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger return status; } // Report error associated with the event and some configuration details. void AudioRecord::reportError(status_t status, const char *event, const char *message) const { if (status == NO_ERROR) return; // We report error on the native side because some callers do not come // from Java. // Ensure these variables are initialized in set(). mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR) .set(AMEDIAMETRICS_PROP_EVENT, event) .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status) .set(AMEDIAMETRICS_PROP_STATUSMESSAGE, message) .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str()) .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId) .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str()) .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId) .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str()) .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask) .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount) .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate) .record(); } status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig) { if (audioBuffer == NULL) { Loading media/libaudioclient/include/media/AudioRecord.h +2 −0 Original line number Diff line number Diff line Loading @@ -890,6 +890,8 @@ private: MediaMetrics mMediaMetrics; std::string mMetricsId; // GUARDED_BY(mLock), could change in createRecord_l(). std::string mCallerName; // for example "aaudio" void reportError(status_t status, const char *event, const char *message) const; }; }; // namespace android Loading media/libmediametrics/include/MediaMetricsConstants.h +1 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ // Error keys #define AMEDIAMETRICS_KEY_AUDIO_TRACK_ERROR AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "error" #define AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "error" /* * MediaMetrics Properties are unified space for consistency and readability. Loading Loading
media/libaudioclient/AudioRecord.cpp +92 −59 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <inttypes.h> #include <android-base/macros.h> #include <android-base/stringprintf.h> #include <sys/resource.h> #include <audio_utils/format.h> Loading @@ -40,6 +41,7 @@ namespace android { using ::android::base::StringPrintf; using android::content::AttributionSourceState; using aidl_utils::statusTFromBinderStatus; Loading Loading @@ -304,7 +306,6 @@ status_t AudioRecord::set( int32_t maxSharedAudioHistoryMs) { status_t status = NO_ERROR; uint32_t channelCount; const sp<IAudioRecordCallback> callbackHandle = callback.promote(); // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set. ALOGV("%s(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " Loading Loading @@ -336,80 +337,82 @@ status_t AudioRecord::set( mSelectedMicFieldDimension = microphoneFieldDimension; mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs; switch (transferType) { std::string errorMessage; // Copy the state variables early so they are available for error reporting. if (pAttributes == nullptr) { mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; mAttributes.source = inputSource; if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION || inputSource == AUDIO_SOURCE_CAMCORDER) { mAttributes.flags = static_cast<audio_flags_mask_t>( mAttributes.flags | AUDIO_FLAG_CAPTURE_PRIVATE); } } else { // stream type shouldn't be looked at, this track has audio attributes memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); ALOGV("%s: Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]", __func__, mAttributes.source, mAttributes.flags, mAttributes.tags); } mSampleRate = sampleRate; if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } mFormat = format; mChannelMask = channelMask; mSessionId = sessionId; ALOGV("%s: mSessionId %d", __func__, mSessionId); mOrigFlags = mFlags = flags; mTransfer = transferType; switch (mTransfer) { case TRANSFER_DEFAULT: if (callbackHandle == nullptr || threadCanCallJava) { transferType = TRANSFER_SYNC; mTransfer = TRANSFER_SYNC; } else { transferType = TRANSFER_CALLBACK; mTransfer = TRANSFER_CALLBACK; } break; case TRANSFER_CALLBACK: if (callbackHandle == nullptr) { ALOGE("%s(): Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__); errorMessage = StringPrintf( "%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__); status = BAD_VALUE; goto exit; goto error; } break; case TRANSFER_OBTAIN: case TRANSFER_SYNC: break; default: ALOGE("%s(): Invalid transfer type %d", __func__, transferType); errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer); status = BAD_VALUE; goto exit; goto error; } mTransfer = transferType; // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { ALOGE("%s(): Track already in use", __func__); errorMessage = StringPrintf("%s: Track already in use", __func__); status = INVALID_OPERATION; goto exit; goto error; } if (pAttributes == nullptr) { mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; mAttributes.source = inputSource; if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION || inputSource == AUDIO_SOURCE_CAMCORDER) { mAttributes.flags = static_cast<audio_flags_mask_t>( mAttributes.flags | AUDIO_FLAG_CAPTURE_PRIVATE); } } else { // stream type shouldn't be looked at, this track has audio attributes memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); ALOGV("%s(): Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]", __func__, mAttributes.source, mAttributes.flags, mAttributes.tags); } mSampleRate = sampleRate; // these below should probably come from the audioFlinger too... if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } // validate parameters // AudioFlinger capture only supports linear PCM if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { ALOGE("%s(): Format %#x is not linear pcm", __func__, format); if (!audio_is_valid_format(mFormat) || !audio_is_linear_pcm(mFormat)) { errorMessage = StringPrintf("%s: Format %#x is not linear pcm", __func__, mFormat); status = BAD_VALUE; goto exit; goto error; } mFormat = format; if (!audio_is_input_channel(channelMask)) { ALOGE("%s(): Invalid channel mask %#x", __func__, channelMask); if (!audio_is_input_channel(mChannelMask)) { errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask); status = BAD_VALUE; goto exit; goto error; } mChannelMask = channelMask; channelCount = audio_channel_count_from_in_mask(channelMask); mChannelCount = channelCount; if (audio_is_linear_pcm(format)) { mFrameSize = channelCount * audio_bytes_per_sample(format); mChannelCount = audio_channel_count_from_in_mask(mChannelMask); if (audio_is_linear_pcm(mFormat)) { mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat); } else { mFrameSize = sizeof(uint8_t); } Loading @@ -420,12 +423,7 @@ status_t AudioRecord::set( mNotificationFramesReq = notificationFrames; // mNotificationFramesAct is initialized in createRecord_l mSessionId = sessionId; ALOGV("%s(): mSessionId %d", __func__, mSessionId); mOrigFlags = mFlags = flags; mCallback = callbackHandle; if (mCallback != nullptr) { mAudioRecordThread = new AudioRecordThread(*this); mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO); Loading @@ -446,6 +444,7 @@ status_t AudioRecord::set( mAudioRecordThread->requestExitAndWait(); mAudioRecordThread.clear(); } // bypass error message to avoid logging twice (createRecord_l logs the error). goto exit; } Loading @@ -462,11 +461,14 @@ status_t AudioRecord::set( mFramesRead = 0; mFramesReadServerOffset = 0; exit: mStatus = status; error: if (status != NO_ERROR) { mMediaMetrics.markError(status, __FUNCTION__); ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str()); reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str()); } exit: mStatus = status; return status; } Loading Loading @@ -857,9 +859,10 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) status_t status; static const int32_t kMaxCreateAttempts = 3; int32_t remainingAttempts = kMaxCreateAttempts; std::string errorMessage; if (audioFlinger == 0) { ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId); errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId); status = NO_INIT; goto exit; } Loading Loading @@ -925,7 +928,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) break; } if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) { ALOGE("%s(%d): AudioFlinger could not create record track, status: %d", errorMessage = StringPrintf( "%s(%d): AudioFlinger could not create record track, status: %d", __func__, mPortId, status); goto exit; } Loading Loading @@ -959,7 +963,7 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) mServerSampleSize = audio_bytes_per_sample(mServerConfig.format); if (output.cblk == 0) { ALOGE("%s(%d): Could not get control block", __func__, mPortId); errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId); status = NO_INIT; goto exit; } Loading @@ -969,7 +973,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) // issue (e.g. by copying). iMemPointer = output.cblk ->unsecurePointer(); if (iMemPointer == NULL) { ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId); errorMessage = StringPrintf( "%s(%d): Could not get control block pointer", __func__, mPortId); status = NO_INIT; goto exit; } Loading @@ -988,7 +993,8 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) // issue (e.g. by copying). buffers = output.buffers->unsecurePointer(); if (buffers == NULL) { ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId); errorMessage = StringPrintf( "%s(%d): Could not get buffer pointer", __func__, mPortId); status = NO_INIT; goto exit; } Loading Loading @@ -1083,11 +1089,38 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch) .record(); exit: if (status != NO_ERROR) { ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str()); reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str()); } mStatus = status; // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger return status; } // Report error associated with the event and some configuration details. void AudioRecord::reportError(status_t status, const char *event, const char *message) const { if (status == NO_ERROR) return; // We report error on the native side because some callers do not come // from Java. // Ensure these variables are initialized in set(). mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR) .set(AMEDIAMETRICS_PROP_EVENT, event) .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status) .set(AMEDIAMETRICS_PROP_STATUSMESSAGE, message) .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str()) .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId) .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str()) .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId) .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str()) .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask) .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount) .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate) .record(); } status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig) { if (audioBuffer == NULL) { Loading
media/libaudioclient/include/media/AudioRecord.h +2 −0 Original line number Diff line number Diff line Loading @@ -890,6 +890,8 @@ private: MediaMetrics mMediaMetrics; std::string mMetricsId; // GUARDED_BY(mLock), could change in createRecord_l(). std::string mCallerName; // for example "aaudio" void reportError(status_t status, const char *event, const char *message) const; }; }; // namespace android Loading
media/libmediametrics/include/MediaMetricsConstants.h +1 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ // Error keys #define AMEDIAMETRICS_KEY_AUDIO_TRACK_ERROR AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "error" #define AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "error" /* * MediaMetrics Properties are unified space for consistency and readability. Loading