进行AudioRecord相关操作前需要先创建一个Record,如下为CreateRecord的流程:
首先在AudioRecord的构造函数中会调用native_setup方法:
//frameworks/base/media/java/android/media/AudioRecord.java
@RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes)
throws IllegalArgumentException {
this((new AudioAttributes.Builder())
.setInternalCapturePreset(audioSource)
.build(),
(new AudioFormat.Builder())
.setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,
true/*allow legacy configurations*/))
.setEncoding(audioFormat)
.setSampleRate(sampleRateInHz)
.build(),
bufferSizeInBytes,
AudioManager.AUDIO_SESSION_ID_GENERATE);
}
private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int sessionId, @Nullable Context context,
int maxSharedAudioHistoryMs) throws IllegalArgumentException {
mRecordingState = RECORDSTATE_STOPPED;
if (attributes == null) {
throw new IllegalArgumentException("Illegal null AudioAttributes");
}
if (format == null) {
throw new IllegalArgumentException("Illegal null AudioFormat");
}
// remember which looper is associated with the AudioRecord instanciation
if ((mInitializationLooper = Looper.myLooper()) == null) {
mInitializationLooper = Looper.getMainLooper();
}
// is this AudioRecord using REMOTE_SUBMIX at full volume?
if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
final AudioAttributes.Builder ab =
new AudioAttributes.Builder(attributes);
HashSet<String> filteredTags = new HashSet<String>();
final Iterator<String> tagsIter = attributes.getTags().iterator();
while (tagsIter.hasNext()) {
final String tag = tagsIter.next();
if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
mIsSubmixFullVolume = true;
Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
} else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers
filteredTags.add(tag);
}
}
ab.replaceTags(filteredTags);
attributes = ab.build();
}
mAudioAttributes = attributes;
int rate = format.getSampleRate();
if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
rate = 0;
}
int encoding = AudioFormat.ENCODING_DEFAULT;
if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
{
encoding = format.getEncoding();
}
audioParamCheck(mAudioAttributes.getCapturePreset(), rate, encoding);
if ((format.getPropertySetMask()
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
mChannelIndexMask = format.getChannelIndexMask();
mChannelCount = format.getChannelCount();
}
if ((format.getPropertySetMask()
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false); //取得ChannelMask,原生只有CHANNEL_IN_MONO、CHANNEL_IN_STEREO,如果需要支持多声道录音,需要追加代码
mChannelCount = format.getChannelCount();
} else if (mChannelIndexMask == 0) {
mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false);
mChannelCount = AudioFormat.channelCountFromInChannelMask(mChannelMask);
}
audioBuffSizeCheck(bufferSizeInBytes);
AttributionSource attributionSource = (context != null)
? context.getAttributionSource() : AttributionSource.myAttributionSource();
if (attributionSource.getPackageName() == null) {
// Command line utility
attributionSource = attributionSource.withPackageName("uid:" + Binder.getCallingUid());
}
int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1];
session[0] = sessionId;
//TODO: update native initialization when information about hardware init failure
// due to capture device already open is available.
try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
int initResult = native_setup(new WeakReference<AudioRecord>(this), mAudioAttributes,
sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, session, attributionSourceState.getParcel(),
0 /*nativeRecordInJavaObj*/, maxSharedAudioHistoryMs);
if (initResult != SUCCESS) {
loge("Error code " + initResult + " when initializing native AudioRecord object.");
return; // with mState == STATE_UNINITIALIZED
}
}
mSampleRate = sampleRate[0];
mSessionId = session[0];
mState = STATE_INITIALIZED;
}
通过查询JNI代码android_media_AudioRecord.cpp得出调用的函数是android_media_AudioRecord_setup:
//frameworks/base/core/jni/android_media_AudioRecord.cpp
static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jaa, jintArray jSampleRate, jint channelMask,
jint channelIndexMask, jint audioFormat,
jint buffSizeInBytes, jintArray jSession,
jobject jAttributionSource, jlong nativeRecordInJavaObj,
jint sharedAudioHistoryMs) {
//ALOGV(">> Entering android_media_AudioRecord_setup");
//ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
// "nativeRecordInJavaObj=0x%llX",
// sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
if (jSession == NULL) {
ALOGE("Error creating AudioRecord: invalid session ID pointer");
return (jint) AUDIO_JAVA_ERROR;
}
jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
return (jint) AUDIO_JAVA_ERROR;
}
audio_session_t sessionId = (audio_session_t) nSession[0];
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
sp<AudioRecord> lpRecorder;
sp<AudioRecordJNIStorage> callbackData;
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
ALOGE("Can't find %s when setting up callback.", kClassPathName);
return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}
// if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
if (nativeRecordInJavaObj == 0) {
if (jaa == 0) {
ALOGE("Error creating AudioRecord: invalid audio attributes");
return (jint) AUDIO_JAVA_ERROR;
}
if (jSampleRate == 0) {
ALOGE("Error creating AudioRecord: invalid sample rates");
return (jint) AUDIO_JAVA_ERROR;
}
jint elements[1];
env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
int sampleRateInHertz = elements[0];
// channel index mask takes priority over channel position masks.
if (channelIndexMask) {
// Java channel index masks need the representation bits set.
localChanMask = audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_INDEX,
channelIndexMask);
}
// Java channel position masks map directly to the native definition
if (!audio_is_input_channel(localChanMask)) {
ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
// compare the format against the Java constants
audio_format_t format = audioFormatToNative(audioFormat);
if (format == AUDIO_FORMAT_INVALID) {
ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
}
size_t bytesPerSample = audio_bytes_per_sample(format);
if (buffSizeInBytes == 0) {
ALOGE("Error creating AudioRecord: frameCount is 0.");
return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
}
size_t frameSize = channelCount * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
// create an uninitialized AudioRecord object
Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
android::content::AttributionSourceState attributionSource;
attributionSource.readFromParcel(parcel);
lpRecorder = new AudioRecord(attributionSource); 创建AudioRecord
// read the AudioAttributes values
auto paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
return jStatus;
}
ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
}
// create the callback information:
// this data will be passed with every AudioRecord callback
// we use a weak reference so the AudioRecord object can be garbage collected.
callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
const status_t status =
lpRecorder->set(paa->source, sampleRateInHertz, //调用AudioRecord的set函数
format, // word length, PCM
localChanMask, frameCount,
callbackData, // callback
0, // notificationFrames,
true, // threadCanCallJava
sessionId, AudioRecord::TRANSFER_DEFAULT, flags, -1,
-1, // default uid, pid
paa.get(), AUDIO_PORT_HANDLE_NONE, MIC_DIRECTION_UNSPECIFIED,
MIC_FIELD_DIMENSION_DEFAULT, sharedAudioHistoryMs);
if (status != NO_ERROR) {
ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
status);
goto native_init_failure;
}
// Set caller name so it can be logged in destructor.
// MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
lpRecorder->setCallerName("java");
} else { // end if nativeRecordInJavaObj == 0)
lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
// TODO: We need to find out which members of the Java AudioRecord might need to be
// initialized from the Native AudioRecord
// these are directly returned from getters:
// mSampleRate
// mRecordSource
// mAudioFormat
// mChannelMask
// mChannelCount
// mState (?)
// mRecordingState (?)
// mPreferredDevice
// create the callback information:
// this data will be passed with every AudioRecord callback
// This next line makes little sense
// callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
}
nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
goto native_init_failure;
}
// read the audio session ID back from AudioRecord in case a new session was created during set()
nSession[0] = lpRecorder->getSessionId();
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
{
const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
}
// save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
// of the Java object
setFieldSp(env, thiz, lpRecorder, javaAudioRecordFields.nativeRecorderInJavaObj);
// save our newly created callback information in the "jniData" field
// of the Java object (in mNativeJNIDataHandle) so we can free the memory in finalize()
setFieldSp(env, thiz, callbackData, javaAudioRecordFields.jniData);
return (jint) AUDIO_JAVA_SUCCESS;
// failure:
native_init_failure:
setFieldSp(env, thiz, sp<AudioRecord>{}, javaAudioRecordFields.nativeRecorderInJavaObj);
setFieldSp(env, thiz, sp<AudioRecordJNIStorage>{}, javaAudioRecordFields.jniData);
// lpRecorder goes out of scope, so reference count drops to zero
return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}
在android_media_AudioRecord_setup中创建AudioRecord并调用AudioRecord的set函数:
//frameworks/av/media/libaudioclient/AudioRecord.cpp
status_t AudioRecord::set(
audio_source_t inputSource,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
const wp<IAudioRecordCallback>& callback,
uint32_t notificationFrames,
bool threadCanCallJava,
audio_session_t sessionId,
transfer_type transferType,
audio_input_flags_t flags,
uid_t uid,
pid_t pid,
const audio_attributes_t* pAttributes,
audio_port_handle_t selectedDeviceId,
audio_microphone_direction_t selectedMicDirection,
float microphoneFieldDimension,
int32_t maxSharedAudioHistoryMs)
{
status_t status = NO_ERROR;
LOG_ALWAYS_FATAL_IF(mInitialized, "%s: should not be called twice", __func__);
mInitialized = true;
// 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, "
"notificationFrames %u, sessionId %d, transferType %d, flags %#x, attributionSource %s"
"uid %d, pid %d",
__func__,
inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
sessionId, transferType, flags, mClientAttributionSource.toString().c_str(), uid, pid);
// TODO b/182392553: refactor or remove
pid_t callingPid = IPCThreadState::self()->getCallingPid();
pid_t myPid = getpid();
pid_t adjPid = pid;
if (pid == -1 || (callingPid != myPid)) {
adjPid = callingPid;
}
mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
uid_t adjUid = uid;
if (uid == -1 || (callingPid != myPid)) {
adjUid = IPCThreadState::self()->getCallingUid();
}
mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
mTracker.reset(new RecordingActivityTracker());
mSelectedDeviceId = selectedDeviceId;
mSelectedMicDirection = selectedMicDirection;
mSelectedMicFieldDimension = microphoneFieldDimension;
mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
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;
}
if (!audio_is_linear_pcm(format)) {
// Compressed capture requires direct
flags = (audio_input_flags_t) (flags | AUDIO_INPUT_FLAG_DIRECT);
ALOGI("%s(): Format %#x is not linear pcm. Setting DIRECT, using flags %#x", __func__,
format, flags);
}
mFormat = format;
mChannelMask = channelMask;
mSessionId = sessionId;
ALOGV("%s: mSessionId %d", __func__, mSessionId);
mOrigFlags = mFlags = flags;
mTransfer = transferType;
switch (mTransfer) {
case TRANSFER_DEFAULT:
if (callback == nullptr || threadCanCallJava) {
mTransfer = TRANSFER_SYNC;
} else {
mTransfer = TRANSFER_CALLBACK;
}
break;
case TRANSFER_CALLBACK:
if (callback == nullptr) {
errorMessage = StringPrintf(
"%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__);
status = BAD_VALUE;
goto error;
}
break;
case TRANSFER_OBTAIN:
case TRANSFER_SYNC:
break;
default:
errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer);
status = BAD_VALUE;
goto error;
}
// invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) {
errorMessage = StringPrintf("%s: Track already in use", __func__);
status = INVALID_OPERATION;
goto error;
}
if (!audio_is_valid_format(mFormat)) {
errorMessage = StringPrintf("%s: Format %#x is not valid", __func__, mFormat);
status = BAD_VALUE;
goto error;
}
if (!audio_is_input_channel(mChannelMask)) {
errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask);
status = BAD_VALUE;
goto error;
}
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);
}
// mFrameCount is initialized in createRecord_l
mReqFrameCount = frameCount;
mNotificationFramesReq = notificationFrames;
// mNotificationFramesAct is initialized in createRecord_l
mCallback = callback;
if (mCallback != nullptr) {
mAudioRecordThread = new AudioRecordThread(*this); //创建AudioRecord线程
mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO); //运行AudioRecord线程
// thread begins in paused state, and will not reference us until start()
}
// create the IAudioRecord
{
AutoMutex lock(mLock);
status = createRecord_l(0 /*epoch*/); //创建IAudioRecord
}
ALOGV("%s(%d): status %d", __func__, mPortId, status);
if (status != NO_ERROR) {
if (mAudioRecordThread != 0) {
mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
// bypass error message to avoid logging twice (createRecord_l logs the error).
goto exit;
}
// TODO: add audio hardware input latency here
mLatency = (1000LL * mFrameCount) / mSampleRate;
mMarkerPosition = 0;
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
AudioSystem::acquireAudioSessionId(mSessionId, adjPid, adjUid);
mSequence = 1;
mObservedSequence = mSequence;
mInOverrun = false;
mFramesRead = 0;
mFramesReadServerOffset = 0;
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;
}
这个函数会创建并运行AudioRecord线程,然后调用createRecord_l创建IAudioRecord:
//frameworks/av/media/libaudioclient/AudioRecord.cpp
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch)
{
const int64_t beginNs = systemTime();
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); //取得audioFlinger
IAudioFlinger::CreateRecordInput input; //Record输入
IAudioFlinger::CreateRecordOutput output; //Record输出
[[maybe_unused]] audio_session_t originalSessionId;
void *iMemPointer;
audio_track_cblk_t* cblk;
status_t status;
static const int32_t kMaxCreateAttempts = 3;
int32_t remainingAttempts = kMaxCreateAttempts;
std::string errorMessage;
if (audioFlinger == 0) {
errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId);
status = NO_INIT;
goto exit;
}
// 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.
// 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.
// Client can only express a preference for FAST. Server will perform additional tests.
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
bool useCaseAllowed =
// any of these use cases:
// use case 1: callback transfer mode
(mTransfer == TRANSFER_CALLBACK) ||
// use case 2: blocking read mode
// The default buffer capacity at 48 kHz is 2048 frames, or ~42.6 ms.
// That's enough for double-buffering with our standard 20 ms rule of thumb for
// the minimum period of a non-SCHED_FIFO thread.
// This is needed so that AAudio apps can do a low latency non-blocking read from a
// callback running with SCHED_FIFO.
(mTransfer == TRANSFER_SYNC) ||
// use case 3: obtain/release mode
(mTransfer == TRANSFER_OBTAIN);
if (!useCaseAllowed) {
ALOGD("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
__func__, mPortId,
convertTransferToText(mTransfer));
mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
AUDIO_INPUT_FLAG_RAW));
}
}
input.attr = mAttributes;
input.config.sample_rate = mSampleRate;
input.config.channel_mask = mChannelMask;
input.config.format = mFormat;
input.clientInfo.attributionSource = mClientAttributionSource;
input.clientInfo.clientTid = -1;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
if (mAudioRecordThread != 0) {
input.clientInfo.clientTid = mAudioRecordThread->getTid();
}
}
input.riid = mTracker->getRiid();
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;
input.maxSharedAudioHistoryMs = mMaxSharedAudioHistoryMs;
do {
media::CreateRecordResponse response;
status = audioFlinger->createRecord(VALUE_OR_FATAL(input.toAidl()), response); //调用audioFlinger的createRecord函数创建RecordTrack
output = VALUE_OR_FATAL(IAudioFlinger::CreateRecordOutput::fromAidl(response)); 创建Record输出
if (status == NO_ERROR) {
break;
}
if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
errorMessage = StringPrintf(
"%s(%d): AudioFlinger could not create record track, status: %d",
__func__, mPortId, status);
goto exit;
}
// FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
// between audio policy manager and audio flinger during the input stream open sequence
// and can be recovered by retrying.
// Leave time for race condition to clear before retrying and randomize delay
// to reduce the probability of concurrent retries in locked steps.
usleep((20 + rand() % 30) * 10000);
} while (1);
ALOG_ASSERT(output.audioRecord != 0);
// AudioFlinger now owns the reference to the I/O handle,
// so we are no longer responsible for releasing it.
mAwaitBoost = false;
if (output.flags & AUDIO_INPUT_FLAG_FAST) {
ALOGI("%s(%d): AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu",
__func__, mPortId,
mReqFrameCount, output.frameCount);
mAwaitBoost = true;
}
mFlags = output.flags;
mRoutedDeviceId = output.selectedDeviceId;
mSessionId = output.sessionId;
mSampleRate = output.sampleRate;
mServerConfig = output.serverConfig;
mServerFrameSize = audio_bytes_per_frame(
audio_channel_count_from_in_mask(mServerConfig.channel_mask), mServerConfig.format);
mServerSampleSize = audio_bytes_per_sample(mServerConfig.format);
if (output.cblk == 0) {
errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
status = NO_INIT;
goto exit;
}
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
// Either document why it is safe in this case or address the
// issue (e.g. by copying).
iMemPointer = output.cblk ->unsecurePointer();
if (iMemPointer == NULL) {
errorMessage = StringPrintf(
"%s(%d): Could not get control block pointer", __func__, mPortId);
status = NO_INIT;
goto exit;
}
cblk = static_cast<audio_track_cblk_t*>(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) {
buffers = cblk + 1;
} else {
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
// Either document why it is safe in this case or address the
// issue (e.g. by copying).
buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
errorMessage = StringPrintf(
"%s(%d): Could not get buffer pointer", __func__, mPortId);
status = NO_INIT;
goto exit;
}
}
// invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) {
IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
mAudioRecord = output.audioRecord;
mCblkMemory = output.cblk;
mBufferMemory = output.buffers;
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("%s(%d): Requested frameCount %zu but received frameCount %zu",
__func__, output.portId,
mReqFrameCount, output.frameCount);
}
// Make sure that application is notified with sufficient margin before overrun.
// The computation is done on server side.
if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) {
ALOGW("%s(%d): Server adjusted notificationFrames from %u to %zu for frameCount %zu",
__func__, output.portId,
mNotificationFramesReq, output.notificationFrameCount, output.frameCount);
}
mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
if (mServerConfig.format != mFormat && mCallback != nullptr) {
mFormatConversionBufRaw = std::make_unique<uint8_t[]>(mNotificationFramesAct * mFrameSize);
mFormatConversionBuffer.raw = mFormatConversionBufRaw.get();
}
//mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
if (mDeviceCallback != 0) {
if (mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
}
AudioSystem::addAudioDeviceCallback(this, output.inputId, output.portId);
}
if (!mSharedAudioPackageName.empty()) {
mAudioRecord->shareAudioHistory(mSharedAudioPackageName, mSharedAudioStartMs);
}
mPortId = output.portId;
// We retain a copy of the I/O handle, but don't own the reference
mInput = output.inputId;
mRefreshRemaining = true;
mFrameCount = output.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;
}
// update proxy
mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mServerFrameSize);
mProxy->setEpoch(epoch);
mProxy->setMinimum(mNotificationFramesAct);
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(mPortId);
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
.set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
// the following are immutable (at least until restore)
.set(AMEDIAMETRICS_PROP_FLAGS, toString(mFlags).c_str())
.set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
.set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
.set(AMEDIAMETRICS_PROP_TRACKID, mPortId)
.set(AMEDIAMETRICS_PROP_LOGSESSIONID, mLogSessionId)
.set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
.set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.inputId)
.set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
.set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)mRoutedDeviceId)
.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)
// the following are NOT immutable
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
.set(AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION, (int32_t)mSelectedMicDirection)
.set(AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION, (double)mSelectedMicFieldDimension)
.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;
}
调用audioFlinger的createRecord函数创建RecordTrack,是通过IAudioFlinger接口:
//frameworks/av/media/libaudioclient/include/media/IAudioFlinger.h
class IAudioFlinger : public virtual RefBase {
......
virtual status_t createRecord(const media::CreateRecordRequest& input,
media::CreateRecordResponse& output) = 0;
......
}
AudioFlinger CreateRecord
调用AudioFlinger的CreateRecord方法:
待确定