AudioRecord#
初期化#
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,int bufferSizeInBytes)
サンプリングレートについては、44100Hz 以外のすべてのデバイスでサポートが保証されているわけではなく、他の周波数はサポートされているかどうかは不確かです。この場合、パラメータ SAMPLE_RATE_UNSPECIFIED を使用して、デバイスが使用するサンプリングレートを自動的に決定させることができます。channelConfig はサンプリングチャネルであり、現在すべてのデバイスがモノラルをサポートしていることが保証されていますが、マルチチャネルは必ずしもサポートされているわけではありません。bufferSizeInBytes はバッファのサイズで、収集したデータを保存するために使用され、通常はインターフェース getMinBufferSize の戻り値をそのままバッファサイズとして使用します。
getMinBufferSize#
//frameworks/base/media/java/android/media/AudioRecord.java
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch (channelConfig) {
case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
channelCount = 2;
break;
case AudioFormat.CHANNEL_INVALID:
default:
loge("getMinBufferSize(): Invalid channel configuration.");
return ERROR_BAD_VALUE;
}
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if (size == 0) {
return ERROR_BAD_VALUE;
}
else if (size == -1) {
return ERROR;
}
else {
return size;
}
}
//frameworks/base/core/jni/android_media_AudioRecord.cpp
static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
jint sampleRateInHertz, jint channelCount, jint audioFormat) {
ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
sampleRateInHertz, channelCount, audioFormat);
size_t frameCount = 0;
audio_format_t format = audioFormatToNative(audioFormat); // javaのフォーマットをnativeに変換
status_t result = AudioRecord::getMinFrameCount(&frameCount, // 最小フレーム数を取得
sampleRateInHertz,
format,
audio_channel_in_mask_from_count(channelCount));
if (result == BAD_VALUE) {
return 0;
}
if (result != NO_ERROR) {
return -1;
}
return frameCount * audio_bytes_per_frame(channelCount, format);
}
//frameworks/av/media/libaudioclient/AudioRecord.cpp
status_t AudioRecord::getMinFrameCount(
size_t* frameCount,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask)
{
if (frameCount == NULL) {
return BAD_VALUE;
}
size_t size;
status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
if (status != NO_ERROR) {
ALOGE("%s(): AudioSystem could not query the input buffer size for"
" sampleRate %u, format %#x, channelMask %#x; status %d",
__func__, sampleRate, format, channelMask, status);
return status;
}
// 入力バッファのサイズを2倍にして、レコーディングバッファのピンポン使用を可能にします。
const auto frameSize = audio_bytes_per_frame(
audio_channel_count_from_in_mask(channelMask), format);
if (frameSize == 0 || ((*frameCount = (size * 2) / frameSize) == 0)) {
ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
__func__, sampleRate, format, channelMask);
return BAD_VALUE;
}
return NO_ERROR;
}
//frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize) {
const sp<AudioFlingerClient> afc = getAudioFlingerClient();
if (afc == 0) {
return NO_INIT;
}
return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize);
}
status_t AudioSystem::AudioFlingerClient::getInputBufferSize(
uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize) {
const sp<IAudioFlinger> af = get_audio_flinger();
if (af == 0) {
return PERMISSION_DENIED;
}
std::lock_guard _l(mMutex);
// 古いmInBuffSizeを持っているか、新しい値の入力バッファサイズを要求しているか
if ((mInBuffSize == 0) || (sampleRate != mInSamplingRate) || (format != mInFormat)
|| (channelMask != mInChannelMask)) {
size_t inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
if (inBuffSize == 0) {
ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %#x",
sampleRate, format, channelMask);
return BAD_VALUE;
}
// 競合状態が発生する可能性があるため、より新しいキャッシュエントリを上書きすることができます
// リクエストパラメータを保存します
mInSamplingRate = sampleRate;
mInFormat = format;
mInChannelMask = channelMask;
mInBuffSize = inBuffSize;
}
*buffSize = mInBuffSize;
return NO_ERROR;
}
//frameworks/av/services/audioflinger/AudioFlinger.cpp
size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
return 0;
}
if ((sampleRate == 0) ||
!audio_is_valid_format(format) ||
!audio_is_input_channel(channelMask)) {
return 0;
}
audio_utils::lock_guard lock(hardwareMutex());
if (mPrimaryHardwareDev == nullptr) {
return 0;
}
if (mInputBufferSizeOrderedDevs.empty()) {
return 0;
}
mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
std::vector<audio_channel_mask_t> channelMasks = {channelMask};
if (channelMask != AUDIO_CHANNEL_IN_MONO) {
channelMasks.push_back(AUDIO_CHANNEL_IN_MONO);
}
if (channelMask != AUDIO_CHANNEL_IN_STEREO) {
channelMasks.push_back(AUDIO_CHANNEL_IN_STEREO);
}
std::vector<audio_format_t> formats = {format};
if (format != AUDIO_FORMAT_PCM_16_BIT) {
// 圧縮フォーマットの場合、バッファサイズはPCMを使用して照会できます。互換性のためにこれを許可します
// プライマリhwデバイスがフォーマットをサポートしていない場合。
// TODO: 名目ビットレートとコーデックフレームサイズに基づいて、フォーマットと名目バッファサイズのテーブルに置き換えます。
formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
}
std::vector<uint32_t> sampleRates = {sampleRate};
static const uint32_t SR_44100 = 44100;
static const uint32_t SR_48000 = 48000;
if (sampleRate != SR_48000) {
sampleRates.push_back(SR_48000);
}
if (sampleRate != SR_44100) {
sampleRates.push_back(SR_44100);
}
mHardwareStatus = AUDIO_HW_IDLE;
auto getInputBufferSize = [](const sp<DeviceHalInterface>& dev, audio_config_t config,
size_t* bytes) -> status_t {
if (!dev) {
return BAD_VALUE;
}
status_t result = dev->getInputBufferSize(&config, bytes);
if (result == BAD_VALUE) {
// HALによって提案された構成で再試行します。
result = dev->getInputBufferSize(&config, bytes);
}
if (result != OK || *bytes == 0) {
return BAD_VALUE;
}
return result;
};
// デバイスがサポートする構成を見つけるまで、各反復で構成のパラメータを変更します。
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
for (auto testChannelMask : channelMasks) {
config.channel_mask = testChannelMask;
for (auto testFormat : formats) {
config.format = testFormat;
for (auto testSampleRate : sampleRates) {
config.sample_rate = testSampleRate;
size_t bytes = 0;
ret = BAD_VALUE;
for (const AudioHwDevice* dev : mInputBufferSizeOrderedDevs) {
ret = getInputBufferSize(dev->hwDevice(), config, &bytes);
if (ret == OK) {
break;
}
}
if (ret == BAD_VALUE) continue;
if (config.sample_rate != sampleRate || config.channel_mask != channelMask ||
config.format != format) {
uint32_t dstChannelCount = audio_channel_count_from_in_mask(channelMask);
uint32_t srcChannelCount =
audio_channel_count_from_in_mask(config.channel_mask);
size_t srcFrames =
bytes / audio_bytes_per_frame(srcChannelCount, config.format);
size_t dstFrames = destinationFramesPossible(
srcFrames, config.sample_rate, sampleRate);
bytes = dstFrames * audio_bytes_per_frame(dstChannelCount, format);
}
return bytes;
}
}
}
ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, "
"format %#x, channelMask %#x",sampleRate, format, channelMask);
return 0;
}
AudioRecord 初期化#
//frameworks/base/media/java/android/media/AudioRecord.java
private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int sessionId, @Nullable Context context,
int maxSharedAudioHistoryMs, int halInputFlags) throws IllegalArgumentException {
mRecordingState = RECORDSTATE_STOPPED;
mHalInputFlags = halInputFlags;
if (attributes == null) {
throw new IllegalArgumentException("Illegal null AudioAttributes");
}
if (format == null) {
throw new IllegalArgumentException("Illegal null AudioFormat");
}
// AudioRecordインスタンスに関連付けられているルーパーを記憶します
if ((mInitializationLooper = Looper.myLooper()) == null) {
mInitializationLooper = Looper.getMainLooper();
}
// このAudioRecordはREMOTE_SUBMIXをフルボリュームで使用していますか?
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: ネイティブレイヤーに伝播させるべきではありません
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);
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) {
// コマンドラインユーティリティ
attributionSource = attributionSource.withPackageName("uid:" + Binder.getCallingUid());
}
int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1];
session[0] = resolveSessionId(context, sessionId);
//TODO: ハードウェア初期化失敗に関する情報が利用可能になったときにネイティブ初期化を更新します。
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, mHalInputFlags);
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;
}
//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,
jint halFlags) {
//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 = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
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->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
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;
}
// 既存の*Native* AudioRecordを渡す場合、作成/初期化する必要はありません。
if (nativeRecordInJavaObj == 0) { // nativeのaudio recordがまだ作成されていない場合、作成する必要があります
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];
// チャネルインデックスマスクはチャネル位置マスクより優先されます。
if (channelIndexMask) {
// Javaチャネルインデックスマスクには表現ビットが設定される必要があります。
localChanMask = audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_INDEX,
channelIndexMask);
}
// Javaチャネル位置マスクはネイティブ定義に直接マッピングされます。
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);
// フォーマットをJava定数と比較します
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;
}
if (buffSizeInBytes == 0) {
ALOGE("Error creating AudioRecord: frameCount is 0.");
return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
}
size_t frameCount = buffSizeInBytes / audio_bytes_per_frame(channelCount, format);
// 初期化されていないAudioRecordオブジェクトを作成します
Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
android::content::AttributionSourceState attributionSource;
attributionSource.readFromParcel(parcel);
lpRecorder = new AudioRecord(attributionSource);
// AudioAttributesの値を読み取ります
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);
const auto flags = static_cast<audio_input_flags_t>(halFlags);
// コールバック情報を作成します:
// このデータはすべてのAudioRecordコールバックとともに渡されます
// AudioRecordオブジェクトがガーベジコレクトされることができるように弱い参照を使用します。
callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
const status_t status =
lpRecorder->set(paa->source, sampleRateInHertz, // 設定構成
format, // ワード長、PCM
localChanMask, frameCount,
callbackData, // コールバック
0, // notificationFrames,
true, // threadCanCallJava
sessionId, AudioRecord::TRANSFER_DEFAULT, flags, -1,
-1, // デフォルトの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;
}
// 呼び出し元の名前を設定して、デストラクタでログに記録できるようにします。
// MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
lpRecorder->setCallerName("java");
} else { // end if nativeRecordInJavaObj == 0) // すでにnativeのAudioRecordが作成されています
lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
// TODO: Java AudioRecordのどのメンバーがNative AudioRecordから初期化する必要があるかを見つける必要があります
// これらはゲッターから直接返されます:
// mSampleRate
// mRecordSource
// mAudioFormat
// mChannelMask
// mChannelCount
// mState (?)
// mRecordingState (?)
// mPreferredDevice
// コールバック情報を作成します:
// このデータはすべてのAudioRecordコールバックとともに渡されます
// この次の行はあまり意味がありません
// callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
}
nSession = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
if (nSession == NULL) {
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
goto native_init_failure;
}
// set()中に新しいセッションが作成された場合に備えてAudioRecordからオーディオセッションIDを読み取ります
nSession[0] = lpRecorder->getSessionId();
env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
nSession = NULL;
{
const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
}
// Javaオブジェクトの"nativeRecorderInJavaObj"フィールドに新しく作成されたC++ AudioRecordを保存します
// Javaオブジェクトを関連付けます
setFieldSp(env, thiz, lpRecorder, javaAudioRecordFields.nativeRecorderInJavaObj);
// Javaオブジェクトの"jniData"フィールドに新しく作成されたコールバック情報を保存します
// finalize()でメモリを解放できるようにします
setFieldSp(env, thiz, callbackData, javaAudioRecordFields.jniData);
return (jint) AUDIO_JAVA_SUCCESS;
// 失敗:
native_init_failure:
setFieldSp(env, thiz, sp<AudioRecord>{}, javaAudioRecordFields.nativeRecorderInJavaObj);
setFieldSp(env, thiz, sp<AudioRecordJNIStorage>{}, javaAudioRecordFields.jniData);
// lpRecorderはスコープを外れるので、参照カウントがゼロに下がります
return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}
//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;
// mPortIdはトラックが作成されるまで無効ですので、setのALOGにはmPortIdを省略します。
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: リファクタリングまたは削除
pid_t callingPid = IPCThreadState::self()->getCallingPid();
pid_t myPid = getpid();
pid_t adjPid = pid;
if (pid == -1 || (callingPid != myPid)) {
adjPid = callingPid;
}
auto clientAttributionSourcePid = legacy2aidl_pid_t_int32_t(adjPid);
if (!clientAttributionSourcePid.ok()) {
return logIfErrorAndReturnStatus(BAD_VALUE,
StringPrintf("%s: received invalid client attribution "
"source pid, pid: %d, sessionId: %d",
__func__, pid, sessionId),
__func__);
}
mClientAttributionSource.pid = clientAttributionSourcePid.value();
uid_t adjUid = uid;
if (uid == -1 || (callingPid != myPid)) {
adjUid = IPCThreadState::self()->getCallingUid();
}
auto clientAttributionSourceUid = legacy2aidl_uid_t_int32_t(adjUid);
if (!clientAttributionSourceUid.ok()) {
return logIfErrorAndReturnStatus(BAD_VALUE,
StringPrintf("%s: received invalid client attribution "
"source uid, pid: %d, session id: %d",
__func__, pid, sessionId),
__func__);
}
mClientAttributionSource.uid = clientAttributionSourceUid.value();
mTracker.reset(new RecordingActivityTracker());
mSelectedDeviceId = selectedDeviceId;
mSelectedMicDirection = selectedMicDirection;
mSelectedMicFieldDimension = microphoneFieldDimension;
mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
// 状態変数を早期にコピーして、エラー報告に利用できるようにします。
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 {
// ストリームタイプは見ないでください。このトラックにはオーディオ属性があります
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)) {
// 圧縮キャプチャには直接が必要です
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) { // 入力されたtransferはdefaultで、他のケースは無視できます
case TRANSFER_DEFAULT:
if (callback == nullptr || threadCanCallJava) {
mTransfer = TRANSFER_SYNC;
} else {
mTransfer = TRANSFER_CALLBACK;
}
break;
case TRANSFER_CALLBACK:
if (callback == nullptr) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s: Transfer type TRANSFER_CALLBACK but callback == nullptr, "
"pid: %d, session id: %d",
__func__, pid, sessionId),
__func__);
}
break;
case TRANSFER_OBTAIN:
case TRANSFER_SYNC:
break;
default:
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s: Invalid transfer type %d, pid: %d, session id: %d", __func__,
mTransfer, pid, sessionId),
__func__);
}
// mAudioRecord != 0の不変条件は、set()が正常に戻った後のみ真です
if (mAudioRecord != 0) {
return logIfErrorAndReturnStatus(
INVALID_OPERATION,
StringPrintf("%s: Track already in use, pid: %d, session id: %d", __func__, pid,
sessionId),
__func__);
}
if (!audio_is_valid_format(mFormat)) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s: Format %#x is not valid, pid: %d, session id: %d", __func__,
mFormat, pid, sessionId),
__func__);
}
if (!audio_is_input_channel(mChannelMask)) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s: Invalid channel mask %#x, pid: %d, session id: %d", __func__,
mChannelMask, pid, sessionId),
__func__);
}
mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
mFrameSize = audio_bytes_per_frame(mChannelCount, mFormat);
// mFrameCountはcreateRecord_lで初期化されます
mReqFrameCount = frameCount;
mNotificationFramesReq = notificationFrames;
// mNotificationFramesActはcreateRecord_lで初期化されます
mCallback = callback;
if (mCallback != nullptr) {
mAudioRecordThread = new AudioRecordThread(*this); // コールバックスレッド。データを収集した後、呼び出し元にコールバックできます
mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
// スレッドは一時停止状態で開始され、start()まで私たちを参照しません
}
// IAudioRecordを作成します
// 重要
{
AutoMutex lock(mLock);
status = createRecord_l(0 /*epoch*/);
}
ALOGV("%s(%d): status %d", __func__, mPortId, status);
if (status != NO_ERROR) {
if (mAudioRecordThread != 0) {
mAudioRecordThread->requestExit(); // AudioRecord.hのコメントを参照
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
// エラーメッセージをバイパスして二重ログを避けます(createRecord_lがエラーをログします)。
mStatus = status;
return mStatus;
}
// TODO: ここにオーディオハードウェア入力レイテンシを追加します
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;
return logIfErrorAndReturnStatus(status, "", __func__);
}
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch)
{
const int64_t beginNs = systemTime();
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
IAudioFlinger::CreateRecordInput input;
IAudioFlinger::CreateRecordOutput output;
[[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;
if (audioFlinger == 0) {
return logIfErrorAndReturnStatus(
NO_INIT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId), "");
}
// mFlags (not mOrigFlags)は、ファストリクエストが受け入れられるかどうかに応じて変更されます。
// ファストリクエストが拒否された後、IAudioRecordが再作成される場合は再リクエストします。
// クライアントはFASTの好みを表現できます。サーバーは追加のテストを実行します。
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
bool useCaseAllowed =
// これらのいずれかの使用ケース:
// 使用ケース1:コールバック転送モード
(mTransfer == TRANSFER_CALLBACK) ||
// 使用ケース2:ブロッキング読み取りモード
// 48kHzでのデフォルトバッファ容量は2048フレーム、または約42.6msです。
// これは、標準の20msルールに従ったダブルバッファリングに十分です。
// これは、AAudioアプリがSCHED_FIFOで実行されているコールバックから低レイテンシのノンブロッキング読み取りを行うために必要です。
(mTransfer == TRANSFER_SYNC) ||
// 使用ケース3:取得/解放モード
(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;
// 通知フレーム数はコールバックによって提案された期間であり、サーバーによって調整されます。レコードの場合、計算は完全にサーバー側で行われます。
input.frameCount = mReqFrameCount;
input.notificationFrameCount = mNotificationFramesReq;
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
originalSessionId = mSessionId;
input.maxSharedAudioHistoryMs = mMaxSharedAudioHistoryMs;
do {
media::CreateRecordResponse response;
auto aidlInput = input.toAidl();
if (!aidlInput.ok()) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s(%d): Could not create record due to invalid input", __func__,
mPortId),
"");
}
status = audioFlinger->createRecord(aidlInput.value(), response); // レコードを作成
auto recordOutput = IAudioFlinger::CreateRecordOutput::fromAidl(response);
if (!recordOutput.ok()) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s(%d): Could not create record output due to invalid response",
__func__, mPortId),
"");
}
output = recordOutput.value();
if (status == NO_ERROR) {
break;
}
if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
return logIfErrorAndReturnStatus(
status,
StringPrintf("%s(%d): AudioFlinger could not create record track, status: %d",
__func__, mPortId, status),
"");
}
// FAILED_TRANSACTIONは、入力ストリームオープンシーケンス中にオーディオポリシーマネージャーとオーディオフリンガーの間で状態不一致を引き起こす特定の条件下で発生し、
// 再試行することで回復できます。
// 再試行する前に競合状態がクリアされるのを待つための時間を残し、同時再試行の確率を減らすために遅延をランダム化します。
usleep((20 + rand() % 30) * 10000);
} while (1);
ALOG_ASSERT(output.audioRecord != 0);
// AudioFlingerはI/Oハンドルへの参照を所有しているため、
// もはやそれを解放する責任はありません。
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);
mHalSampleRate = output.halConfig.sample_rate;
mHalChannelCount = audio_channel_count_from_in_mask(output.halConfig.channel_mask);
mHalFormat = output.halConfig.format;
if (output.cblk == 0) {
return logIfErrorAndReturnStatus(
NO_INIT, StringPrintf("%s(%d): Could not get control block", __func__, mPortId),
"");
}
// TODO: unsecurePointer()を使用することにはいくつかの関連するセキュリティの落とし穴があります
// (詳細については宣言を参照)。
// この場合に安全である理由を文書化するか、問題に対処します(例:コピーすることによって)。
iMemPointer = output.cblk ->unsecurePointer(); // 共有メモリを取得
if (iMemPointer == NULL) {
return logIfErrorAndReturnStatus(
NO_INIT,
StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId), "");
}
cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
// 共有メモリ内のバッファの開始アドレス。
// バッファは制御ブロックのすぐ後にあるか、
// サーバーの裁量で別の領域にあります。
void *buffers;
if (output.buffers == 0) {
buffers = cblk + 1;
} else {
// TODO: unsecurePointer()を使用することにはいくつかの関連するセキュリティの落とし穴があります
// (詳細については宣言を参照)。
// この場合に安全である理由を文書化するか、問題に対処します(例:コピーすることによって)。
buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
return logIfErrorAndReturnStatus(
NO_INIT,
StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId), "");
}
}
// mAudioRecord != 0の不変条件は、set()が正常に戻った後のみ真です
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;
// output.frameCountは(おそらく修正された)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);
}
// アプリケーションがオーバーランの前に通知されるようにします。
// 計算はサーバー側で行われます。
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は、mInputが最初の作成のためにAUDIO_IO_HANDLE_NONEである場合を含みます
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;
// I/Oハンドルのコピーを保持しますが、参照は所有しません
mInput = output.inputId;
mRefreshRemaining = true;
mFrameCount = output.frameCount;
// IAudioRecordが再作成される場合、要求されたframeCountが減少しないようにします。
// これは、frameCount()をキャッシュするクライアントを混乱させる可能性があります。
if (mFrameCount > mReqFrameCount) {
mReqFrameCount = mFrameCount;
}
// プロキシを更新します
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))
// 以下は不変です(復元されるまで少なくとも)
.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)
// 以下は不変ではありません
.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();
// sp<IAudioTrack> trackのデストラクタは、AudioFlingerによってreleaseOutput()を呼び出します
return logIfErrorAndReturnStatus(status, "", "");
}
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch)
{
const int64_t beginNs = systemTime();
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
IAudioFlinger::CreateRecordInput input;
IAudioFlinger::CreateRecordOutput output;
[[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;
if (audioFlinger == 0) {
return logIfErrorAndReturnStatus(
NO_INIT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId), "");
}
// mFlags (not mOrigFlags)は、ファストリクエストが受け入れられるかどうかに応じて変更されます。
// ファストリクエストが拒否された後、IAudioRecordが再作成される場合は再リクエストします。
// クライアントはFASTの好みを表現できます。サーバーは追加のテストを実行します。
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
bool useCaseAllowed =
// これらのいずれかの使用ケース:
// 使用ケース1:コールバック転送モード
(mTransfer == TRANSFER_CALLBACK) ||
// 使用ケース2:ブロッキング読み取りモード
// 48kHzでのデフォルトバッファ容量は2048フレーム、または約42.6msです。
// これは、標準の20msルールに従ったダブルバッファリングに十分です。
// これは、AAudioアプリがSCHED_FIFOで実行されているコールバックから低レイテンシのノンブロッキング読み取りを行うために必要です。
(mTransfer == TRANSFER_SYNC) ||
// 使用ケース3:取得/解放モード
(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;
// 通知フレーム数はコールバックによって提案された期間であり、サーバーによって調整されます。レコードの場合、計算は完全にサーバー側で行われます。
input.frameCount = mReqFrameCount;
input.notificationFrameCount = mNotificationFramesReq;
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
originalSessionId = mSessionId;
input.maxSharedAudioHistoryMs = mMaxSharedAudioHistoryMs;
do {
media::CreateRecordResponse response;
auto aidlInput = input.toAidl();
if (!aidlInput.ok()) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s(%d): Could not create record due to invalid input", __func__,
mPortId),
"");
}
status = audioFlinger->createRecord(aidlInput.value(), response); // レコードを作成
auto recordOutput = IAudioFlinger::CreateRecordOutput::fromAidl(response);
if (!recordOutput.ok()) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s(%d): Could not create record output due to invalid response",
__func__, mPortId),
"");
}
output = recordOutput.value();
if (status == NO_ERROR) {
break;
}
if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
return logIfErrorAndReturnStatus(
status,
StringPrintf("%s(%d): AudioFlinger could not create record track, status: %d",
__func__, mPortId, status),
"");
}
// FAILED_TRANSACTIONは、入力ストリームオープンシーケンス中にオーディオポリシーマネージャーとオーディオフリンガーの間で状態不一致を引き起こす特定の条件下で発生し、
// 再試行することで回復できます。
// 再試行する前に競合状態がクリアされるのを待つための時間を残し、同時再試行の確率を減らすために遅延をランダム化します。
usleep((20 + rand() % 30) * 10000);
} while (1);
ALOG_ASSERT(output.audioRecord != 0);
// AudioFlingerはI/Oハンドルへの参照を所有しているため、
// もはやそれを解放する責任はありません。
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);
mHalSampleRate = output.halConfig.sample_rate;
mHalChannelCount = audio_channel_count_from_in_mask(output.halConfig.channel_mask);
mHalFormat = output.halConfig.format;
if (output.cblk == 0) {
return logIfErrorAndReturnStatus(
NO_INIT, StringPrintf("%s(%d): Could not get control block", __func__, mPortId),
"");
}
// TODO: unsecurePointer()を使用することにはいくつかの関連するセキュリティの落とし穴があります
// (詳細については宣言を参照)。
// この場合に安全である理由を文書化するか、問題に対処します(例:コピーすることによって)。
iMemPointer = output.cblk ->unsecurePointer(); // 共有メモリを取得
if (iMemPointer == NULL) {
return logIfErrorAndReturnStatus(
NO_INIT,
StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId), "");
}
cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
// 共有メモリ内のバッファの開始アドレス。
// バッファは制御ブロックのすぐ後にあるか、
// サーバーの裁量で別の領域にあります。
void *buffers;
if (output.buffers == 0) {
buffers = cblk + 1;
} else {
// TODO: unsecurePointer()を使用することにはいくつかの関連するセキュリティの落とし穴があります
// (詳細については宣言を参照)。
// この場合に安全である理由を文書化するか、問題に対処します(例:コピーすることによって)。
buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
return logIfErrorAndReturnStatus(
NO_INIT,
StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId), "");
}
}
// mAudioRecord != 0の不変条件は、set()が正常に戻った後のみ真です
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;
// output.frameCountは(おそらく修正された)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);
}
// アプリケーションがオーバーランの前に通知されるようにします。
// 計算はサーバー側で行われます。
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は、mInputが最初の作成のためにAUDIO_IO_HANDLE_NONEである場合を含みます
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;
// I/Oハンドルのコピーを保持しますが、参照は所有しません
mInput = output.inputId;
mRefreshRemaining = true;
mFrameCount = output.frameCount;
// IAudioRecordが再作成される場合、要求されたframeCountが減少しないようにします。
// これは、frameCount()をキャッシュするクライアントを混乱させる可能性があります。
if (mFrameCount > mReqFrameCount) {
mReqFrameCount = mFrameCount;
}
// プロキシを更新します
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))
// 以下は不変です(復元されるまで少なくとも)
.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)
// 以下は不変ではありません
.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();
// sp<IAudioTrack> trackのデストラクタは、AudioFlingerによってreleaseOutput()を呼び出します
return logIfErrorAndReturnStatus(status, "", "");
}
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch)
{
const int64_t beginNs = systemTime();
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
IAudioFlinger::CreateRecordInput input;
IAudioFlinger::CreateRecordOutput output;
[[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;
if (audioFlinger == 0) {
return logIfErrorAndReturnStatus(
NO_INIT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId), "");
}
// mFlags (not mOrigFlags)は、ファストリクエストが受け入れられるかどうかに応じて変更されます。
// ファストリクエストが拒否された後、IAudioRecordが再作成される場合は再リクエストします。
// クライアントはFASTの好みを表現できます。サーバーは追加のテストを実行します。
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
bool useCaseAllowed =
// これらのいずれかの使用ケース:
// 使用ケース1:コールバック転送モード
(mTransfer == TRANSFER_CALLBACK) ||
// 使用ケース2:ブロッキング読み取りモード
// 48kHzでのデフォルトバッファ容量は2048フレーム、または約42.6msです。
// これは、標準の20msルールに従ったダブルバッファリングに十分です。
// これは、AAudioアプリがSCHED_FIFOで実行されているコールバックから低レイテンシのノンブロッキング読み取りを行うために必要です。
(mTransfer == TRANSFER_SYNC) ||
// 使用ケース3:取得/解放モード
(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;
// 通知フレーム数はコールバックによって提案された期間であり、サーバーによって調整されます。レコードの場合、計算は完全にサーバー側で行われます。
input.frameCount = mReqFrameCount;
input.notificationFrameCount = mNotificationFramesReq;
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
originalSessionId = mSessionId;
input.maxSharedAudioHistoryMs = mMaxSharedAudioHistoryMs;
do {
media::CreateRecordResponse response;
auto aidlInput = input.toAidl();
if (!aidlInput.ok()) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s(%d): Could not create record due to invalid input", __func__,
mPortId),
"");
}
status = audioFlinger->createRecord(aidlInput.value(), response); // レコードを作成
auto recordOutput = IAudioFlinger::CreateRecordOutput::fromAidl(response);
if (!recordOutput.ok()) {
return logIfErrorAndReturnStatus(
BAD_VALUE,
StringPrintf("%s(%d): Could not create record output due to invalid response",
__func__, mPortId),
"");
}
output = recordOutput.value();
if (status == NO_ERROR) {
break;
}
if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
return logIfErrorAndReturnStatus(
status,
StringPrintf("%s(%d): AudioFlinger could not create record track, status: %d",
__func__, mPortId, status),
"");
}
// FAILED_TRANSACTIONは、入力ストリームオープンシーケンス中にオーディオポリシーマネージャーとオーディオフリンガーの間で状態不一致を引き起こす特定の条件下で発生し、
// 再試行することで回復できます。
// 再試行する前に競合状態がクリアされるのを待つための時間を残し、同時再試行の確率を減らすために遅延をランダム化します。
usleep((20 + rand() % 30) * 10000);
} while (1);
ALOG_ASSERT(output.audioRecord != 0);
// AudioFlingerはI/Oハンドルへの参照を所有しているため、
// もはやそれを解放する責任はありません。
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);
mHalSampleRate = output.halConfig.sample_rate;
mHalChannelCount = audio_channel_count_from_in_mask(output.halConfig.channel_mask);
mHalFormat = output.halConfig.format;
if (output.cblk == 0) {
return logIfErrorAndReturnStatus(
NO_INIT, StringPrintf("%s(%d): Could not get control block", __func__, mPortId),
"");
}
// TODO: unsecurePointer()を使用することにはいくつかの関連するセキュリティの落とし穴があります
// (詳細については宣言を参照)。
// この場合に安全である理由を文書化するか、問題に対処します(例:コピーすることによって)。
iMemPointer = output.cblk ->unsecurePointer(); // 共有メモリを取得
if (iMemPointer == NULL) {
return logIfErrorAndReturnStatus(
NO_INIT,
StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId), "");
}
cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
// 共有メモリ内のバッファの開始アドレス。
// バッファは制御ブロックのすぐ後にあるか、
// サーバーの裁量で別の領域にあります。
void *buffers;
if (output.buffers == 0) {
buffers = cblk + 1;
} else {
// TODO: unsecurePointer()を使用することにはいくつかの関連するセキュリティの落とし穴があります
// (詳細については宣言を参照)。
// この場合に安全である理由を文書化するか、問題に対処します(例:コピーすることによって)。
buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
return logIfErrorAndReturnStatus(
NO_INIT,
StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId), "");
}
}
// mAudioRecord != 0の不変条件は、set()が正常に戻った後のみ真です
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;
// output.frameCountは(おそらく修正された)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);
}
// アプリケーションがオーバーランの前に通知されるようにします。
// 計算はサーバー側で行われます。
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は、mInputが最初の作成のためにAUDIO_IO_HANDLE_NONEである場合を含みます
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;
// I/Oハンドルのコピーを保持しますが、参照は所有しません
mInput = output.inputId;
mRefreshRemaining = true;
mFrameCount = output.frameCount;
// IAudioRecordが再作成される場合、要求されたframeCountが減少しないようにします。
// これは、frameCount()をキャッシュするクライアントを混乱させる可能性があります。
if (mFrameCount > mReqFrameCount) {
mReqFrameCount = mFrameCount;
}
// プロキシを更新します
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(AMEDIAMET