blob: 1917d571ac0b1db8a01a89595a08b7e263a27b4b [file] [log] [blame]
Eric Laurent81784c32012-11-19 14:55:58 -08001/*
2**
3** Copyright 2012, 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#ifndef INCLUDING_FROM_AUDIOFLINGER_H
19 #error This header file should only be included from AudioFlinger.h
20#endif
21
22// base for record and playback
Andy Hung02a6c4e2023-06-23 19:27:19 -070023class TrackBase : public ExtendedAudioBufferProvider, public virtual IAfTrackBase {
Eric Laurent81784c32012-11-19 14:55:58 -080024public:
Eric Laurent81784c32012-11-19 14:55:58 -080025 TrackBase(ThreadBase *thread,
26 const sp<Client>& client,
Kevin Rocard1f564ac2018-03-29 13:53:10 -070027 const audio_attributes_t& mAttr,
Eric Laurent81784c32012-11-19 14:55:58 -080028 uint32_t sampleRate,
29 audio_format_t format,
30 audio_channel_mask_t channelMask,
31 size_t frameCount,
Eric Laurent83b88082014-06-20 18:31:16 -070032 void *buffer,
Andy Hung8fe68032017-06-05 16:17:51 -070033 size_t bufferSize,
Glenn Kastend848eb42016-03-08 13:42:11 -080034 audio_session_t sessionId,
Eric Laurent09f1ed22019-04-24 17:45:17 -070035 pid_t creatorPid,
Andy Hung1f12a8a2016-11-07 16:10:30 -080036 uid_t uid,
Glenn Kastend776ac62014-05-07 09:16:09 -070037 bool isOut,
Dmitry Sidorenkova41c2732023-05-15 13:47:07 -070038 const alloc_type alloc = ALLOC_CBLK,
Eric Laurent20b9ef02016-12-05 11:03:16 -080039 track_type type = TYPE_DEFAULT,
Andy Hungb68f5eb2019-12-03 16:49:17 -080040 audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
41 std::string metricsId = {});
Andy Hung02a6c4e2023-06-23 19:27:19 -070042 ~TrackBase() override;
43 status_t initCheck() const override;
44 sp<IMemory> getCblk() const final { return mCblkMemory; }
45 audio_track_cblk_t* cblk() const final { return mCblk; }
46 audio_session_t sessionId() const final { return mSessionId; }
47 uid_t uid() const final { return mUid; }
48 pid_t creatorPid() const final { return mCreatorPid; }
49 audio_port_handle_t portId() const final { return mPortId; }
50 status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) override;
51 track_state state() const final { return mState; }
52 void setState(track_state state) final { mState = state; }
53 sp<IMemory> getBuffers() const final { return mBufferMemory; }
54 void* buffer() const final { return mBuffer; }
55 size_t bufferSize() const final { return mBufferSize; }
Eric Laurent81784c32012-11-19 14:55:58 -080056
Andy Hung02a6c4e2023-06-23 19:27:19 -070057 bool isOutputTrack() const final { return (mType == TYPE_OUTPUT); }
58 bool isPatchTrack() const final { return (mType == TYPE_PATCH); }
59 bool isExternalTrack() const final { return !isOutputTrack() && !isPatchTrack(); }
60 void invalidate() override {
Andy Hungb68f5eb2019-12-03 16:49:17 -080061 if (mIsInvalid) return;
Andy Hungc2b11cb2020-04-22 09:04:01 -070062 mTrackMetrics.logInvalidate();
Andy Hungb68f5eb2019-12-03 16:49:17 -080063 mIsInvalid = true;
64 }
Andy Hung02a6c4e2023-06-23 19:27:19 -070065 bool isInvalid() const final { return mIsInvalid; }
66 void terminate() final { mTerminated = true; }
67 bool isTerminated() const final { return mTerminated; }
68 audio_attributes_t attributes() const final { return mAttr; }
69 bool isSpatialized() const override { return false; }
70 bool isBitPerfect() const override { return false; }
Eric Laurent6acd1d42017-01-04 14:23:29 -080071
Andy Hung02a6c4e2023-06-23 19:27:19 -070072 // TODO(b/288339104) type
73 wp<Thread> thread() const final { return mThread; }
Andy Hungc3d62f92019-03-14 13:38:51 -070074
Andy Hung02a6c4e2023-06-23 19:27:19 -070075 const sp<ServerProxy>& serverProxy() const final { return mServerProxy; }
jiabinc658e452022-10-21 20:52:21 +000076
Andy Hung8946a282018-04-19 20:04:56 -070077#ifdef TEE_SINK
Andy Hung02a6c4e2023-06-23 19:27:19 -070078 void dumpTee(int fd, const std::string &reason) const final {
79 mTee.dump(fd, reason);
80 }
Andy Hung8946a282018-04-19 20:04:56 -070081#endif
Andy Hung02a6c4e2023-06-23 19:27:19 -070082 /** returns the buffer contents size converted to time in milliseconds
83 * for PCM Playback or Record streaming tracks. The return value is zero for
84 * PCM static tracks and not defined for non-PCM tracks.
85 *
86 * This may be called without the thread lock.
87 */
88 double bufferLatencyMs() const override {
Andy Hung920f6572022-10-06 12:09:49 -070089 return mServerProxy->framesReadySafe() * 1000. / sampleRate();
Andy Hungcef2daa2018-06-01 15:31:49 -070090 }
91
Andy Hung02a6c4e2023-06-23 19:27:19 -070092 /** returns whether the track supports server latency computation.
93 * This is set in the constructor and constant throughout the track lifetime.
94 */
95 bool isServerLatencySupported() const final { return mServerLatencySupported; }
Andy Hungcef2daa2018-06-01 15:31:49 -070096
Andy Hung02a6c4e2023-06-23 19:27:19 -070097 /** computes the server latency for PCM Playback or Record track
98 * to the device sink/source. This is the time for the next frame in the track buffer
99 * written or read from the server thread to the device source or sink.
100 *
101 * This may be called without the thread lock, but latencyMs and fromTrack
102 * may be not be synchronized. For example PatchPanel may not obtain the
103 * thread lock before calling.
104 *
105 * \param latencyMs on success is set to the latency in milliseconds of the
106 * next frame written/read by the server thread to/from the track buffer
107 * from the device source/sink.
108 * \param fromTrack on success is set to true if latency was computed directly
109 * from the track timestamp; otherwise set to false if latency was
110 * estimated from the server timestamp.
111 * fromTrack may be nullptr or omitted if not required.
112 *
113 * \returns OK or INVALID_OPERATION on failure.
114 */
115 status_t getServerLatencyMs(double* latencyMs, bool* fromTrack = nullptr) const final {
Andy Hungcef2daa2018-06-01 15:31:49 -0700116 if (!isServerLatencySupported()) {
117 return INVALID_OPERATION;
118 }
119
120 // if no thread lock is acquired, these atomics are not
121 // synchronized with each other, considered a benign race.
122
123 const double serverLatencyMs = mServerLatencyMs.load();
124 if (serverLatencyMs == 0.) {
125 return INVALID_OPERATION;
126 }
127 if (fromTrack != nullptr) {
128 *fromTrack = mServerLatencyFromTrack.load();
129 }
130 *latencyMs = serverLatencyMs;
131 return OK;
132 }
133
Andy Hung02a6c4e2023-06-23 19:27:19 -0700134 /** computes the total client latency for PCM Playback or Record tracks
135 * for the next client app access to the device sink/source; i.e. the
136 * server latency plus the buffer latency.
137 *
138 * This may be called without the thread lock, but latencyMs and fromTrack
139 * may be not be synchronized. For example PatchPanel may not obtain the
140 * thread lock before calling.
141 *
142 * \param latencyMs on success is set to the latency in milliseconds of the
143 * next frame written/read by the client app to/from the track buffer
144 * from the device sink/source.
145 * \param fromTrack on success is set to true if latency was computed directly
146 * from the track timestamp; otherwise set to false if latency was
147 * estimated from the server timestamp.
148 * fromTrack may be nullptr or omitted if not required.
149 *
150 * \returns OK or INVALID_OPERATION on failure.
151 */
152 status_t getTrackLatencyMs(double* latencyMs, bool* fromTrack = nullptr) const {
Andy Hungcef2daa2018-06-01 15:31:49 -0700153 double serverLatencyMs;
154 status_t status = getServerLatencyMs(&serverLatencyMs, fromTrack);
155 if (status == OK) {
156 *latencyMs = serverLatencyMs + bufferLatencyMs();
157 }
158 return status;
159 }
160
Andy Hung02a6c4e2023-06-23 19:27:19 -0700161 // KernelFrameTime is updated per "mix" period even for non-pcm tracks.
162 void getKernelFrameTime(FrameTime* ft) const final {
Andy Hung30282562018-08-08 18:27:03 -0700163 *ft = mKernelFrameTime.load();
164 }
165
Andy Hung02a6c4e2023-06-23 19:27:19 -0700166 audio_format_t format() const final { return mFormat; }
167 int id() const final { return mId; }
Andy Hung30282562018-08-08 18:27:03 -0700168
Andy Hung02a6c4e2023-06-23 19:27:19 -0700169 const char* getTrackStateAsString() const final {
Andy Hunge2e830f2019-12-03 12:54:46 -0800170 if (isTerminated()) {
171 return "TERMINATED";
172 }
173 switch (mState) {
174 case IDLE:
175 return "IDLE";
176 case STOPPING_1: // for Fast and Offload
177 return "STOPPING_1";
178 case STOPPING_2: // for Fast and Offload
179 return "STOPPING_2";
180 case STOPPED:
181 return "STOPPED";
182 case RESUMING:
183 return "RESUMING";
184 case ACTIVE:
185 return "ACTIVE";
186 case PAUSING:
187 return "PAUSING";
188 case PAUSED:
189 return "PAUSED";
190 case FLUSHED:
191 return "FLUSHED";
192 case STARTING_1: // for RecordTrack
193 return "STARTING_1";
194 case STARTING_2: // for RecordTrack
195 return "STARTING_2";
196 default:
197 return "UNKNOWN";
198 }
199 }
200
Andy Hungc2b11cb2020-04-22 09:04:01 -0700201 // Called by the PlaybackThread to indicate that the track is becoming active
202 // and a new interval should start with a given device list.
Andy Hung02a6c4e2023-06-23 19:27:19 -0700203 void logBeginInterval(const std::string& devices) final {
Andy Hungc2b11cb2020-04-22 09:04:01 -0700204 mTrackMetrics.logBeginInterval(devices);
205 }
206
207 // Called by the PlaybackThread to indicate the track is no longer active.
Andy Hung02a6c4e2023-06-23 19:27:19 -0700208 void logEndInterval() final {
Andy Hungc2b11cb2020-04-22 09:04:01 -0700209 mTrackMetrics.logEndInterval();
210 }
211
212 // Called to tally underrun frames in playback.
Andy Hung02a6c4e2023-06-23 19:27:19 -0700213 void tallyUnderrunFrames(size_t /* frames */) override {}
Andy Hungc2b11cb2020-04-22 09:04:01 -0700214
Andy Hung02a6c4e2023-06-23 19:27:19 -0700215 audio_channel_mask_t channelMask() const final { return mChannelMask; }
Eric Laurent94579172020-11-20 18:41:04 +0100216
Jasmine Chaeaa10e42021-05-11 10:11:14 +0800217 /** @return true if the track has changed (metadata or volume) since
218 * the last time this function was called,
219 * true if this function was never called since the track creation,
220 * false otherwise.
221 * Thread safe.
222 */
Andy Hung02a6c4e2023-06-23 19:27:19 -0700223 bool readAndClearHasChanged() final { return !mChangeNotified.test_and_set(); }
Jasmine Chaeaa10e42021-05-11 10:11:14 +0800224
225 /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
Andy Hung02a6c4e2023-06-23 19:27:19 -0700226 void setMetadataHasChanged() final { mChangeNotified.clear(); }
Jasmine Chaeaa10e42021-05-11 10:11:14 +0800227
Eric Laurent81784c32012-11-19 14:55:58 -0800228protected:
Mikhail Naganovbf493082017-04-17 17:37:12 -0700229 DISALLOW_COPY_AND_ASSIGN(TrackBase);
Eric Laurent81784c32012-11-19 14:55:58 -0800230
Andy Hung689e82c2019-08-21 17:53:17 -0700231 void releaseCblk() {
232 if (mCblk != nullptr) {
Andy Hung959b5b82021-09-24 10:46:20 -0700233 mState.clear();
Andy Hung689e82c2019-08-21 17:53:17 -0700234 mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
235 if (mClient == 0) {
236 free(mCblk);
237 }
238 mCblk = nullptr;
239 }
240 }
241
Eric Laurent81784c32012-11-19 14:55:58 -0800242 // AudioBufferProvider interface
Andy Hung02a6c4e2023-06-23 19:27:19 -0700243 // status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) override;
244 void releaseBuffer(AudioBufferProvider::Buffer* buffer) override;
Eric Laurent81784c32012-11-19 14:55:58 -0800245
246 // ExtendedAudioBufferProvider interface is only needed for Track,
247 // but putting it in TrackBase avoids the complexity of virtual inheritance
Andy Hung02a6c4e2023-06-23 19:27:19 -0700248 size_t framesReady() const override { return SIZE_MAX; } // MmapTrack doesn't implement.
Eric Laurent81784c32012-11-19 14:55:58 -0800249
Eric Laurent81784c32012-11-19 14:55:58 -0800250 uint32_t channelCount() const { return mChannelCount; }
251
Andy Hung02a6c4e2023-06-23 19:27:19 -0700252 size_t frameSize() const final { return mFrameSize; }
Jean-Michel Trividdf87ef2019-08-20 15:42:04 -0700253
Andy Hung02a6c4e2023-06-23 19:27:19 -0700254 uint32_t sampleRate() const override { return mSampleRate; }
Eric Laurent81784c32012-11-19 14:55:58 -0800255
Andy Hung02a6c4e2023-06-23 19:27:19 -0700256 bool isStopped() const final {
Eric Laurent81784c32012-11-19 14:55:58 -0800257 return (mState == STOPPED || mState == FLUSHED);
258 }
259
Eric Laurentbfb1b832013-01-07 09:53:42 -0800260 // for fast tracks and offloaded tracks only
Andy Hung02a6c4e2023-06-23 19:27:19 -0700261 bool isStopping() const final {
Eric Laurent81784c32012-11-19 14:55:58 -0800262 return mState == STOPPING_1 || mState == STOPPING_2;
263 }
Andy Hung02a6c4e2023-06-23 19:27:19 -0700264 bool isStopping_1() const final {
Eric Laurent81784c32012-11-19 14:55:58 -0800265 return mState == STOPPING_1;
266 }
Andy Hung02a6c4e2023-06-23 19:27:19 -0700267 bool isStopping_2() const final {
Eric Laurent81784c32012-11-19 14:55:58 -0800268 return mState == STOPPING_2;
269 }
270
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700271 // Upper case characters are final states.
272 // Lower case characters are transitory.
Andy Hunge2e830f2019-12-03 12:54:46 -0800273 const char *getTrackStateAsCodedString() const {
Andy Hung2c6c3bb2017-06-16 14:01:45 -0700274 if (isTerminated()) {
275 return "T ";
276 }
277 switch (mState) {
278 case IDLE:
279 return "I ";
280 case STOPPING_1: // for Fast and Offload
281 return "s1";
282 case STOPPING_2: // for Fast and Offload
283 return "s2";
284 case STOPPED:
285 return "S ";
286 case RESUMING:
287 return "r ";
288 case ACTIVE:
289 return "A ";
290 case PAUSING:
291 return "p ";
292 case PAUSED:
293 return "P ";
294 case FLUSHED:
295 return "F ";
296 case STARTING_1: // for RecordTrack
297 return "r1";
298 case STARTING_2: // for RecordTrack
299 return "r2";
300 default:
301 return "? ";
302 }
303 }
304
Glenn Kastene3aa6592012-12-04 12:22:46 -0800305 bool isOut() const { return mIsOut; }
Glenn Kastend79072e2016-01-06 08:41:20 -0800306 // true for Track, false for RecordTrack,
Eric Laurent81784c32012-11-19 14:55:58 -0800307 // this could be a track type if needed later
308
309 const wp<ThreadBase> mThread;
Dmitry Sidorenkova41c2732023-05-15 13:47:07 -0700310 const alloc_type mAllocType;
Eric Laurent81784c32012-11-19 14:55:58 -0800311 /*const*/ sp<Client> mClient; // see explanation at ~TrackBase() why not const
312 sp<IMemory> mCblkMemory;
313 audio_track_cblk_t* mCblk;
Glenn Kastend776ac62014-05-07 09:16:09 -0700314 sp<IMemory> mBufferMemory; // currently non-0 for fast RecordTrack only
Eric Laurent81784c32012-11-19 14:55:58 -0800315 void* mBuffer; // start of track buffer, typically in shared memory
Glenn Kastene3aa6592012-12-04 12:22:46 -0800316 // except for OutputTrack when it is in local memory
Andy Hung8fe68032017-06-05 16:17:51 -0700317 size_t mBufferSize; // size of mBuffer in bytes
Eric Laurent81784c32012-11-19 14:55:58 -0800318 // we don't really need a lock for these
Andy Hung959b5b82021-09-24 10:46:20 -0700319 MirroredVariable<track_state> mState;
Kevin Rocard1f564ac2018-03-29 13:53:10 -0700320 const audio_attributes_t mAttr;
Eric Laurent81784c32012-11-19 14:55:58 -0800321 const uint32_t mSampleRate; // initial sample rate only; for tracks which
322 // support dynamic rates, the current value is in control block
323 const audio_format_t mFormat;
324 const audio_channel_mask_t mChannelMask;
Glenn Kastenf6ed4232013-07-16 11:16:27 -0700325 const uint32_t mChannelCount;
Eric Laurent81784c32012-11-19 14:55:58 -0800326 const size_t mFrameSize; // AudioFlinger's view of frame size in shared memory,
327 // where for AudioTrack (but not AudioRecord),
328 // 8-bit PCM samples are stored as 16-bit
329 const size_t mFrameCount;// size of track buffer given at createTrack() or
Eric Laurentf14db3c2017-12-08 14:20:36 -0800330 // createRecord(), and then adjusted as needed
Eric Laurent81784c32012-11-19 14:55:58 -0800331
Glenn Kastend848eb42016-03-08 13:42:11 -0800332 const audio_session_t mSessionId;
Andy Hung1f12a8a2016-11-07 16:10:30 -0800333 uid_t mUid;
Andy Hung068e08e2023-05-15 19:02:55 -0700334 std::list<sp<audioflinger::SyncEvent>> mSyncEvents;
Glenn Kastene3aa6592012-12-04 12:22:46 -0800335 const bool mIsOut;
Eric Laurent5bba2f62016-03-18 11:14:14 -0700336 sp<ServerProxy> mServerProxy;
Glenn Kastenda6ef132013-01-10 12:31:01 -0800337 const int mId;
Andy Hung8946a282018-04-19 20:04:56 -0700338#ifdef TEE_SINK
339 NBAIO_Tee mTee;
340#endif
Eric Laurentbfb1b832013-01-07 09:53:42 -0800341 bool mTerminated;
Eric Laurent83b88082014-06-20 18:31:16 -0700342 track_type mType; // must be one of TYPE_DEFAULT, TYPE_OUTPUT, TYPE_PATCH ...
Eric Laurentaaa44472014-09-12 17:41:50 -0700343 audio_io_handle_t mThreadIoHandle; // I/O handle of the thread the track is attached to
Eric Laurent20b9ef02016-12-05 11:03:16 -0800344 audio_port_handle_t mPortId; // unique ID for this track used by audio policy
Eric Laurent6acd1d42017-01-04 14:23:29 -0800345 bool mIsInvalid; // non-resettable latch, set by invalidate()
Andy Hungcef2daa2018-06-01 15:31:49 -0700346
Andy Hungb68f5eb2019-12-03 16:49:17 -0800347 // It typically takes 5 threadloop mix iterations for latency to stabilize.
Andy Hung62921122020-05-18 10:47:31 -0700348 // However, this can be 12+ iterations for BT.
349 // To be sure, we wait for latency to dip (it usually increases at the start)
350 // to assess stability and then log to MediaMetrics.
351 // Rapid start / pause calls may cause inaccurate numbers.
352 static inline constexpr int32_t LOG_START_COUNTDOWN = 12;
353 int32_t mLogStartCountdown = 0; // Mixer period countdown
354 int64_t mLogStartTimeNs = 0; // Monotonic time at start()
355 int64_t mLogStartFrames = 0; // Timestamp frames at start()
356 double mLogLatencyMs = 0.; // Track the last log latency
Andy Hungb68f5eb2019-12-03 16:49:17 -0800357
Andy Hunga81a4b42022-05-19 19:24:51 -0700358 bool mLogForceVolumeUpdate = true; // force volume update to TrackMetrics.
359
Andy Hungc2b11cb2020-04-22 09:04:01 -0700360 TrackMetrics mTrackMetrics;
Andy Hungb68f5eb2019-12-03 16:49:17 -0800361
Andy Hungcef2daa2018-06-01 15:31:49 -0700362 bool mServerLatencySupported = false;
363 std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
364 std::atomic<double> mServerLatencyMs{}; // last latency pushed from server thread.
Andy Hung30282562018-08-08 18:27:03 -0700365 std::atomic<FrameTime> mKernelFrameTime{}; // last frame time on kernel side.
Eric Laurent09f1ed22019-04-24 17:45:17 -0700366 const pid_t mCreatorPid; // can be different from mclient->pid() for instance
367 // when created by NuPlayer on behalf of a client
Jasmine Chaeaa10e42021-05-11 10:11:14 +0800368
369 // If the last track change was notified to the client with readAndClearHasChanged
370 std::atomic_flag mChangeNotified = ATOMIC_FLAG_INIT;
Eric Laurent83b88082014-06-20 18:31:16 -0700371};
372
Andy Hung4d85ad02023-06-26 19:20:57 -0700373class PatchTrackBase : public PatchProxyBufferProvider, public virtual IAfPatchTrackBase
Kevin Rocard45986c72018-12-18 18:22:59 -0800374{
375public:
376 using Timeout = std::optional<std::chrono::nanoseconds>;
Andy Hung920f6572022-10-06 12:09:49 -0700377 PatchTrackBase(const sp<ClientProxy>& proxy, const ThreadBase& thread,
Kevin Rocard45986c72018-12-18 18:22:59 -0800378 const Timeout& timeout);
Andy Hung4d85ad02023-06-26 19:20:57 -0700379 void setPeerTimeout(std::chrono::nanoseconds timeout) final;
380 void setPeerProxy(const sp<IAfPatchTrackBase>& proxy, bool holdReference) final {
381 if (proxy) {
382 mPeerReferenceHold = holdReference ? proxy : nullptr;
383 mPeerProxy = proxy->asPatchProxyBufferProvider();
384 } else {
385 clearPeerProxy();
386 }
387 }
388 void clearPeerProxy() final {
Andy Hungabfab202019-03-07 19:45:54 -0800389 mPeerReferenceHold.clear();
390 mPeerProxy = nullptr;
391 }
Kevin Rocard45986c72018-12-18 18:22:59 -0800392
Andy Hung4d85ad02023-06-26 19:20:57 -0700393 PatchProxyBufferProvider* asPatchProxyBufferProvider() final { return this; }
394
Mikhail Naganovcaf59942019-09-25 14:05:29 -0700395 bool producesBufferOnDemand() const override { return false; }
396
Kevin Rocard45986c72018-12-18 18:22:59 -0800397protected:
398 const sp<ClientProxy> mProxy;
Andy Hungabfab202019-03-07 19:45:54 -0800399 sp<RefBase> mPeerReferenceHold; // keeps mPeerProxy alive during access.
Kevin Rocard45986c72018-12-18 18:22:59 -0800400 PatchProxyBufferProvider* mPeerProxy = nullptr;
401 struct timespec mPeerTimeout{};
402
403};