blob: 91bc700c9513ce34d5a1869616b0d7a81969563b [file] [log] [blame]
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001/*
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "AudioRecord"
20
Mark Salyzyn34fb2962014-06-18 16:30:56 -070021#include <inttypes.h>
Chih-Hung Hsiehffe35582018-09-13 13:59:28 -070022#include <android-base/macros.h>
Andy Hungb58f2c52022-01-10 00:00:15 -080023#include <android-base/stringprintf.h>
Glenn Kasten868a6a32012-06-21 16:22:09 -070024#include <sys/resource.h>
Mark Salyzyn34fb2962014-06-18 16:30:56 -070025
jiabinb00edc32021-08-16 16:27:54 +000026#include <audio_utils/format.h>
Mikhail Naganov2996f672019-04-18 12:29:59 -070027#include <audiomanager/AudioManager.h>
28#include <audiomanager/IAudioManager.h>
29#include <binder/Binder.h>
Glenn Kasten868a6a32012-06-21 16:22:09 -070030#include <binder/IPCThreadState.h>
Mikhail Naganov2996f672019-04-18 12:29:59 -070031#include <binder/IServiceManager.h>
Glenn Kasten868a6a32012-06-21 16:22:09 -070032#include <media/AudioRecord.h>
Glenn Kasten868a6a32012-06-21 16:22:09 -070033#include <utils/Log.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080034#include <private/media/AudioTrackShared.h>
Suren Baghdasaryan7435e7d2018-12-19 17:09:28 -080035#include <processgroup/sched_policy.h>
Glenn Kasten1ab85ec2013-05-31 09:18:43 -070036#include <media/IAudioFlinger.h>
Ray Essickf27e9872019-12-07 06:28:46 -080037#include <media/MediaMetricsItem.h>
Ray Essick734d1862018-01-09 10:42:14 -080038#include <media/TypeConverter.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080039
Glenn Kasten9f80dd22012-12-18 15:57:32 -080040#define WAIT_PERIOD_MS 10
41
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080042namespace android {
Philip P. Moltmannbda45752020-07-17 16:41:18 -070043
Andy Hungb58f2c52022-01-10 00:00:15 -080044using ::android::base::StringPrintf;
Svet Ganov3e5f14f2021-05-13 22:51:08 +000045using android::content::AttributionSourceState;
Andy Hung1131b6e2020-12-08 20:47:45 -080046using aidl_utils::statusTFromBinderStatus;
47
Chia-chi Yeh15304d62010-06-22 08:01:13 +080048// ---------------------------------------------------------------------------
49
50// static
51status_t AudioRecord::getMinFrameCount(
Glenn Kastene33054e2012-11-14 12:54:39 -080052 size_t* frameCount,
Chia-chi Yeh15304d62010-06-22 08:01:13 +080053 uint32_t sampleRate,
Glenn Kasten58f30212012-01-12 12:27:51 -080054 audio_format_t format,
Glenn Kastendd8104c2012-07-02 12:42:44 -070055 audio_channel_mask_t channelMask)
Chia-chi Yeh15304d62010-06-22 08:01:13 +080056{
Glenn Kasten9f80dd22012-12-18 15:57:32 -080057 if (frameCount == NULL) {
58 return BAD_VALUE;
59 }
Glenn Kasten04cd0182012-06-25 11:49:27 -070060
Glenn Kastenb42f3182014-02-24 13:42:58 -080061 size_t size;
Glenn Kastenc9b2e202013-02-26 11:32:32 -080062 status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
63 if (status != NO_ERROR) {
Andy Hung6b1c6122018-09-12 19:09:07 -070064 ALOGE("%s(): AudioSystem could not query the input buffer size for"
65 " sampleRate %u, format %#x, channelMask %#x; status %d",
66 __func__, sampleRate, format, channelMask, status);
Glenn Kastenb42f3182014-02-24 13:42:58 -080067 return status;
Chia-chi Yeh15304d62010-06-22 08:01:13 +080068 }
69
Glenn Kastenb42f3182014-02-24 13:42:58 -080070 // We double the size of input buffer for ping pong use of record buffer.
Dean Wheatleyd883e302023-10-20 06:11:43 +110071 const auto frameSize = audio_bytes_per_frame(
72 audio_channel_count_from_in_mask(channelMask), format);
73 if (frameSize == 0 || ((*frameCount = (size * 2) / frameSize) == 0)) {
Andy Hung6b1c6122018-09-12 19:09:07 -070074 ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
75 __func__, sampleRate, format, channelMask);
Chia-chi Yeh15304d62010-06-22 08:01:13 +080076 return BAD_VALUE;
77 }
78
Chia-chi Yeh15304d62010-06-22 08:01:13 +080079 return NO_ERROR;
80}
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080081
82// ---------------------------------------------------------------------------
83
Ray Essick734d1862018-01-09 10:42:14 -080084void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
85{
Andy Hungd0979812019-02-21 15:51:44 -080086#define MM_PREFIX "android.media.audiorecord." // avoid cut-n-paste errors.
Ray Essick734d1862018-01-09 10:42:14 -080087
Andy Hungd0979812019-02-21 15:51:44 -080088 // Java API 28 entries, do not change.
Ray Essickf27e9872019-12-07 06:28:46 -080089 mMetricsItem->setCString(MM_PREFIX "encoding", toString(record->mFormat).c_str());
90 mMetricsItem->setCString(MM_PREFIX "source", toString(record->mAttributes.source).c_str());
91 mMetricsItem->setInt32(MM_PREFIX "latency", (int32_t)record->mLatency); // bad estimate.
92 mMetricsItem->setInt32(MM_PREFIX "samplerate", (int32_t)record->mSampleRate);
93 mMetricsItem->setInt32(MM_PREFIX "channels", (int32_t)record->mChannelCount);
Ray Essick734d1862018-01-09 10:42:14 -080094
Andy Hungd0979812019-02-21 15:51:44 -080095 // Non-API entries, these can change.
Ray Essickf27e9872019-12-07 06:28:46 -080096 mMetricsItem->setInt32(MM_PREFIX "portId", (int32_t)record->mPortId);
97 mMetricsItem->setInt32(MM_PREFIX "frameCount", (int32_t)record->mFrameCount);
98 mMetricsItem->setCString(MM_PREFIX "attributes", toString(record->mAttributes).c_str());
99 mMetricsItem->setInt64(MM_PREFIX "channelMask", (int64_t)record->mChannelMask);
Ray Essick84e84a52018-05-03 18:45:07 -0700100
Andy Hungd0979812019-02-21 15:51:44 -0800101 // log total duration recording, including anything currently running.
102 int64_t activeNs = 0;
Ray Essick84e84a52018-05-03 18:45:07 -0700103 if (mStartedNs != 0) {
Andy Hungd0979812019-02-21 15:51:44 -0800104 activeNs = systemTime() - mStartedNs;
Ray Essick84e84a52018-05-03 18:45:07 -0700105 }
Ray Essickf27e9872019-12-07 06:28:46 -0800106 mMetricsItem->setDouble(MM_PREFIX "durationMs", (mDurationNs + activeNs) * 1e-6);
107 mMetricsItem->setInt64(MM_PREFIX "startCount", (int64_t)mCount);
Ray Essick84e84a52018-05-03 18:45:07 -0700108
109 if (mLastError != NO_ERROR) {
Ray Essickf27e9872019-12-07 06:28:46 -0800110 mMetricsItem->setInt32(MM_PREFIX "lastError.code", (int32_t)mLastError);
111 mMetricsItem->setCString(MM_PREFIX "lastError.at", mLastErrorFunc.c_str());
Ray Essick84e84a52018-05-03 18:45:07 -0700112 }
Andy Hung1a9c21b2021-02-25 20:43:18 -0800113 mMetricsItem->setCString(MM_PREFIX "logSessionId", record->mLogSessionId.c_str());
Ray Essick88394302018-01-24 14:52:05 -0800114}
115
Andy Hungb68f5eb2019-12-03 16:49:17 -0800116static const char *stateToString(bool active) {
117 return active ? "ACTIVE" : "STOPPED";
118}
119
Ray Essick88394302018-01-24 14:52:05 -0800120// hand the user a snapshot of the metrics.
Ray Essickf27e9872019-12-07 06:28:46 -0800121status_t AudioRecord::getMetrics(mediametrics::Item * &item)
Ray Essick88394302018-01-24 14:52:05 -0800122{
123 mMediaMetrics.gather(this);
Ray Essickf27e9872019-12-07 06:28:46 -0800124 mediametrics::Item *tmp = mMediaMetrics.dup();
Ray Essick88394302018-01-24 14:52:05 -0800125 if (tmp == nullptr) {
126 return BAD_VALUE;
127 }
128 item = tmp;
129 return NO_ERROR;
Ray Essick734d1862018-01-09 10:42:14 -0800130}
131
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000132AudioRecord::AudioRecord(const AttributionSourceState &client)
133 : mActive(false), mStatus(NO_INIT), mClientAttributionSource(client),
134 mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL),
135 mPreviousSchedulingGroup(SP_DEFAULT), mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
136 mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE), mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
Paul McLean366b6432019-02-25 10:35:51 -0700137 mSelectedMicFieldDimension(MIC_FIELD_DIMENSION_DEFAULT)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800138{
139}
140
141AudioRecord::AudioRecord(
Glenn Kasteneba51fb2012-01-23 13:58:49 -0800142 audio_source_t inputSource,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800143 uint32_t sampleRate,
Glenn Kasten58f30212012-01-12 12:27:51 -0800144 audio_format_t format,
Glenn Kasten624a7fc2012-06-21 16:24:00 -0700145 audio_channel_mask_t channelMask,
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000146 const AttributionSourceState& client,
Glenn Kastenbce50bf2014-02-27 15:29:51 -0800147 size_t frameCount,
Atneya Nairb249d272021-11-29 18:06:46 -0500148 const wp<IAudioRecordCallback>& callback,
149 uint32_t notificationFrames,
150 audio_session_t sessionId,
151 transfer_type transferType,
152 audio_input_flags_t flags,
153 const audio_attributes_t* pAttributes,
154 audio_port_handle_t selectedDeviceId,
155 audio_microphone_direction_t selectedMicDirection,
156 float microphoneFieldDimension)
157 : mActive(false),
158 mStatus(NO_INIT),
159 mClientAttributionSource(client),
160 mSessionId(AUDIO_SESSION_ALLOCATE),
161 mPreviousPriority(ANDROID_PRIORITY_NORMAL),
162 mPreviousSchedulingGroup(SP_DEFAULT),
163 mProxy(nullptr)
164{
165 uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mClientAttributionSource.uid));
166 pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid));
167 (void)set(inputSource, sampleRate, format, channelMask, frameCount, callback,
Eric Laurentcaf7f482014-11-25 17:50:47 -0800168 notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700169 uid, pid, pAttributes, selectedDeviceId, selectedMicDirection,
170 microphoneFieldDimension);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800171}
172
173AudioRecord::~AudioRecord()
174{
Ray Essick734d1862018-01-09 10:42:14 -0800175 mMediaMetrics.gather(this);
176
Andy Hungb68f5eb2019-12-03 16:49:17 -0800177 mediametrics::LogItem(mMetricsId)
178 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
Phil Burkd3813f32020-04-23 16:26:15 -0700179 .set(AMEDIAMETRICS_PROP_CALLERNAME,
180 mCallerName.empty()
Andy Hunga6b27032020-04-27 10:34:24 -0700181 ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
Phil Burkd3813f32020-04-23 16:26:15 -0700182 : mCallerName.c_str())
Andy Hungb68f5eb2019-12-03 16:49:17 -0800183 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
184 .record();
185
Phil Burk7a9577c2021-03-12 20:12:11 +0000186 stopAndJoinCallbacks(); // checks mStatus
187
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800188 if (mStatus == NO_ERROR) {
Marco Nelissenf8880202014-11-14 07:58:25 -0800189 IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
Glenn Kasten089e8722014-02-24 15:12:48 -0800190 mAudioRecord.clear();
Eric Laurent3bcffa12014-06-12 18:38:45 -0700191 mCblkMemory.clear();
192 mBufferMemory.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800193 IPCThreadState::self()->flushCommands();
Andy Hung6b1c6122018-09-12 19:09:07 -0700194 ALOGV("%s(%d): releasing session id %d",
Eric Laurent973db022018-11-20 14:54:31 -0800195 __func__, mPortId, mSessionId);
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000196 pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientAttributionSource.pid));
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700197 AudioSystem::releaseAudioSessionId(mSessionId, pid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800198 }
199}
200
Phil Burk7a9577c2021-03-12 20:12:11 +0000201void AudioRecord::stopAndJoinCallbacks() {
202 // Prevent nullptr crash if it did not open properly.
203 if (mStatus != NO_ERROR) return;
204
205 // Make sure that callback function exits in the case where
206 // it is looping on buffer empty condition in obtainBuffer().
207 // Otherwise the callback thread will never exit.
208 stop();
209 if (mAudioRecordThread != 0) {
Phil Burk7a9577c2021-03-12 20:12:11 +0000210 mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
Andy Hung21f819c2021-12-02 10:51:40 -0800211 mProxy->interrupt();
Phil Burk7a9577c2021-03-12 20:12:11 +0000212 mAudioRecordThread->requestExitAndWait();
213 mAudioRecordThread.clear();
214 }
zhenjun.zhang116df6a2021-12-08 09:17:13 +0800215
216 AutoMutex lock(mLock);
Phil Burk7a9577c2021-03-12 20:12:11 +0000217 if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
218 // This may not stop all of these device callbacks!
219 // TODO: Add some sort of protection.
220 AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
zhenjun.zhang116df6a2021-12-08 09:17:13 +0800221 mDeviceCallback.clear();
Phil Burk7a9577c2021-03-12 20:12:11 +0000222 }
223}
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800224status_t AudioRecord::set(
Glenn Kasteneba51fb2012-01-23 13:58:49 -0800225 audio_source_t inputSource,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800226 uint32_t sampleRate,
Glenn Kasten58f30212012-01-12 12:27:51 -0800227 audio_format_t format,
Glenn Kasten624a7fc2012-06-21 16:24:00 -0700228 audio_channel_mask_t channelMask,
Glenn Kastenbce50bf2014-02-27 15:29:51 -0800229 size_t frameCount,
Atneya Nairb249d272021-11-29 18:06:46 -0500230 const wp<IAudioRecordCallback>& callback,
Glenn Kasten838b3d82014-02-27 15:30:41 -0800231 uint32_t notificationFrames,
Eric Laurentbe916aa2010-06-01 23:49:17 -0700232 bool threadCanCallJava,
Glenn Kastend848eb42016-03-08 13:42:11 -0800233 audio_session_t sessionId,
Glenn Kasten27f7b2a2013-07-31 16:10:22 -0700234 transfer_type transferType,
Eric Laurentcaf7f482014-11-25 17:50:47 -0800235 audio_input_flags_t flags,
Andy Hung1f12a8a2016-11-07 16:10:30 -0800236 uid_t uid,
Jean-Michel Trivi4cb66832015-05-01 18:34:17 -0700237 pid_t pid,
jiabinfec2f932017-10-24 10:10:53 -0700238 const audio_attributes_t* pAttributes,
Paul McLean366b6432019-02-25 10:35:51 -0700239 audio_port_handle_t selectedDeviceId,
240 audio_microphone_direction_t selectedMicDirection,
Eric Laurentec376dc2021-04-08 20:41:22 +0200241 float microphoneFieldDimension,
242 int32_t maxSharedAudioHistoryMs)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800243{
Eric Laurentf14db3c2017-12-08 14:20:36 -0800244 status_t status = NO_ERROR;
Atneya Nairc2f0db72022-02-28 16:00:51 -0500245 LOG_ALWAYS_FATAL_IF(mInitialized, "%s: should not be called twice", __func__);
246 mInitialized = true;
Eric Laurent973db022018-11-20 14:54:31 -0800247 // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
Andy Hung6b1c6122018-09-12 19:09:07 -0700248 ALOGV("%s(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000249 "notificationFrames %u, sessionId %d, transferType %d, flags %#x, attributionSource %s"
Jean-Michel Trivi4cb66832015-05-01 18:34:17 -0700250 "uid %d, pid %d",
Andy Hung6b1c6122018-09-12 19:09:07 -0700251 __func__,
Glenn Kastenbce50bf2014-02-27 15:29:51 -0800252 inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000253 sessionId, transferType, flags, mClientAttributionSource.toString().c_str(), uid, pid);
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700254
255 // TODO b/182392553: refactor or remove
256 pid_t callingPid = IPCThreadState::self()->getCallingPid();
257 pid_t myPid = getpid();
258 pid_t adjPid = pid;
259 if (pid == -1 || (callingPid != myPid)) {
260 adjPid = callingPid;
261 }
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000262 mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700263
264 uid_t adjUid = uid;
265 if (uid == -1 || (callingPid != myPid)) {
266 adjUid = IPCThreadState::self()->getCallingUid();
267 }
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000268 mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
Glenn Kasten86f04662014-02-24 15:13:05 -0800269
Mikhail Naganov2996f672019-04-18 12:29:59 -0700270 mTracker.reset(new RecordingActivityTracker());
271
jiabinfec2f932017-10-24 10:10:53 -0700272 mSelectedDeviceId = selectedDeviceId;
Paul McLean366b6432019-02-25 10:35:51 -0700273 mSelectedMicDirection = selectedMicDirection;
274 mSelectedMicFieldDimension = microphoneFieldDimension;
Eric Laurentec376dc2021-04-08 20:41:22 +0200275 mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
jiabinfec2f932017-10-24 10:10:53 -0700276
Andy Hungb58f2c52022-01-10 00:00:15 -0800277 std::string errorMessage;
278 // Copy the state variables early so they are available for error reporting.
Atneya Nairb249d272021-11-29 18:06:46 -0500279 if (pAttributes == nullptr) {
Eric Laurentd17c8502019-10-24 15:58:35 -0700280 mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
Eric Laurentcaf7f482014-11-25 17:50:47 -0800281 mAttributes.source = inputSource;
Eric Laurentd17c8502019-10-24 15:58:35 -0700282 if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION
283 || inputSource == AUDIO_SOURCE_CAMCORDER) {
Mikhail Naganov55773032020-10-01 15:08:13 -0700284 mAttributes.flags = static_cast<audio_flags_mask_t>(
285 mAttributes.flags | AUDIO_FLAG_CAPTURE_PRIVATE);
Eric Laurentd17c8502019-10-24 15:58:35 -0700286 }
Eric Laurentcaf7f482014-11-25 17:50:47 -0800287 } else {
288 // stream type shouldn't be looked at, this track has audio attributes
289 memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
Andy Hungb58f2c52022-01-10 00:00:15 -0800290 ALOGV("%s: Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]",
Andy Hung6b1c6122018-09-12 19:09:07 -0700291 __func__, mAttributes.source, mAttributes.flags, mAttributes.tags);
Eric Laurentcaf7f482014-11-25 17:50:47 -0800292 }
Glenn Kastene3aa6592012-12-04 12:22:46 -0800293 mSampleRate = sampleRate;
Glenn Kasten58f30212012-01-12 12:27:51 -0800294 if (format == AUDIO_FORMAT_DEFAULT) {
Dima Zavinfce7a472011-04-19 22:30:36 -0700295 format = AUDIO_FORMAT_PCM_16_BIT;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800296 }
Atneya Nair497fff12022-01-18 16:23:04 -0500297 if (!audio_is_linear_pcm(format)) {
298 // Compressed capture requires direct
299 flags = (audio_input_flags_t) (flags | AUDIO_INPUT_FLAG_DIRECT);
300 ALOGI("%s(): Format %#x is not linear pcm. Setting DIRECT, using flags %#x", __func__,
301 format, flags);
302 }
Glenn Kasten2e466462013-01-10 14:26:24 -0800303 mFormat = format;
Glenn Kastena42ff002012-11-14 12:47:55 -0800304 mChannelMask = channelMask;
Andy Hungb58f2c52022-01-10 00:00:15 -0800305 mSessionId = sessionId;
306 ALOGV("%s: mSessionId %d", __func__, mSessionId);
307 mOrigFlags = mFlags = flags;
Eric Laurentc2f1f072009-07-17 12:17:14 -0700308
Andy Hungb58f2c52022-01-10 00:00:15 -0800309 mTransfer = transferType;
310 switch (mTransfer) {
311 case TRANSFER_DEFAULT:
Atneya Nair2eedae32022-02-14 16:42:23 -0500312 if (callback == nullptr || threadCanCallJava) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800313 mTransfer = TRANSFER_SYNC;
314 } else {
315 mTransfer = TRANSFER_CALLBACK;
316 }
317 break;
318 case TRANSFER_CALLBACK:
Atneya Nair2eedae32022-02-14 16:42:23 -0500319 if (callback == nullptr) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800320 errorMessage = StringPrintf(
321 "%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__);
322 status = BAD_VALUE;
323 goto error;
324 }
325 break;
326 case TRANSFER_OBTAIN:
327 case TRANSFER_SYNC:
328 break;
329 default:
330 errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer);
331 status = BAD_VALUE;
332 goto error;
333 }
334
335 // invariant that mAudioRecord != 0 is true only after set() returns successfully
336 if (mAudioRecord != 0) {
337 errorMessage = StringPrintf("%s: Track already in use", __func__);
338 status = INVALID_OPERATION;
339 goto error;
340 }
341
Atneya Nair497fff12022-01-18 16:23:04 -0500342 if (!audio_is_valid_format(mFormat)) {
343 errorMessage = StringPrintf("%s: Format %#x is not valid", __func__, mFormat);
Andy Hungb58f2c52022-01-10 00:00:15 -0800344 status = BAD_VALUE;
345 goto error;
346 }
347
348 if (!audio_is_input_channel(mChannelMask)) {
349 errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask);
350 status = BAD_VALUE;
351 goto error;
352 }
353
354 mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
Dean Wheatleyd883e302023-10-20 06:11:43 +1100355 mFrameSize = audio_bytes_per_frame(mChannelCount, mFormat);
Glenn Kastene3aa6592012-12-04 12:22:46 -0800356
Eric Laurentf14db3c2017-12-08 14:20:36 -0800357 // mFrameCount is initialized in createRecord_l
Glenn Kastenb3b2e232014-02-05 11:10:26 -0800358 mReqFrameCount = frameCount;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800359
Glenn Kasten4a0efb72013-08-08 15:20:53 -0700360 mNotificationFramesReq = notificationFrames;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800361 // mNotificationFramesAct is initialized in createRecord_l
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800362
Atneya Nair2eedae32022-02-14 16:42:23 -0500363 mCallback = callback;
Atneya Nairb249d272021-11-29 18:06:46 -0500364 if (mCallback != nullptr) {
Andy Hungca353672019-03-06 11:54:38 -0800365 mAudioRecordThread = new AudioRecordThread(*this);
Glenn Kasten68337ed2012-07-12 09:05:58 -0700366 mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
Glenn Kastenbfd31842015-03-20 09:01:44 -0700367 // thread begins in paused state, and will not reference us until start()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800368 }
369
Glenn Kasten87970702014-02-27 15:31:39 -0800370 // create the IAudioRecord
Francois Gaffie24a9fb02019-01-18 17:51:34 +0100371 {
372 AutoMutex lock(mLock);
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700373 status = createRecord_l(0 /*epoch*/);
Francois Gaffie24a9fb02019-01-18 17:51:34 +0100374 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800375
Eric Laurent973db022018-11-20 14:54:31 -0800376 ALOGV("%s(%d): status %d", __func__, mPortId, status);
Andy Hung6b1c6122018-09-12 19:09:07 -0700377
Glenn Kasten87970702014-02-27 15:31:39 -0800378 if (status != NO_ERROR) {
379 if (mAudioRecordThread != 0) {
380 mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
381 mAudioRecordThread->requestExitAndWait();
382 mAudioRecordThread.clear();
383 }
Andy Hungb58f2c52022-01-10 00:00:15 -0800384 // bypass error message to avoid logging twice (createRecord_l logs the error).
Eric Laurentf14db3c2017-12-08 14:20:36 -0800385 goto exit;
Glenn Kasten87970702014-02-27 15:31:39 -0800386 }
387
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800388 // TODO: add audio hardware input latency here
Andy Hung13969262017-09-11 17:24:21 -0700389 mLatency = (1000LL * mFrameCount) / mSampleRate;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800390 mMarkerPosition = 0;
Jean-Michel Trivi7d563242009-03-24 19:48:58 -0700391 mMarkerReached = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800392 mNewPosition = 0;
393 mUpdatePeriod = 0;
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700394 AudioSystem::acquireAudioSessionId(mSessionId, adjPid, adjUid);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800395 mSequence = 1;
396 mObservedSequence = mSequence;
397 mInOverrun = false;
Andy Hung3f0c9022016-01-15 17:49:46 -0800398 mFramesRead = 0;
399 mFramesReadServerOffset = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800400
Andy Hungb58f2c52022-01-10 00:00:15 -0800401error:
Ray Essick84e84a52018-05-03 18:45:07 -0700402 if (status != NO_ERROR) {
403 mMediaMetrics.markError(status, __FUNCTION__);
Andy Hungb58f2c52022-01-10 00:00:15 -0800404 ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
405 reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
Ray Essick84e84a52018-05-03 18:45:07 -0700406 }
Andy Hungb58f2c52022-01-10 00:00:15 -0800407exit:
408 mStatus = status;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800409 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800410}
411
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800412// -------------------------------------------------------------------------
413
Glenn Kastend848eb42016-03-08 13:42:11 -0800414status_t AudioRecord::start(AudioSystem::sync_event_t event, audio_session_t triggerSession)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800415{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800416 const int64_t beginNs = systemTime();
Eric Laurent973db022018-11-20 14:54:31 -0800417 ALOGV("%s(%d): sync event %d trigger session %d", __func__, mPortId, event, triggerSession);
Eric Laurentf5aafb22010-11-18 08:40:16 -0800418 AutoMutex lock(mLock);
Andy Hungb68f5eb2019-12-03 16:49:17 -0800419
420 status_t status = NO_ERROR;
Andy Hung06a730b2020-04-09 13:28:31 -0700421 mediametrics::Defer defer([&] {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800422 mediametrics::LogItem(mMetricsId)
Andy Hunga6b27032020-04-27 10:34:24 -0700423 .set(AMEDIAMETRICS_PROP_CALLERNAME,
424 mCallerName.empty()
425 ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
426 : mCallerName.c_str())
Andy Hungb68f5eb2019-12-03 16:49:17 -0800427 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
Andy Hungea840382020-05-05 21:50:17 -0700428 .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
Andy Hungb68f5eb2019-12-03 16:49:17 -0800429 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
430 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
431 .record(); });
432
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800433 if (mActive) {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800434 return status;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800435 }
Eric Laurent1703cdf2011-03-07 14:52:59 -0800436
Andy Hung3f0c9022016-01-15 17:49:46 -0800437 // discard data in buffer
438 const uint32_t framesFlushed = mProxy->flush();
439 mFramesReadServerOffset -= mFramesRead + framesFlushed;
440 mFramesRead = 0;
441 mProxy->clearTimestamp(); // timestamp is invalid until next server push
Andy Hung7efe2b82020-03-31 10:24:42 -0700442 mPreviousTimestamp.clear();
443 mTimestampRetrogradePositionReported = false;
444 mTimestampRetrogradeTimeReported = false;
Andy Hung3f0c9022016-01-15 17:49:46 -0800445
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800446 // reset current position as seen by client to 0
447 mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
Glenn Kasten5e1f79b2014-01-14 15:45:21 -0800448 // force refresh of remaining frames by processAudioBuffer() as last
449 // read before stop could be partial.
450 mRefreshRemaining = true;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800451
452 mNewPosition = mProxy->getPosition() + mUpdatePeriod;
Glenn Kasten96f60d82013-07-12 10:21:18 -0700453 int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800454
Andy Hung3da23b22015-10-23 18:11:28 -0700455 // we reactivate markers (mMarkerPosition != 0) as the position is reset to 0.
456 // This is legacy behavior. This is not done in stop() to avoid a race condition
457 // where the last marker event is issued twice.
458 mMarkerReached = false;
Mikhail Naganov2996f672019-04-18 12:29:59 -0700459 // mActive is checked by restoreRecord_l
Eric Laurent296fb132015-05-01 11:38:42 -0700460 mActive = true;
461
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800462 if (!(flags & CBLK_INVALID)) {
Andy Hung1131b6e2020-12-08 20:47:45 -0800463 status = statusTFromBinderStatus(mAudioRecord->start(event, triggerSession));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800464 if (status == DEAD_OBJECT) {
465 flags |= CBLK_INVALID;
466 }
467 }
468 if (flags & CBLK_INVALID) {
469 status = restoreRecord_l("start");
470 }
471
Paul McLean366b6432019-02-25 10:35:51 -0700472 // Call these directly because we are already holding the lock.
Paul McLean12340082019-03-19 09:35:05 -0600473 mAudioRecord->setPreferredMicrophoneDirection(mSelectedMicDirection);
474 mAudioRecord->setPreferredMicrophoneFieldDimension(mSelectedMicFieldDimension);
Paul McLean366b6432019-02-25 10:35:51 -0700475
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800476 if (status != NO_ERROR) {
Eric Laurent296fb132015-05-01 11:38:42 -0700477 mActive = false;
Eric Laurent973db022018-11-20 14:54:31 -0800478 ALOGE("%s(%d): status %d", __func__, mPortId, status);
Mikhail Naganov2996f672019-04-18 12:29:59 -0700479 mMediaMetrics.markError(status, __FUNCTION__);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800480 } else {
Mikhail Naganov2996f672019-04-18 12:29:59 -0700481 mTracker->recordingStarted();
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800482 sp<AudioRecordThread> t = mAudioRecordThread;
483 if (t != 0) {
484 t->resume();
Eric Laurent6100d2d2009-11-19 09:00:56 -0800485 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800486 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
487 get_sched_policy(0, &mPreviousSchedulingGroup);
488 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
Eric Laurent6100d2d2009-11-19 09:00:56 -0800489 }
Ray Essick84e84a52018-05-03 18:45:07 -0700490
491 // we've successfully started, log that time
492 mMediaMetrics.logStart(systemTime());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800493 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800494 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800495}
496
Glenn Kastend64cd232012-02-21 10:21:23 -0800497void AudioRecord::stop()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800498{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800499 const int64_t beginNs = systemTime();
Eric Laurentf5aafb22010-11-18 08:40:16 -0800500 AutoMutex lock(mLock);
Andy Hung06a730b2020-04-09 13:28:31 -0700501 mediametrics::Defer defer([&] {
Andy Hungb68f5eb2019-12-03 16:49:17 -0800502 mediametrics::LogItem(mMetricsId)
503 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
Andy Hungea840382020-05-05 21:50:17 -0700504 .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
Andy Hungb68f5eb2019-12-03 16:49:17 -0800505 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
506 .record(); });
507
Eric Laurent973db022018-11-20 14:54:31 -0800508 ALOGV("%s(%d): mActive:%d\n", __func__, mPortId, mActive);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800509 if (!mActive) {
510 return;
511 }
512
513 mActive = false;
514 mProxy->interrupt();
515 mAudioRecord->stop();
Mikhail Naganov2996f672019-04-18 12:29:59 -0700516 mTracker->recordingStopped();
Andy Hung3da23b22015-10-23 18:11:28 -0700517
518 // Note: legacy handling - stop does not clear record marker and
519 // periodic update position; we update those on start().
520
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800521 sp<AudioRecordThread> t = mAudioRecordThread;
522 if (t != 0) {
523 t->pause();
524 } else {
525 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
526 set_sched_policy(0, mPreviousSchedulingGroup);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800527 }
Ray Essick84e84a52018-05-03 18:45:07 -0700528
529 // we've successfully started, log that time
530 mMediaMetrics.logStop(systemTime());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800531}
532
533bool AudioRecord::stopped() const
534{
Glenn Kasten68337ed2012-07-12 09:05:58 -0700535 AutoMutex lock(mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800536 return !mActive;
537}
538
539status_t AudioRecord::setMarkerPosition(uint32_t marker)
540{
Atneya Nairb249d272021-11-29 18:06:46 -0500541 AutoMutex lock(mLock);
Glenn Kasten2b2165c2014-01-13 08:53:36 -0800542 // The only purpose of setting marker position is to get a callback
Atneya Nair2eedae32022-02-14 16:42:23 -0500543 if (mCallback == nullptr) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800544 return INVALID_OPERATION;
545 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800546
547 mMarkerPosition = marker;
Jean-Michel Trivi7d563242009-03-24 19:48:58 -0700548 mMarkerReached = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800549
Andy Hung803b3e52015-03-18 23:26:55 -0700550 sp<AudioRecordThread> t = mAudioRecordThread;
551 if (t != 0) {
552 t->wake();
553 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800554 return NO_ERROR;
555}
556
Robert Wu310037a2022-09-06 21:48:18 +0000557uint32_t AudioRecord::getHalSampleRate() const
558{
559 return mHalSampleRate;
560}
561
562uint32_t AudioRecord::getHalChannelCount() const
563{
564 return mHalChannelCount;
565}
566
567audio_format_t AudioRecord::getHalFormat() const
568{
569 return mHalFormat;
570}
571
Glenn Kasten606ee612012-02-24 16:33:14 -0800572status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800573{
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800574 if (marker == NULL) {
575 return BAD_VALUE;
576 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800577
Glenn Kasten955e7812012-02-21 10:32:45 -0800578 AutoMutex lock(mLock);
Andy Hung90e8a972015-11-09 16:42:40 -0800579 mMarkerPosition.getValue(marker);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800580
581 return NO_ERROR;
582}
583
584status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
585{
Atneya Nairb249d272021-11-29 18:06:46 -0500586 AutoMutex lock(mLock);
Glenn Kasten2b2165c2014-01-13 08:53:36 -0800587 // The only purpose of setting position update period is to get a callback
Atneya Nair2eedae32022-02-14 16:42:23 -0500588 if (mCallback == nullptr) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800589 return INVALID_OPERATION;
590 }
Glenn Kasten955e7812012-02-21 10:32:45 -0800591
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800592 mNewPosition = mProxy->getPosition() + updatePeriod;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800593 mUpdatePeriod = updatePeriod;
594
Andy Hung803b3e52015-03-18 23:26:55 -0700595 sp<AudioRecordThread> t = mAudioRecordThread;
596 if (t != 0) {
597 t->wake();
598 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800599 return NO_ERROR;
600}
601
Glenn Kasten606ee612012-02-24 16:33:14 -0800602status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800603{
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800604 if (updatePeriod == NULL) {
605 return BAD_VALUE;
606 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800607
Glenn Kasten955e7812012-02-21 10:32:45 -0800608 AutoMutex lock(mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800609 *updatePeriod = mUpdatePeriod;
610
611 return NO_ERROR;
612}
613
Glenn Kasten606ee612012-02-24 16:33:14 -0800614status_t AudioRecord::getPosition(uint32_t *position) const
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800615{
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800616 if (position == NULL) {
617 return BAD_VALUE;
618 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800619
Eric Laurent1703cdf2011-03-07 14:52:59 -0800620 AutoMutex lock(mLock);
Andy Hung90e8a972015-11-09 16:42:40 -0800621 mProxy->getPosition().getValue(position);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800622
623 return NO_ERROR;
624}
625
Glenn Kasten5f972c02014-01-13 09:59:31 -0800626uint32_t AudioRecord::getInputFramesLost() const
Eric Laurent05bca2f2010-02-26 02:47:27 -0800627{
Glenn Kastenbf04a5d2012-07-12 09:07:11 -0700628 // no need to check mActive, because if inactive this will return 0, which is what we want
Glenn Kasten32860f72015-03-20 08:55:18 -0700629 return AudioSystem::getInputFramesLost(getInputPrivate());
Eric Laurent05bca2f2010-02-26 02:47:27 -0800630}
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800631
Andy Hung3f0c9022016-01-15 17:49:46 -0800632status_t AudioRecord::getTimestamp(ExtendedTimestamp *timestamp)
633{
634 if (timestamp == nullptr) {
635 return BAD_VALUE;
636 }
637 AutoMutex lock(mLock);
638 status_t status = mProxy->getTimestamp(timestamp);
639 if (status == OK) {
640 timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
641 timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
Atneya Nair497fff12022-01-18 16:23:04 -0500642 if (!audio_is_linear_pcm(mFormat)) {
643 // Don't do retrograde corrections or server offset if track is
644 // compressed
645 return OK;
646 }
Andy Hung3f0c9022016-01-15 17:49:46 -0800647 // server side frame offset in case AudioRecord has been restored.
648 for (int i = ExtendedTimestamp::LOCATION_SERVER;
649 i < ExtendedTimestamp::LOCATION_MAX; ++i) {
650 if (timestamp->mTimeNs[i] >= 0) {
651 timestamp->mPosition[i] += mFramesReadServerOffset;
652 }
653 }
Andy Hung7efe2b82020-03-31 10:24:42 -0700654
655 bool timestampRetrogradeTimeReported = false;
656 bool timestampRetrogradePositionReported = false;
657 for (int i = 0; i < ExtendedTimestamp::LOCATION_MAX; ++i) {
658 if (timestamp->mTimeNs[i] >= 0 && mPreviousTimestamp.mTimeNs[i] >= 0) {
659 if (timestamp->mTimeNs[i] < mPreviousTimestamp.mTimeNs[i]) {
660 if (!mTimestampRetrogradeTimeReported) {
661 ALOGD("%s: retrograde time adjusting [%d] current:%lld to previous:%lld",
662 __func__, i, (long long)timestamp->mTimeNs[i],
663 (long long)mPreviousTimestamp.mTimeNs[i]);
664 timestampRetrogradeTimeReported = true;
665 }
666 timestamp->mTimeNs[i] = mPreviousTimestamp.mTimeNs[i];
667 }
668 if (timestamp->mPosition[i] < mPreviousTimestamp.mPosition[i]) {
669 if (!mTimestampRetrogradePositionReported) {
670 ALOGD("%s: retrograde position"
671 " adjusting [%d] current:%lld to previous:%lld",
672 __func__, i, (long long)timestamp->mPosition[i],
673 (long long)mPreviousTimestamp.mPosition[i]);
674 timestampRetrogradePositionReported = true;
675 }
676 timestamp->mPosition[i] = mPreviousTimestamp.mPosition[i];
677 }
678 }
679 }
680 mPreviousTimestamp = *timestamp;
681 if (timestampRetrogradeTimeReported) {
682 mTimestampRetrogradeTimeReported = true;
683 }
684 if (timestampRetrogradePositionReported) {
685 mTimestampRetrogradePositionReported = true;
686 }
Andy Hung3f0c9022016-01-15 17:49:46 -0800687 }
688 return status;
689}
690
Paul McLean466dc8e2015-04-17 13:15:36 -0600691// ---- Explicit Routing ---------------------------------------------------
692status_t AudioRecord::setInputDevice(audio_port_handle_t deviceId) {
693 AutoMutex lock(mLock);
Eric Laurent2f2c1982021-06-02 14:03:11 +0200694 ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d",
695 __func__, mPortId, deviceId, mSelectedDeviceId);
Paul McLean466dc8e2015-04-17 13:15:36 -0600696 if (mSelectedDeviceId != deviceId) {
697 mSelectedDeviceId = deviceId;
Eric Laurentfb00fc72017-05-25 18:17:12 -0700698 if (mStatus == NO_ERROR) {
699 // stop capture so that audio policy manager does not reject the new instance start request
700 // as only one capture can be active at a time.
701 if (mAudioRecord != 0 && mActive) {
702 mAudioRecord->stop();
703 }
704 android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
jiabinfec2f932017-10-24 10:10:53 -0700705 mProxy->interrupt();
Eric Laurent296fb132015-05-01 11:38:42 -0700706 }
Paul McLean466dc8e2015-04-17 13:15:36 -0600707 }
708 return NO_ERROR;
709}
710
711audio_port_handle_t AudioRecord::getInputDevice() {
712 AutoMutex lock(mLock);
713 return mSelectedDeviceId;
714}
715
Eric Laurentad2e7b92017-09-14 20:06:42 -0700716// must be called with mLock held
717void AudioRecord::updateRoutedDeviceId_l()
718{
719 // if the record is inactive, do not update actual device as the input stream maybe routed
720 // from a device not relevant to this client because of other active use cases.
721 if (!mActive) {
722 return;
723 }
724 if (mInput != AUDIO_IO_HANDLE_NONE) {
725 audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
726 if (deviceId != AUDIO_PORT_HANDLE_NONE) {
727 mRoutedDeviceId = deviceId;
728 }
729 }
730}
731
Eric Laurent296fb132015-05-01 11:38:42 -0700732audio_port_handle_t AudioRecord::getRoutedDeviceId() {
733 AutoMutex lock(mLock);
Eric Laurentad2e7b92017-09-14 20:06:42 -0700734 updateRoutedDeviceId_l();
735 return mRoutedDeviceId;
Eric Laurent296fb132015-05-01 11:38:42 -0700736}
737
Eric Laurent724a1812017-12-06 16:59:56 -0800738status_t AudioRecord::dump(int fd, const Vector<String16>& args __unused) const
739{
740 String8 result;
741
742 result.append(" AudioRecord::dump\n");
Andy Hung6b1c6122018-09-12 19:09:07 -0700743 result.appendFormat(" id(%d) status(%d), active(%d), session Id(%d)\n",
Eric Laurent973db022018-11-20 14:54:31 -0800744 mPortId, mStatus, mActive, mSessionId);
Eric Laurent724a1812017-12-06 16:59:56 -0800745 result.appendFormat(" flags(%#x), req. flags(%#x), audio source(%d)\n",
746 mFlags, mOrigFlags, mAttributes.source);
747 result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u), sample rate(%u)\n",
748 mFormat, mChannelMask, mChannelCount, mSampleRate);
749 result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
750 mFrameCount, mReqFrameCount);
751 result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u)\n",
752 mNotificationFramesAct, mNotificationFramesReq);
753 result.appendFormat(" input(%d), latency(%u), selected device Id(%d), routed device Id(%d)\n",
754 mInput, mLatency, mSelectedDeviceId, mRoutedDeviceId);
Paul McLean366b6432019-02-25 10:35:51 -0700755 result.appendFormat(" mic direction(%d) mic field dimension(%f)",
756 mSelectedMicDirection, mSelectedMicFieldDimension);
Tomasz Wasilczyk8f36f6e2023-08-15 20:59:35 +0000757 ::write(fd, result.c_str(), result.size());
Eric Laurent724a1812017-12-06 16:59:56 -0800758 return NO_ERROR;
759}
760
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800761// -------------------------------------------------------------------------
Phil Burkadbb75a2017-06-16 12:19:42 -0700762// TODO Move this macro to a common header file for enum to string conversion in audio framework.
763#define MEDIA_CASE_ENUM(name) case name: return #name
764const char * AudioRecord::convertTransferToText(transfer_type transferType) {
765 switch (transferType) {
766 MEDIA_CASE_ENUM(TRANSFER_DEFAULT);
767 MEDIA_CASE_ENUM(TRANSFER_CALLBACK);
768 MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
769 MEDIA_CASE_ENUM(TRANSFER_SYNC);
770 default:
771 return "UNRECOGNIZED";
772 }
773}
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800774
Eric Laurent1703cdf2011-03-07 14:52:59 -0800775// must be called with mLock held
Philip P. Moltmannbda45752020-07-17 16:41:18 -0700776status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch)
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800777{
Andy Hungb68f5eb2019-12-03 16:49:17 -0800778 const int64_t beginNs = systemTime();
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800779 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
Eric Laurentf14db3c2017-12-08 14:20:36 -0800780 IAudioFlinger::CreateRecordInput input;
781 IAudioFlinger::CreateRecordOutput output;
Atneya Nairb249d272021-11-29 18:06:46 -0500782 [[maybe_unused]] audio_session_t originalSessionId;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800783 void *iMemPointer;
784 audio_track_cblk_t* cblk;
785 status_t status;
Eric Laurentd52a28c2020-08-21 17:10:39 -0700786 static const int32_t kMaxCreateAttempts = 3;
787 int32_t remainingAttempts = kMaxCreateAttempts;
Andy Hungb58f2c52022-01-10 00:00:15 -0800788 std::string errorMessage;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800789
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800790 if (audioFlinger == 0) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800791 errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId);
Eric Laurentf14db3c2017-12-08 14:20:36 -0800792 status = NO_INIT;
793 goto exit;
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800794 }
795
Glenn Kasten58883a02016-03-08 15:31:49 -0800796 // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
797 // After fast request is denied, we will request again if IAudioRecord is re-created.
798
Glenn Kasten7fd04222016-02-02 12:38:16 -0800799 // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
800 // we must release it ourselves if anything goes wrong.
801
Glenn Kasten31514272013-08-01 07:24:34 -0700802 // Client can only express a preference for FAST. Server will perform additional tests.
Glenn Kasten7fd04222016-02-02 12:38:16 -0800803 if (mFlags & AUDIO_INPUT_FLAG_FAST) {
804 bool useCaseAllowed =
Phil Burk382d11a2017-05-22 16:07:37 -0700805 // any of these use cases:
Glenn Kastenb7fbf7e2015-03-18 12:57:28 -0700806 // use case 1: callback transfer mode
807 (mTransfer == TRANSFER_CALLBACK) ||
Phil Burk382d11a2017-05-22 16:07:37 -0700808 // use case 2: blocking read mode
809 // The default buffer capacity at 48 kHz is 2048 frames, or ~42.6 ms.
810 // That's enough for double-buffering with our standard 20 ms rule of thumb for
811 // the minimum period of a non-SCHED_FIFO thread.
812 // This is needed so that AAudio apps can do a low latency non-blocking read from a
813 // callback running with SCHED_FIFO.
814 (mTransfer == TRANSFER_SYNC) ||
815 // use case 3: obtain/release mode
Glenn Kasten7fd04222016-02-02 12:38:16 -0800816 (mTransfer == TRANSFER_OBTAIN);
Phil Burkadbb75a2017-06-16 12:19:42 -0700817 if (!useCaseAllowed) {
Phil Burkcc6ed2d2020-05-18 13:06:54 -0700818 ALOGD("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
Eric Laurent973db022018-11-20 14:54:31 -0800819 __func__, mPortId,
Phil Burkadbb75a2017-06-16 12:19:42 -0700820 convertTransferToText(mTransfer));
Glenn Kasten2854e512016-03-11 16:14:06 -0800821 mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
822 AUDIO_INPUT_FLAG_RAW));
Glenn Kasten7fd04222016-02-02 12:38:16 -0800823 }
Glenn Kastenc6ba8232014-02-27 13:34:29 -0800824 }
825
Eric Laurentf14db3c2017-12-08 14:20:36 -0800826 input.attr = mAttributes;
827 input.config.sample_rate = mSampleRate;
828 input.config.channel_mask = mChannelMask;
829 input.config.format = mFormat;
Svet Ganov3e5f14f2021-05-13 22:51:08 +0000830 input.clientInfo.attributionSource = mClientAttributionSource;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800831 input.clientInfo.clientTid = -1;
Eric Laurent0aa3c6e2017-12-08 18:13:22 +0000832 if (mFlags & AUDIO_INPUT_FLAG_FAST) {
833 if (mAudioRecordThread != 0) {
Eric Laurentf14db3c2017-12-08 14:20:36 -0800834 input.clientInfo.clientTid = mAudioRecordThread->getTid();
Eric Laurent0aa3c6e2017-12-08 18:13:22 +0000835 }
836 }
Mikhail Naganov2996f672019-04-18 12:29:59 -0700837 input.riid = mTracker->getRiid();
Eric Laurent0aa3c6e2017-12-08 18:13:22 +0000838
Eric Laurentf14db3c2017-12-08 14:20:36 -0800839 input.flags = mFlags;
840 // The notification frame count is the period between callbacks, as suggested by the client
841 // but moderated by the server. For record, the calculations are done entirely on server side.
842 input.frameCount = mReqFrameCount;
843 input.notificationFrameCount = mNotificationFramesReq;
844 input.selectedDeviceId = mSelectedDeviceId;
845 input.sessionId = mSessionId;
846 originalSessionId = mSessionId;
Eric Laurentec376dc2021-04-08 20:41:22 +0200847 input.maxSharedAudioHistoryMs = mMaxSharedAudioHistoryMs;
Eric Laurent0aa3c6e2017-12-08 18:13:22 +0000848
Eric Laurentd52a28c2020-08-21 17:10:39 -0700849 do {
Ytai Ben-Tsvi4dfeb622020-11-02 12:47:30 -0800850 media::CreateRecordResponse response;
Ytai Ben-Tsvi16d87612020-11-03 16:32:36 -0800851 status = audioFlinger->createRecord(VALUE_OR_FATAL(input.toAidl()), response);
Ytai Ben-Tsvi4dfeb622020-11-02 12:47:30 -0800852 output = VALUE_OR_FATAL(IAudioFlinger::CreateRecordOutput::fromAidl(response));
Eric Laurentd52a28c2020-08-21 17:10:39 -0700853 if (status == NO_ERROR) {
854 break;
855 }
856 if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800857 errorMessage = StringPrintf(
858 "%s(%d): AudioFlinger could not create record track, status: %d",
859 __func__, mPortId, status);
Eric Laurentd52a28c2020-08-21 17:10:39 -0700860 goto exit;
861 }
862 // FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
863 // between audio policy manager and audio flinger during the input stream open sequence
864 // and can be recovered by retrying.
865 // Leave time for race condition to clear before retrying and randomize delay
866 // to reduce the probability of concurrent retries in locked steps.
867 usleep((20 + rand() % 30) * 10000);
868 } while (1);
Marco Nelissen3a34bef2011-08-02 13:33:41 -0700869
Eric Laurentec376dc2021-04-08 20:41:22 +0200870 ALOG_ASSERT(output.audioRecord != 0);
Glenn Kastenc08d20b2014-02-24 15:21:10 -0800871
Glenn Kasten38e905b2014-01-13 10:21:48 -0800872 // AudioFlinger now owns the reference to the I/O handle,
873 // so we are no longer responsible for releasing it.
874
Glenn Kasten2854e512016-03-11 16:14:06 -0800875 mAwaitBoost = false;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800876 if (output.flags & AUDIO_INPUT_FLAG_FAST) {
Andy Hung6b1c6122018-09-12 19:09:07 -0700877 ALOGI("%s(%d): AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu",
Eric Laurent973db022018-11-20 14:54:31 -0800878 __func__, mPortId,
Eric Laurentf14db3c2017-12-08 14:20:36 -0800879 mReqFrameCount, output.frameCount);
880 mAwaitBoost = true;
Glenn Kasten2854e512016-03-11 16:14:06 -0800881 }
Eric Laurentf14db3c2017-12-08 14:20:36 -0800882 mFlags = output.flags;
883 mRoutedDeviceId = output.selectedDeviceId;
884 mSessionId = output.sessionId;
885 mSampleRate = output.sampleRate;
jiabinb00edc32021-08-16 16:27:54 +0000886 mServerConfig = output.serverConfig;
887 mServerFrameSize = audio_bytes_per_frame(
888 audio_channel_count_from_in_mask(mServerConfig.channel_mask), mServerConfig.format);
889 mServerSampleSize = audio_bytes_per_sample(mServerConfig.format);
Robert Wu310037a2022-09-06 21:48:18 +0000890 mHalSampleRate = output.halConfig.sample_rate;
891 mHalChannelCount = audio_channel_count_from_in_mask(output.halConfig.channel_mask);
892 mHalFormat = output.halConfig.format;
Glenn Kasten2854e512016-03-11 16:14:06 -0800893
Eric Laurentf14db3c2017-12-08 14:20:36 -0800894 if (output.cblk == 0) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800895 errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
Eric Laurentf14db3c2017-12-08 14:20:36 -0800896 status = NO_INIT;
897 goto exit;
Eric Laurent34f1d8e2009-11-04 08:27:26 -0800898 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700899 // TODO: Using unsecurePointer() has some associated security pitfalls
900 // (see declaration for details).
901 // Either document why it is safe in this case or address the
902 // issue (e.g. by copying).
903 iMemPointer = output.cblk ->unsecurePointer();
Glenn Kastene93cf2c2013-09-24 11:52:37 -0700904 if (iMemPointer == NULL) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800905 errorMessage = StringPrintf(
906 "%s(%d): Could not get control block pointer", __func__, mPortId);
Eric Laurentf14db3c2017-12-08 14:20:36 -0800907 status = NO_INIT;
908 goto exit;
Glenn Kastene93cf2c2013-09-24 11:52:37 -0700909 }
Eric Laurentf14db3c2017-12-08 14:20:36 -0800910 cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
Glenn Kastend776ac62014-05-07 09:16:09 -0700911
912 // Starting address of buffers in shared memory.
913 // The buffers are either immediately after the control block,
914 // or in a separate area at discretion of server.
915 void *buffers;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800916 if (output.buffers == 0) {
Glenn Kastend776ac62014-05-07 09:16:09 -0700917 buffers = cblk + 1;
918 } else {
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700919 // TODO: Using unsecurePointer() has some associated security pitfalls
920 // (see declaration for details).
921 // Either document why it is safe in this case or address the
922 // issue (e.g. by copying).
923 buffers = output.buffers->unsecurePointer();
Glenn Kastend776ac62014-05-07 09:16:09 -0700924 if (buffers == NULL) {
Andy Hungb58f2c52022-01-10 00:00:15 -0800925 errorMessage = StringPrintf(
926 "%s(%d): Could not get buffer pointer", __func__, mPortId);
Eric Laurentf14db3c2017-12-08 14:20:36 -0800927 status = NO_INIT;
928 goto exit;
Glenn Kastend776ac62014-05-07 09:16:09 -0700929 }
930 }
931
Glenn Kasten089e8722014-02-24 15:12:48 -0800932 // invariant that mAudioRecord != 0 is true only after set() returns successfully
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800933 if (mAudioRecord != 0) {
Marco Nelissenf8880202014-11-14 07:58:25 -0800934 IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800935 mDeathNotifier.clear();
936 }
Ytai Ben-Tsvi16d87612020-11-03 16:32:36 -0800937 mAudioRecord = output.audioRecord;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800938 mCblkMemory = output.cblk;
939 mBufferMemory = output.buffers;
Eric Laurent3bcffa12014-06-12 18:38:45 -0700940 IPCThreadState::self()->flushCommands();
941
Glenn Kastenb36a7a62012-11-12 15:46:10 -0800942 mCblk = cblk;
Eric Laurentf14db3c2017-12-08 14:20:36 -0800943 // note that output.frameCount is the (possibly revised) value of mReqFrameCount
944 if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) {
Andy Hung6b1c6122018-09-12 19:09:07 -0700945 ALOGW("%s(%d): Requested frameCount %zu but received frameCount %zu",
Eric Laurent09f1ed22019-04-24 17:45:17 -0700946 __func__, output.portId,
Eric Laurentf14db3c2017-12-08 14:20:36 -0800947 mReqFrameCount, output.frameCount);
Glenn Kasten74935e42013-12-19 08:56:45 -0800948 }
Glenn Kasten74935e42013-12-19 08:56:45 -0800949
Glenn Kasten7fd04222016-02-02 12:38:16 -0800950 // Make sure that application is notified with sufficient margin before overrun.
951 // The computation is done on server side.
Eric Laurentf14db3c2017-12-08 14:20:36 -0800952 if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) {
Andy Hung6b1c6122018-09-12 19:09:07 -0700953 ALOGW("%s(%d): Server adjusted notificationFrames from %u to %zu for frameCount %zu",
Eric Laurent09f1ed22019-04-24 17:45:17 -0700954 __func__, output.portId,
Eric Laurentf14db3c2017-12-08 14:20:36 -0800955 mNotificationFramesReq, output.notificationFrameCount, output.frameCount);
Glenn Kasten74105912014-07-03 12:28:53 -0700956 }
Eric Laurentf14db3c2017-12-08 14:20:36 -0800957 mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
Atneya Nair2eedae32022-02-14 16:42:23 -0500958 if (mServerConfig.format != mFormat && mCallback != nullptr) {
jiabinb00edc32021-08-16 16:27:54 +0000959 mFormatConversionBufRaw = std::make_unique<uint8_t[]>(mNotificationFramesAct * mFrameSize);
960 mFormatConversionBuffer.raw = mFormatConversionBufRaw.get();
961 }
Eric Laurentad2e7b92017-09-14 20:06:42 -0700962
963 //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
Eric Laurent09f1ed22019-04-24 17:45:17 -0700964 if (mDeviceCallback != 0) {
Eric Laurentad2e7b92017-09-14 20:06:42 -0700965 if (mInput != AUDIO_IO_HANDLE_NONE) {
Eric Laurent09f1ed22019-04-24 17:45:17 -0700966 AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
Eric Laurentad2e7b92017-09-14 20:06:42 -0700967 }
Eric Laurent09f1ed22019-04-24 17:45:17 -0700968 AudioSystem::addAudioDeviceCallback(this, output.inputId, output.portId);
Eric Laurentad2e7b92017-09-14 20:06:42 -0700969 }
970
Eric Laurentec376dc2021-04-08 20:41:22 +0200971 if (!mSharedAudioPackageName.empty()) {
972 mAudioRecord->shareAudioHistory(mSharedAudioPackageName, mSharedAudioStartMs);
973 }
974
Eric Laurent09f1ed22019-04-24 17:45:17 -0700975 mPortId = output.portId;
Glenn Kasten045e7392014-02-25 15:15:53 -0800976 // We retain a copy of the I/O handle, but don't own the reference
Eric Laurentf14db3c2017-12-08 14:20:36 -0800977 mInput = output.inputId;
Glenn Kastena5ed48d2014-02-25 15:13:37 -0800978 mRefreshRemaining = true;
979
Eric Laurentf14db3c2017-12-08 14:20:36 -0800980 mFrameCount = output.frameCount;
Glenn Kasten11cb1752014-02-24 15:16:59 -0800981 // If IAudioRecord is re-created, don't let the requested frameCount
982 // decrease. This can confuse clients that cache frameCount().
Eric Laurentf14db3c2017-12-08 14:20:36 -0800983 if (mFrameCount > mReqFrameCount) {
984 mReqFrameCount = mFrameCount;
Glenn Kasten11cb1752014-02-24 15:16:59 -0800985 }
Glenn Kastenb3b2e232014-02-05 11:10:26 -0800986
Glenn Kastene3aa6592012-12-04 12:22:46 -0800987 // update proxy
jiabinb00edc32021-08-16 16:27:54 +0000988 mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mServerFrameSize);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800989 mProxy->setEpoch(epoch);
Glenn Kasten7cd9cf72013-08-01 07:22:02 -0700990 mProxy->setMinimum(mNotificationFramesAct);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800991
992 mDeathNotifier = new DeathNotifier(this);
Marco Nelissenf8880202014-11-14 07:58:25 -0800993 IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
Glenn Kastene3aa6592012-12-04 12:22:46 -0800994
Andy Hungb68f5eb2019-12-03 16:49:17 -0800995 mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(mPortId);
996 mediametrics::LogItem(mMetricsId)
997 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
Andy Hungea840382020-05-05 21:50:17 -0700998 .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
Andy Hungb68f5eb2019-12-03 16:49:17 -0800999 // the following are immutable (at least until restore)
Andy Hunga629bd12020-06-05 16:03:53 -07001000 .set(AMEDIAMETRICS_PROP_FLAGS, toString(mFlags).c_str())
1001 .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
Andy Hungb68f5eb2019-12-03 16:49:17 -08001002 .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
1003 .set(AMEDIAMETRICS_PROP_TRACKID, mPortId)
Andy Hung1a9c21b2021-02-25 20:43:18 -08001004 .set(AMEDIAMETRICS_PROP_LOGSESSIONID, mLogSessionId)
Andy Hungb68f5eb2019-12-03 16:49:17 -08001005 .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
1006 .set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.inputId)
1007 .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
1008 .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)mRoutedDeviceId)
1009 .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
1010 .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
1011 .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
1012 .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
1013 // the following are NOT immutable
1014 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
Andy Hung73dc2f92021-12-07 21:50:04 -08001015 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
Andy Hungb68f5eb2019-12-03 16:49:17 -08001016 .set(AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION, (int32_t)mSelectedMicDirection)
1017 .set(AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION, (double)mSelectedMicFieldDimension)
1018 .record();
1019
Eric Laurentf14db3c2017-12-08 14:20:36 -08001020exit:
Andy Hungb58f2c52022-01-10 00:00:15 -08001021 if (status != NO_ERROR) {
1022 ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
1023 reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
1024 }
1025
Eric Laurentf14db3c2017-12-08 14:20:36 -08001026 mStatus = status;
1027 // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
Glenn Kasten38e905b2014-01-13 10:21:48 -08001028 return status;
Eric Laurent34f1d8e2009-11-04 08:27:26 -08001029}
1030
Andy Hungb58f2c52022-01-10 00:00:15 -08001031// Report error associated with the event and some configuration details.
1032void AudioRecord::reportError(status_t status, const char *event, const char *message) const
1033{
1034 if (status == NO_ERROR) return;
1035 // We report error on the native side because some callers do not come
1036 // from Java.
1037 // Ensure these variables are initialized in set().
1038 mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR)
1039 .set(AMEDIAMETRICS_PROP_EVENT, event)
1040 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
1041 .set(AMEDIAMETRICS_PROP_STATUSMESSAGE, message)
1042 .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
1043 .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
1044 .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
1045 .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
1046 .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
1047 .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
1048 .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
1049 .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
1050 .record();
1051}
1052
Glenn Kasten551b5352015-03-20 11:30:28 -07001053status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001054{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001055 if (audioBuffer == NULL) {
Glenn Kasten551b5352015-03-20 11:30:28 -07001056 if (nonContig != NULL) {
1057 *nonContig = 0;
1058 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001059 return BAD_VALUE;
1060 }
1061 if (mTransfer != TRANSFER_OBTAIN) {
1062 audioBuffer->frameCount = 0;
Atneya Nair03079272022-01-18 17:03:14 -05001063 audioBuffer->mSize = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001064 audioBuffer->raw = NULL;
Glenn Kasten551b5352015-03-20 11:30:28 -07001065 if (nonContig != NULL) {
1066 *nonContig = 0;
1067 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001068 return INVALID_OPERATION;
1069 }
Glenn Kastene3aa6592012-12-04 12:22:46 -08001070
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001071 const struct timespec *requested;
Eric Laurentdf576992014-01-27 18:13:39 -08001072 struct timespec timeout;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001073 if (waitCount == -1) {
1074 requested = &ClientProxy::kForever;
1075 } else if (waitCount == 0) {
1076 requested = &ClientProxy::kNonBlocking;
1077 } else if (waitCount > 0) {
Chih-Hung Hsiehbca74292018-08-10 16:06:07 -07001078 time_t ms = WAIT_PERIOD_MS * (time_t) waitCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001079 timeout.tv_sec = ms / 1000;
Chih-Hung Hsiehbca74292018-08-10 16:06:07 -07001080 timeout.tv_nsec = (long) (ms % 1000) * 1000000;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001081 requested = &timeout;
1082 } else {
Eric Laurent973db022018-11-20 14:54:31 -08001083 ALOGE("%s(%d): invalid waitCount %d", __func__, mPortId, waitCount);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001084 requested = NULL;
1085 }
Glenn Kasten551b5352015-03-20 11:30:28 -07001086 return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001087}
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001088
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001089status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
1090 struct timespec *elapsed, size_t *nonContig)
1091{
1092 // previous and new IAudioRecord sequence numbers are used to detect track re-creation
1093 uint32_t oldSequence = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001094
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001095 Proxy::Buffer buffer;
1096 status_t status = NO_ERROR;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001097
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001098 static const int32_t kMaxTries = 5;
1099 int32_t tryCounter = kMaxTries;
1100
1101 do {
1102 // obtainBuffer() is called with mutex unlocked, so keep extra references to these fields to
1103 // keep them from going away if another thread re-creates the track during obtainBuffer()
1104 sp<AudioRecordClientProxy> proxy;
1105 sp<IMemory> iMem;
Glenn Kastend776ac62014-05-07 09:16:09 -07001106 sp<IMemory> bufferMem;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001107 {
1108 // start of lock scope
1109 AutoMutex lock(mLock);
1110
Glenn Kastenba703d62019-12-13 11:13:42 -08001111 uint32_t newSequence = mSequence;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001112 // did previous obtainBuffer() fail due to media server death or voluntary invalidation?
1113 if (status == DEAD_OBJECT) {
1114 // re-create track, unless someone else has already done so
1115 if (newSequence == oldSequence) {
Atneya Nair497fff12022-01-18 16:23:04 -05001116 if (!audio_is_linear_pcm(mFormat)) {
1117 // If compressed capture, don't attempt to restore the track.
1118 // Return a DEAD_OBJECT error and let the caller recreate.
1119 tryCounter = 0;
1120 } else {
1121 status = restoreRecord_l("obtainBuffer");
1122 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001123 if (status != NO_ERROR) {
Glenn Kastend8a9d022014-01-14 15:46:38 -08001124 buffer.mFrameCount = 0;
1125 buffer.mRaw = NULL;
1126 buffer.mNonContig = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001127 break;
Eric Laurent1703cdf2011-03-07 14:52:59 -08001128 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001129 }
1130 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001131 oldSequence = newSequence;
1132
1133 // Keep the extra references
1134 proxy = mProxy;
1135 iMem = mCblkMemory;
Glenn Kastend776ac62014-05-07 09:16:09 -07001136 bufferMem = mBufferMemory;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001137
1138 // Non-blocking if track is stopped
1139 if (!mActive) {
1140 requested = &ClientProxy::kNonBlocking;
1141 }
1142
1143 } // end of lock scope
1144
1145 buffer.mFrameCount = audioBuffer->frameCount;
1146 // FIXME starts the requested timeout and elapsed over from scratch
1147 status = proxy->obtainBuffer(&buffer, requested, elapsed);
1148
1149 } while ((status == DEAD_OBJECT) && (tryCounter-- > 0));
1150
1151 audioBuffer->frameCount = buffer.mFrameCount;
Atneya Nair03079272022-01-18 17:03:14 -05001152 audioBuffer->mSize = buffer.mFrameCount * mServerFrameSize;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001153 audioBuffer->raw = buffer.mRaw;
Glenn Kastenba703d62019-12-13 11:13:42 -08001154 audioBuffer->sequence = oldSequence;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001155 if (nonContig != NULL) {
1156 *nonContig = buffer.mNonContig;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001157 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001158 return status;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001159}
1160
Glenn Kasten5014c942015-03-20 10:06:37 -07001161void AudioRecord::releaseBuffer(const Buffer* audioBuffer)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001162{
Glenn Kasten17ea1352015-03-20 08:54:17 -07001163 // FIXME add error checking on mode, by adding an internal version
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001164
jiabinb00edc32021-08-16 16:27:54 +00001165 size_t stepCount = audioBuffer->frameCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001166 if (stepCount == 0) {
1167 return;
1168 }
1169
1170 Proxy::Buffer buffer;
1171 buffer.mFrameCount = stepCount;
1172 buffer.mRaw = audioBuffer->raw;
Glenn Kastene3aa6592012-12-04 12:22:46 -08001173
Eric Laurent1703cdf2011-03-07 14:52:59 -08001174 AutoMutex lock(mLock);
Glenn Kastenba703d62019-12-13 11:13:42 -08001175 if (audioBuffer->sequence != mSequence) {
1176 // This Buffer came from a different IAudioRecord instance, so ignore the releaseBuffer
1177 ALOGD("%s is no-op due to IAudioRecord sequence mismatch %u != %u",
1178 __func__, audioBuffer->sequence, mSequence);
1179 return;
1180 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001181 mInOverrun = false;
1182 mProxy->releaseBuffer(&buffer);
1183
1184 // the server does not automatically disable recorder on overrun, so no need to restart
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001185}
1186
Glenn Kasten32860f72015-03-20 08:55:18 -07001187audio_io_handle_t AudioRecord::getInputPrivate() const
Eric Laurent6100d2d2009-11-19 09:00:56 -08001188{
Eric Laurent1703cdf2011-03-07 14:52:59 -08001189 AutoMutex lock(mLock);
Eric Laurentd1a243e2011-07-26 20:32:28 -07001190 return mInput;
Eric Laurent1703cdf2011-03-07 14:52:59 -08001191}
1192
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001193// -------------------------------------------------------------------------
1194
Glenn Kasten3622cdf2015-03-20 10:58:21 -07001195ssize_t AudioRecord::read(void* buffer, size_t userSize, bool blocking)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001196{
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001197 if (mTransfer != TRANSFER_SYNC) {
1198 return INVALID_OPERATION;
1199 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001200
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001201 if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
Jiabin Huangcec62a72020-07-28 22:33:43 +00001202 // Validation. user is most-likely passing an error code, and it would
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001203 // make the return value ambiguous (actualSize vs error).
Andy Hung6b1c6122018-09-12 19:09:07 -07001204 ALOGE("%s(%d) (buffer=%p, size=%zu (%zu)",
Eric Laurent973db022018-11-20 14:54:31 -08001205 __func__, mPortId, buffer, userSize, userSize);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001206 return BAD_VALUE;
1207 }
1208
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001209 ssize_t read = 0;
1210 Buffer audioBuffer;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001211
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001212 while (userSize >= mFrameSize) {
1213 audioBuffer.frameCount = userSize / mFrameSize;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001214
Glenn Kasten3622cdf2015-03-20 10:58:21 -07001215 status_t err = obtainBuffer(&audioBuffer,
1216 blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001217 if (err < 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001218 if (read > 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001219 break;
Glenn Kastend65d73c2012-06-22 17:21:07 -07001220 }
Glenn Kasten0a2f1512016-07-22 08:06:37 -07001221 if (err == TIMED_OUT || err == -EINTR) {
1222 err = WOULD_BLOCK;
1223 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001224 return ssize_t(err);
1225 }
1226
jiabinb00edc32021-08-16 16:27:54 +00001227 size_t bytesRead = audioBuffer.frameCount * mFrameSize;
Dean Wheatley10587022023-11-02 11:38:43 +11001228 if (audio_is_linear_pcm(mFormat)) {
1229 memcpy_by_audio_format(buffer, mFormat, audioBuffer.raw, mServerConfig.format,
1230 audioBuffer.mSize / mServerSampleSize);
1231 } else {
1232 memcpy(buffer, audioBuffer.raw, audioBuffer.mSize);
1233 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001234 buffer = ((char *) buffer) + bytesRead;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001235 userSize -= bytesRead;
1236 read += bytesRead;
1237
1238 releaseBuffer(&audioBuffer);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001239 }
Andy Hung3f0c9022016-01-15 17:49:46 -08001240 if (read > 0) {
1241 mFramesRead += read / mFrameSize;
1242 // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
1243 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001244 return read;
1245}
1246
1247// -------------------------------------------------------------------------
1248
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08001249nsecs_t AudioRecord::processAudioBuffer()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001250{
Eric Laurent1703cdf2011-03-07 14:52:59 -08001251 mLock.lock();
Atneya Nairb249d272021-11-29 18:06:46 -05001252 const sp<IAudioRecordCallback> callback = mCallback.promote();
1253 if (!callback) {
1254 mCallback = nullptr;
Atneya Naire260f5a2022-05-03 17:02:20 -04001255 mLock.unlock();
Atneya Nairb249d272021-11-29 18:06:46 -05001256 return NS_NEVER;
1257 }
Glenn Kasten28f13512013-07-31 12:27:26 -07001258 if (mAwaitBoost) {
1259 mAwaitBoost = false;
1260 mLock.unlock();
1261 static const int32_t kMaxTries = 5;
1262 int32_t tryCounter = kMaxTries;
1263 uint32_t pollUs = 10000;
1264 do {
Glenn Kasten8255ba72016-08-23 13:54:23 -07001265 int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
Glenn Kasten28f13512013-07-31 12:27:26 -07001266 if (policy == SCHED_FIFO || policy == SCHED_RR) {
1267 break;
1268 }
1269 usleep(pollUs);
1270 pollUs <<= 1;
1271 } while (tryCounter-- > 0);
1272 if (tryCounter < 0) {
Eric Laurent973db022018-11-20 14:54:31 -08001273 ALOGE("%s(%d): did not receive expected priority boost on time", __func__, mPortId);
Glenn Kasten28f13512013-07-31 12:27:26 -07001274 }
1275 // Run again immediately
1276 return 0;
1277 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001278
1279 // Can only reference mCblk while locked
Glenn Kasten96f60d82013-07-12 10:21:18 -07001280 int32_t flags = android_atomic_and(~CBLK_OVERRUN, &mCblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001281
1282 // Check for track invalidation
1283 if (flags & CBLK_INVALID) {
1284 (void) restoreRecord_l("processAudioBuffer");
1285 mLock.unlock();
1286 // Run again immediately, but with a new IAudioRecord
1287 return 0;
Glenn Kasten955e7812012-02-21 10:32:45 -08001288 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001289
1290 bool active = mActive;
1291
1292 // Manage overrun callback, must be done under lock to avoid race with releaseBuffer()
1293 bool newOverrun = false;
1294 if (flags & CBLK_OVERRUN) {
1295 if (!mInOverrun) {
1296 mInOverrun = true;
1297 newOverrun = true;
1298 }
1299 }
1300
1301 // Get current position of server
Andy Hung90e8a972015-11-09 16:42:40 -08001302 Modulo<uint32_t> position(mProxy->getPosition());
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001303
1304 // Manage marker callback
1305 bool markerReached = false;
Andy Hung90e8a972015-11-09 16:42:40 -08001306 Modulo<uint32_t> markerPosition(mMarkerPosition);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001307 // FIXME fails for wraparound, need 64 bits
Andy Hung90e8a972015-11-09 16:42:40 -08001308 if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001309 mMarkerReached = markerReached = true;
1310 }
1311
1312 // Determine the number of new position callback(s) that will be needed, while locked
1313 size_t newPosCount = 0;
Andy Hung90e8a972015-11-09 16:42:40 -08001314 Modulo<uint32_t> newPosition(mNewPosition);
Glenn Kasten955e7812012-02-21 10:32:45 -08001315 uint32_t updatePeriod = mUpdatePeriod;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001316 // FIXME fails for wraparound, need 64 bits
1317 if (updatePeriod > 0 && position >= newPosition) {
Andy Hung90e8a972015-11-09 16:42:40 -08001318 newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001319 mNewPosition += updatePeriod * newPosCount;
1320 }
1321
1322 // Cache other fields that will be needed soon
Glenn Kasten838b3d82014-02-27 15:30:41 -08001323 uint32_t notificationFrames = mNotificationFramesAct;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001324 if (mRefreshRemaining) {
1325 mRefreshRemaining = false;
1326 mRemainingFrames = notificationFrames;
1327 mRetryOnPartialBuffer = false;
1328 }
1329 size_t misalignment = mProxy->getMisalignment();
Glenn Kasten8ff50e72014-01-14 15:44:30 -08001330 uint32_t sequence = mSequence;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001331
1332 // These fields don't need to be cached, because they are assigned only by set():
Atneya Nairb249d272021-11-29 18:06:46 -05001333 // mTransfer, mCallback, mUserData, mSampleRate, mFrameSize
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001334
Eric Laurent1703cdf2011-03-07 14:52:59 -08001335 mLock.unlock();
1336
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001337 // perform callbacks while unlocked
1338 if (newOverrun) {
Atneya Nairb249d272021-11-29 18:06:46 -05001339 callback->onOverrun();
1340
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001341 }
1342 if (markerReached) {
Atneya Nairb249d272021-11-29 18:06:46 -05001343 callback->onMarker(markerPosition.value());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001344 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001345 while (newPosCount > 0) {
Atneya Nairb249d272021-11-29 18:06:46 -05001346 callback->onNewPos(newPosition.value());
Glenn Kasten955e7812012-02-21 10:32:45 -08001347 newPosition += updatePeriod;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001348 newPosCount--;
1349 }
1350 if (mObservedSequence != sequence) {
1351 mObservedSequence = sequence;
Atneya Nairb249d272021-11-29 18:06:46 -05001352 callback->onNewIAudioRecord();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001353 }
1354
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001355 // if inactive, then don't run me again until re-started
1356 if (!active) {
1357 return NS_INACTIVE;
1358 }
1359
1360 // Compute the estimated time until the next timed event (position, markers)
1361 uint32_t minFrames = ~0;
1362 if (!markerReached && position < markerPosition) {
Andy Hung90e8a972015-11-09 16:42:40 -08001363 minFrames = (markerPosition - position).value();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001364 }
Andy Hungfb7df2c2015-03-13 15:55:18 -07001365 if (updatePeriod > 0) {
Andy Hung90e8a972015-11-09 16:42:40 -08001366 uint32_t remaining = (newPosition - position).value();
Andy Hungfb7df2c2015-03-13 15:55:18 -07001367 if (remaining < minFrames) {
1368 minFrames = remaining;
1369 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001370 }
1371
1372 // If > 0, poll periodically to recover from a stuck server. A good value is 2.
1373 static const uint32_t kPoll = 0;
1374 if (kPoll > 0 && mTransfer == TRANSFER_CALLBACK && kPoll * notificationFrames < minFrames) {
1375 minFrames = kPoll * notificationFrames;
1376 }
1377
1378 // Convert frame units to time units
1379 nsecs_t ns = NS_WHENEVER;
1380 if (minFrames != (uint32_t) ~0) {
1381 // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
1382 static const nsecs_t kFudgeNs = 10000000LL; // 10 ms
1383 ns = ((minFrames * 1000000000LL) / mSampleRate) + kFudgeNs;
1384 }
1385
1386 // If not supplying data by EVENT_MORE_DATA, then we're done
1387 if (mTransfer != TRANSFER_CALLBACK) {
1388 return ns;
1389 }
1390
1391 struct timespec timeout;
1392 const struct timespec *requested = &ClientProxy::kForever;
1393 if (ns != NS_WHENEVER) {
1394 timeout.tv_sec = ns / 1000000000LL;
1395 timeout.tv_nsec = ns % 1000000000LL;
Andy Hung6b1c6122018-09-12 19:09:07 -07001396 ALOGV("%s(%d): timeout %ld.%03d",
Eric Laurent973db022018-11-20 14:54:31 -08001397 __func__, mPortId, timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001398 requested = &timeout;
1399 }
1400
Andy Hung3f0c9022016-01-15 17:49:46 -08001401 size_t readFrames = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001402 while (mRemainingFrames > 0) {
1403
1404 Buffer audioBuffer;
1405 audioBuffer.frameCount = mRemainingFrames;
1406 size_t nonContig;
1407 status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
1408 LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
Andy Hung6b1c6122018-09-12 19:09:07 -07001409 "%s(%d): obtainBuffer() err=%d frameCount=%zu",
Eric Laurent973db022018-11-20 14:54:31 -08001410 __func__, mPortId, err, audioBuffer.frameCount);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001411 requested = &ClientProxy::kNonBlocking;
1412 size_t avail = audioBuffer.frameCount + nonContig;
Andy Hung6b1c6122018-09-12 19:09:07 -07001413 ALOGV("%s(%d): obtainBuffer(%u) returned %zu = %zu + %zu err %d",
Eric Laurent973db022018-11-20 14:54:31 -08001414 __func__, mPortId, mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001415 if (err != NO_ERROR) {
1416 if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
1417 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001418 }
Andy Hung6b1c6122018-09-12 19:09:07 -07001419 ALOGE("%s(%d): Error %d obtaining an audio buffer, giving up.",
Eric Laurent973db022018-11-20 14:54:31 -08001420 __func__, mPortId, err);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001421 return NS_NEVER;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001422 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001423
1424 if (mRetryOnPartialBuffer) {
1425 mRetryOnPartialBuffer = false;
1426 if (avail < mRemainingFrames) {
1427 int64_t myns = ((mRemainingFrames - avail) *
1428 1100000000LL) / mSampleRate;
1429 if (ns < 0 || myns < ns) {
1430 ns = myns;
1431 }
1432 return ns;
1433 }
1434 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001435
jiabinb00edc32021-08-16 16:27:54 +00001436 Buffer* buffer = &audioBuffer;
1437 if (mServerConfig.format != mFormat) {
1438 buffer = &mFormatConversionBuffer;
1439 buffer->frameCount = audioBuffer.frameCount;
Atneya Nair03079272022-01-18 17:03:14 -05001440 buffer->mSize = buffer->frameCount * mFrameSize;
jiabinb00edc32021-08-16 16:27:54 +00001441 buffer->sequence = audioBuffer.sequence;
1442 memcpy_by_audio_format(buffer->raw, mFormat, audioBuffer.raw,
Atneya Nair03079272022-01-18 17:03:14 -05001443 mServerConfig.format, audioBuffer.size() / mServerSampleSize);
jiabinb00edc32021-08-16 16:27:54 +00001444 }
1445
Atneya Nair03079272022-01-18 17:03:14 -05001446 const size_t reqSize = buffer->size();
Atneya Nairb249d272021-11-29 18:06:46 -05001447 const size_t readSize = callback->onMoreData(*buffer);
Atneya Nair03079272022-01-18 17:03:14 -05001448 buffer->mSize = readSize;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001449
Jiabin Huangcec62a72020-07-28 22:33:43 +00001450 // Validate on returned size
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001451 if (ssize_t(readSize) < 0 || readSize > reqSize) {
Andy Hung6b1c6122018-09-12 19:09:07 -07001452 ALOGE("%s(%d): EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
Eric Laurent973db022018-11-20 14:54:31 -08001453 __func__, mPortId, reqSize, ssize_t(readSize));
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001454 return NS_NEVER;
Eric Laurentcd6725a2009-03-24 21:23:54 -07001455 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001456
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001457 if (readSize == 0) {
1458 // The callback is done consuming buffers
1459 // Keep this thread going to handle timed events and
1460 // still try to provide more data in intervals of WAIT_PERIOD_MS
1461 // but don't just loop and block the CPU, so wait
1462 return WAIT_PERIOD_MS * 1000000LL;
1463 }
1464
1465 size_t releasedFrames = readSize / mFrameSize;
1466 audioBuffer.frameCount = releasedFrames;
1467 mRemainingFrames -= releasedFrames;
1468 if (misalignment >= releasedFrames) {
1469 misalignment -= releasedFrames;
1470 } else {
1471 misalignment = 0;
1472 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001473
1474 releaseBuffer(&audioBuffer);
Andy Hung3f0c9022016-01-15 17:49:46 -08001475 readFrames += releasedFrames;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001476
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001477 // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
1478 // if callback doesn't like to accept the full chunk
1479 if (readSize < reqSize) {
1480 continue;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001481 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001482
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001483 // There could be enough non-contiguous frames available to satisfy the remaining request
1484 if (mRemainingFrames <= nonContig) {
1485 continue;
1486 }
1487
1488#if 0
1489 // This heuristic tries to collapse a series of EVENT_MORE_DATA that would total to a
1490 // sum <= notificationFrames. It replaces that series by at most two EVENT_MORE_DATA
1491 // that total to a sum == notificationFrames.
1492 if (0 < misalignment && misalignment <= mRemainingFrames) {
1493 mRemainingFrames = misalignment;
1494 return (mRemainingFrames * 1100000000LL) / mSampleRate;
1495 }
1496#endif
1497
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001498 }
Andy Hung3f0c9022016-01-15 17:49:46 -08001499 if (readFrames > 0) {
1500 AutoMutex lock(mLock);
1501 mFramesRead += readFrames;
1502 // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
1503 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001504 mRemainingFrames = notificationFrames;
1505 mRetryOnPartialBuffer = true;
1506
1507 // A lot has transpired since ns was calculated, so run again immediately and re-calculate
1508 return 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001509}
1510
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001511status_t AudioRecord::restoreRecord_l(const char *from)
Eric Laurent1703cdf2011-03-07 14:52:59 -08001512{
Andy Hungb68f5eb2019-12-03 16:49:17 -08001513 status_t result = NO_ERROR; // logged: make sure to set this before returning.
1514 const int64_t beginNs = systemTime();
Andy Hung06a730b2020-04-09 13:28:31 -07001515 mediametrics::Defer defer([&] {
Andy Hungb68f5eb2019-12-03 16:49:17 -08001516 mediametrics::LogItem(mMetricsId)
1517 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
Andy Hungea840382020-05-05 21:50:17 -07001518 .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
Andy Hungb68f5eb2019-12-03 16:49:17 -08001519 .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
1520 .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
1521 .set(AMEDIAMETRICS_PROP_WHERE, from)
1522 .record(); });
1523
Eric Laurent973db022018-11-20 14:54:31 -08001524 ALOGW("%s(%d): dead IAudioRecord, creating a new one from %s()", __func__, mPortId, from);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001525 ++mSequence;
Eric Laurent1703cdf2011-03-07 14:52:59 -08001526
Paul McLeanb8ca98e2018-04-16 12:47:19 -07001527 const int INITIAL_RETRIES = 3;
1528 int retries = INITIAL_RETRIES;
1529retry:
1530 if (retries < INITIAL_RETRIES) {
1531 // refresh the audio configuration cache in this process to make sure we get new
1532 // input parameters and new IAudioRecord in createRecord_l()
1533 AudioSystem::clearAudioConfigCache();
1534 }
Glenn Kasten58883a02016-03-08 15:31:49 -08001535 mFlags = mOrigFlags;
1536
Eric Laurentf14db3c2017-12-08 14:20:36 -08001537 // if the new IAudioRecord is created, createRecord_l() will modify the
Glenn Kastend776ac62014-05-07 09:16:09 -07001538 // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
Glenn Kastenb36a7a62012-11-12 15:46:10 -08001539 // It will also delete the strong references on previous IAudioRecord and IMemory
Andy Hung90e8a972015-11-09 16:42:40 -08001540 Modulo<uint32_t> position(mProxy->getPosition());
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001541 mNewPosition = position + mUpdatePeriod;
Philip P. Moltmannbda45752020-07-17 16:41:18 -07001542 result = createRecord_l(position);
Paul McLeanb8ca98e2018-04-16 12:47:19 -07001543
Eric Laurent6ec546d2018-10-10 16:52:14 -07001544 if (result == NO_ERROR) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001545 if (mActive) {
1546 // callback thread or sync event hasn't changed
1547 // FIXME this fails if we have a new AudioFlinger instance
Andy Hung1131b6e2020-12-08 20:47:45 -08001548 result = statusTFromBinderStatus(mAudioRecord->start(
1549 AudioSystem::SYNC_EVENT_SAME, AUDIO_SESSION_NONE));
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001550 }
Andy Hung3f0c9022016-01-15 17:49:46 -08001551 mFramesReadServerOffset = mFramesRead; // server resets to zero so we need an offset.
Eric Laurent1703cdf2011-03-07 14:52:59 -08001552 }
Paul McLeanb8ca98e2018-04-16 12:47:19 -07001553
1554 if (result != NO_ERROR) {
Eric Laurent973db022018-11-20 14:54:31 -08001555 ALOGW("%s(%d): failed status %d, retries %d", __func__, mPortId, result, retries);
Paul McLeanb8ca98e2018-04-16 12:47:19 -07001556 if (--retries > 0) {
Eric Laurent6ec546d2018-10-10 16:52:14 -07001557 // leave time for an eventual race condition to clear before retrying
1558 usleep(500000);
Paul McLeanb8ca98e2018-04-16 12:47:19 -07001559 goto retry;
1560 }
Eric Laurent6ec546d2018-10-10 16:52:14 -07001561 // if no retries left, set invalid bit to force restoring at next occasion
1562 // and avoid inconsistent active state on client and server sides
1563 if (mCblk != nullptr) {
1564 android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
1565 }
Glenn Kastenb36a7a62012-11-12 15:46:10 -08001566 }
1567
Eric Laurent1703cdf2011-03-07 14:52:59 -08001568 return result;
1569}
1570
Eric Laurent296fb132015-05-01 11:38:42 -07001571status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
1572{
1573 if (callback == 0) {
Eric Laurent973db022018-11-20 14:54:31 -08001574 ALOGW("%s(%d): adding NULL callback!", __func__, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07001575 return BAD_VALUE;
1576 }
1577 AutoMutex lock(mLock);
Eric Laurentad2e7b92017-09-14 20:06:42 -07001578 if (mDeviceCallback.unsafe_get() == callback.get()) {
Eric Laurent973db022018-11-20 14:54:31 -08001579 ALOGW("%s(%d): adding same callback!", __func__, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07001580 return INVALID_OPERATION;
1581 }
1582 status_t status = NO_ERROR;
1583 if (mInput != AUDIO_IO_HANDLE_NONE) {
1584 if (mDeviceCallback != 0) {
Eric Laurent973db022018-11-20 14:54:31 -08001585 ALOGW("%s(%d): callback already present!", __func__, mPortId);
Eric Laurent09f1ed22019-04-24 17:45:17 -07001586 AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07001587 }
Eric Laurent09f1ed22019-04-24 17:45:17 -07001588 status = AudioSystem::addAudioDeviceCallback(this, mInput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07001589 }
1590 mDeviceCallback = callback;
1591 return status;
1592}
1593
1594status_t AudioRecord::removeAudioDeviceCallback(
1595 const sp<AudioSystem::AudioDeviceCallback>& callback)
1596{
1597 if (callback == 0) {
Eric Laurent973db022018-11-20 14:54:31 -08001598 ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07001599 return BAD_VALUE;
1600 }
Eric Laurent4463ff52019-02-07 13:56:09 -08001601 AutoMutex lock(mLock);
1602 if (mDeviceCallback.unsafe_get() != callback.get()) {
1603 ALOGW("%s(%d): removing different callback!", __func__, mPortId);
1604 return INVALID_OPERATION;
Eric Laurent296fb132015-05-01 11:38:42 -07001605 }
Eric Laurent4463ff52019-02-07 13:56:09 -08001606 mDeviceCallback.clear();
Eric Laurent296fb132015-05-01 11:38:42 -07001607 if (mInput != AUDIO_IO_HANDLE_NONE) {
Eric Laurent09f1ed22019-04-24 17:45:17 -07001608 AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
Eric Laurent296fb132015-05-01 11:38:42 -07001609 }
Eric Laurent296fb132015-05-01 11:38:42 -07001610 return NO_ERROR;
1611}
1612
Eric Laurentad2e7b92017-09-14 20:06:42 -07001613void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
1614 audio_port_handle_t deviceId)
1615{
1616 sp<AudioSystem::AudioDeviceCallback> callback;
1617 {
1618 AutoMutex lock(mLock);
1619 if (audioIo != mInput) {
1620 return;
1621 }
1622 callback = mDeviceCallback.promote();
1623 // only update device if the record is active as route changes due to other use cases are
1624 // irrelevant for this client
1625 if (mActive) {
1626 mRoutedDeviceId = deviceId;
1627 }
1628 }
1629 if (callback.get() != nullptr) {
1630 callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
1631 }
1632}
1633
jiabin653cc0a2018-01-17 17:54:10 -08001634// -------------------------------------------------------------------------
1635
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001636status_t AudioRecord::getActiveMicrophones(std::vector<media::MicrophoneInfoFw>* activeMicrophones)
jiabin653cc0a2018-01-17 17:54:10 -08001637{
1638 AutoMutex lock(mLock);
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001639 return statusTFromBinderStatus(mAudioRecord->getActiveMicrophones(activeMicrophones));
jiabin653cc0a2018-01-17 17:54:10 -08001640}
1641
Paul McLean12340082019-03-19 09:35:05 -06001642status_t AudioRecord::setPreferredMicrophoneDirection(audio_microphone_direction_t direction)
Paul McLean03a6e6a2018-12-04 10:54:13 -07001643{
1644 AutoMutex lock(mLock);
Paul McLean366b6432019-02-25 10:35:51 -07001645 if (mSelectedMicDirection == direction) {
1646 // NOP
1647 return OK;
1648 }
1649
1650 mSelectedMicDirection = direction;
1651 if (mAudioRecord == 0) {
1652 // the internal AudioRecord hasn't be created yet, so just stash the attribute.
1653 return OK;
1654 } else {
Andy Hung1131b6e2020-12-08 20:47:45 -08001655 return statusTFromBinderStatus(mAudioRecord->setPreferredMicrophoneDirection(direction));
Paul McLean366b6432019-02-25 10:35:51 -07001656 }
Paul McLean03a6e6a2018-12-04 10:54:13 -07001657}
1658
Paul McLean12340082019-03-19 09:35:05 -06001659status_t AudioRecord::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001660 AutoMutex lock(mLock);
Paul McLean366b6432019-02-25 10:35:51 -07001661 if (mSelectedMicFieldDimension == zoom) {
1662 // NOP
1663 return OK;
1664 }
1665
1666 mSelectedMicFieldDimension = zoom;
1667 if (mAudioRecord == 0) {
1668 // the internal AudioRecord hasn't be created yet, so just stash the attribute.
1669 return OK;
1670 } else {
Andy Hung1131b6e2020-12-08 20:47:45 -08001671 return statusTFromBinderStatus(mAudioRecord->setPreferredMicrophoneFieldDimension(zoom));
Paul McLean366b6432019-02-25 10:35:51 -07001672 }
Paul McLean03a6e6a2018-12-04 10:54:13 -07001673}
1674
Andy Hung1a9c21b2021-02-25 20:43:18 -08001675void AudioRecord::setLogSessionId(const char *logSessionId)
1676{
Eric Laurentec376dc2021-04-08 20:41:22 +02001677 AutoMutex lock(mLock);
Andy Hung1a9c21b2021-02-25 20:43:18 -08001678 if (logSessionId == nullptr) logSessionId = ""; // an empty string is an unset session id.
1679 if (mLogSessionId == logSessionId) return;
1680
1681 mLogSessionId = logSessionId;
1682 mediametrics::LogItem(mMetricsId)
1683 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETLOGSESSIONID)
1684 .set(AMEDIAMETRICS_PROP_LOGSESSIONID, logSessionId)
1685 .record();
1686}
1687
Eric Laurentec376dc2021-04-08 20:41:22 +02001688status_t AudioRecord::shareAudioHistory(const std::string& sharedPackageName,
1689 int64_t sharedStartMs)
1690{
1691 AutoMutex lock(mLock);
1692 if (mAudioRecord == 0) {
1693 return NO_INIT;
1694 }
1695 status_t status = statusTFromBinderStatus(
1696 mAudioRecord->shareAudioHistory(sharedPackageName, sharedStartMs));
1697 if (status == NO_ERROR) {
1698 mSharedAudioPackageName = sharedPackageName;
1699 mSharedAudioStartMs = sharedStartMs;
1700 }
1701 return status;
1702}
1703
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001704// =========================================================================
1705
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08001706void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001707{
1708 sp<AudioRecord> audioRecord = mAudioRecord.promote();
1709 if (audioRecord != 0) {
1710 AutoMutex lock(audioRecord->mLock);
1711 audioRecord->mProxy->binderDied();
1712 }
1713}
1714
1715// =========================================================================
1716
Andy Hungca353672019-03-06 11:54:38 -08001717AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver)
Andy Hungeb46cf92019-03-06 10:13:38 -08001718 : Thread(true /* bCanCallJava */) // binder recursion on restoreRecord_l() may call Java.
1719 , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
Glenn Kasten41721bb2014-01-13 09:59:51 -08001720 mIgnoreNextPausedInt(false)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001721{
1722}
1723
Glenn Kasten68337ed2012-07-12 09:05:58 -07001724AudioRecord::AudioRecordThread::~AudioRecordThread()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001725{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001726}
1727
Glenn Kasten68337ed2012-07-12 09:05:58 -07001728bool AudioRecord::AudioRecordThread::threadLoop()
Glenn Kasten6dbc1352012-02-02 10:56:47 -08001729{
Glenn Kasten68337ed2012-07-12 09:05:58 -07001730 {
1731 AutoMutex _l(mMyLock);
1732 if (mPaused) {
Glenn Kasten75f79032017-05-23 11:22:44 -07001733 // TODO check return value and handle or log
Glenn Kasten68337ed2012-07-12 09:05:58 -07001734 mMyCond.wait(mMyLock);
1735 // caller will check for exitPending()
1736 return true;
1737 }
Glenn Kasten41721bb2014-01-13 09:59:51 -08001738 if (mIgnoreNextPausedInt) {
1739 mIgnoreNextPausedInt = false;
1740 mPausedInt = false;
1741 }
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001742 if (mPausedInt) {
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001743 if (mPausedNs > 0) {
Glenn Kasten75f79032017-05-23 11:22:44 -07001744 // TODO check return value and handle or log
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001745 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
1746 } else {
Glenn Kasten75f79032017-05-23 11:22:44 -07001747 // TODO check return value and handle or log
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001748 mMyCond.wait(mMyLock);
1749 }
Eric Laurent9d2c78c2013-09-23 12:29:42 -07001750 mPausedInt = false;
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001751 return true;
1752 }
Glenn Kasten6dbc1352012-02-02 10:56:47 -08001753 }
Kiran Kumar Krishnae813ef92016-11-01 07:50:22 -05001754 if (exitPending()) {
1755 return false;
1756 }
Glenn Kasten7c7be1e2013-12-19 16:34:04 -08001757 nsecs_t ns = mReceiver.processAudioBuffer();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001758 switch (ns) {
1759 case 0:
1760 return true;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001761 case NS_INACTIVE:
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001762 pauseInternal();
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001763 return true;
1764 case NS_NEVER:
1765 return false;
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001766 case NS_WHENEVER:
Andy Hung803b3e52015-03-18 23:26:55 -07001767 // Event driven: call wake() when callback notifications conditions change.
1768 ns = INT64_MAX;
Chih-Hung Hsiehffe35582018-09-13 13:59:28 -07001769 FALLTHROUGH_INTENDED;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001770 default:
Andy Hung6b1c6122018-09-12 19:09:07 -07001771 LOG_ALWAYS_FATAL_IF(ns < 0, "%s() returned %lld", __func__, (long long)ns);
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001772 pauseInternal(ns);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001773 return true;
Glenn Kasten68337ed2012-07-12 09:05:58 -07001774 }
Glenn Kasten68337ed2012-07-12 09:05:58 -07001775}
1776
1777void AudioRecord::AudioRecordThread::requestExit()
1778{
1779 // must be in this order to avoid a race condition
1780 Thread::requestExit();
Glenn Kasten41721bb2014-01-13 09:59:51 -08001781 resume();
Glenn Kasten68337ed2012-07-12 09:05:58 -07001782}
1783
1784void AudioRecord::AudioRecordThread::pause()
1785{
1786 AutoMutex _l(mMyLock);
1787 mPaused = true;
1788}
1789
1790void AudioRecord::AudioRecordThread::resume()
1791{
1792 AutoMutex _l(mMyLock);
Glenn Kasten41721bb2014-01-13 09:59:51 -08001793 mIgnoreNextPausedInt = true;
Eric Laurent9d2c78c2013-09-23 12:29:42 -07001794 if (mPaused || mPausedInt) {
Glenn Kasten68337ed2012-07-12 09:05:58 -07001795 mPaused = false;
Eric Laurent9d2c78c2013-09-23 12:29:42 -07001796 mPausedInt = false;
Glenn Kasten68337ed2012-07-12 09:05:58 -07001797 mMyCond.signal();
1798 }
Glenn Kasten6dbc1352012-02-02 10:56:47 -08001799}
1800
Andy Hung803b3e52015-03-18 23:26:55 -07001801void AudioRecord::AudioRecordThread::wake()
1802{
1803 AutoMutex _l(mMyLock);
Andy Hung805a0c72015-07-22 11:40:26 -07001804 if (!mPaused) {
1805 // wake() might be called while servicing a callback - ignore the next
1806 // pause time and call processAudioBuffer.
Andy Hung803b3e52015-03-18 23:26:55 -07001807 mIgnoreNextPausedInt = true;
Andy Hung805a0c72015-07-22 11:40:26 -07001808 if (mPausedInt && mPausedNs > 0) {
1809 // audio record is active and internally paused with timeout.
1810 mPausedInt = false;
1811 mMyCond.signal();
1812 }
Andy Hung803b3e52015-03-18 23:26:55 -07001813 }
1814}
1815
Glenn Kasten5a6cd222013-09-20 09:20:45 -07001816void AudioRecord::AudioRecordThread::pauseInternal(nsecs_t ns)
1817{
1818 AutoMutex _l(mMyLock);
1819 mPausedInt = true;
1820 mPausedNs = ns;
1821}
1822
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001823// -------------------------------------------------------------------------
1824
Glenn Kasten40bc9062015-03-20 09:09:33 -07001825} // namespace android