diff options
author | Peng Xu <pengxu@google.com> | 2017-05-17 16:53:25 -0700 |
---|---|---|
committer | Peng Xu <pengxu@google.com> | 2017-08-25 11:40:38 -0700 |
commit | 02f1e485a4f42619a592b651906faf9e0571e93a (patch) | |
tree | 4686b97fa6ea8f5b770d97f7db60e40e450667c2 | |
parent | cc13c0ea5d8e65b1f1dd4425ae4cfb3ac5be611c (diff) | |
download | contexthub-02f1e485a4f42619a592b651906faf9e0571e93a.tar.gz |
Adding direct report support for uncal sensor types
* Add direct report support for uncal accel, uncal gyro and
uncal mag.
* Downsample data so that the rate of each direct channel and
the traditional poll() interface are independent from each
other for the same sensor.
Bug: 34356079
Bug: 64841879
Test: all newly added SensorDirectReportTest test cases passed.
Change-Id: I715c87b666c01ab0fe1d61f1143536b1d2547b89
-rw-r--r-- | sensorhal/hubconnection.cpp | 315 | ||||
-rw-r--r-- | sensorhal/hubconnection.h | 18 |
2 files changed, 238 insertions, 95 deletions
diff --git a/sensorhal/hubconnection.cpp b/sensorhal/hubconnection.cpp index 00195c5c..01b95df4 100644 --- a/sensorhal/hubconnection.cpp +++ b/sensorhal/hubconnection.cpp @@ -277,9 +277,18 @@ HubConnection::HubConnection() #ifdef DIRECT_REPORT_ENABLED mDirectChannelHandle = 1; - mSensorToChannel.emplace(COMMS_SENSOR_ACCEL, std::unordered_map<int32_t, int32_t>()); - mSensorToChannel.emplace(COMMS_SENSOR_GYRO, std::unordered_map<int32_t, int32_t>()); - mSensorToChannel.emplace(COMMS_SENSOR_MAG, std::unordered_map<int32_t, int32_t>()); + mSensorToChannel.emplace(COMMS_SENSOR_ACCEL, + std::unordered_map<int32_t, DirectChannelTimingInfo>()); + mSensorToChannel.emplace(COMMS_SENSOR_GYRO, + std::unordered_map<int32_t, DirectChannelTimingInfo>()); + mSensorToChannel.emplace(COMMS_SENSOR_MAG, + std::unordered_map<int32_t, DirectChannelTimingInfo>()); + mSensorToChannel.emplace(COMMS_SENSOR_ACCEL_UNCALIBRATED, + std::unordered_map<int32_t, DirectChannelTimingInfo>()); + mSensorToChannel.emplace(COMMS_SENSOR_GYRO_UNCALIBRATED, + std::unordered_map<int32_t, DirectChannelTimingInfo>()); + mSensorToChannel.emplace(COMMS_SENSOR_MAG_UNCALIBRATED, + std::unordered_map<int32_t, DirectChannelTimingInfo>()); #endif // DIRECT_REPORT_ENABLED } @@ -736,25 +745,30 @@ void HubConnection::processSample(uint64_t timestamp, uint32_t type, uint32_t se sv->y = sample->iy * mScaleAccel; sv->z = sample->iz * mScaleAccel; sv->status = SENSOR_STATUS_ACCURACY_HIGH; - sendDirectReportEvent(&nev[cnt], 1); - if (mSensorState[sensor].enable) { + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) { ++cnt; } - if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable) { - ue = &initEv(&nev[cnt++], timestamp, - SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED, - COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer; - ue->x_uncalib = sample->ix * mScaleAccel + mAccelBias[0]; - ue->y_uncalib = sample->iy * mScaleAccel + mAccelBias[1]; - ue->z_uncalib = sample->iz * mScaleAccel + mAccelBias[2]; - ue->x_bias = mAccelBias[0]; - ue->y_bias = mAccelBias[1]; - ue->z_bias = mAccelBias[2]; + ue = &initEv(&nev[cnt], timestamp, + SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED, + COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer; + ue->x_uncalib = sample->ix * mScaleAccel + mAccelBias[0]; + ue->y_uncalib = sample->iy * mScaleAccel + mAccelBias[1]; + ue->z_uncalib = sample->iz * mScaleAccel + mAccelBias[2]; + ue->x_bias = mAccelBias[0]; + ue->y_bias = mAccelBias[1]; + ue->z_bias = mAccelBias[2]; + + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_UNCALIBRATED, timestamp)) { + ++cnt; } - if (mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].enable) { + if (mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_WRIST_AWARE, timestamp)) { sv = &initEv(&nev[cnt++], timestamp, SENSOR_TYPE_ACCELEROMETER_WRIST_AWARE, COMMS_SENSOR_ACCEL_WRIST_AWARE)->acceleration; @@ -770,22 +784,26 @@ void HubConnection::processSample(uint64_t timestamp, uint32_t type, uint32_t se sv->y = sample->iy * mScaleMag; sv->z = sample->iz * mScaleMag; sv->status = magAccuracyUpdate(sv); - sendDirectReportEvent(&nev[cnt], 1); - if (mSensorState[sensor].enable) { + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) { ++cnt; } - if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable) { - ue = &initEv(&nev[cnt++], timestamp, - SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED, - COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic; - ue->x_uncalib = sample->ix * mScaleMag + mMagBias[0]; - ue->y_uncalib = sample->iy * mScaleMag + mMagBias[1]; - ue->z_uncalib = sample->iz * mScaleMag + mMagBias[2]; - ue->x_bias = mMagBias[0]; - ue->y_bias = mMagBias[1]; - ue->z_bias = mMagBias[2]; + ue = &initEv(&nev[cnt], timestamp, + SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED, + COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic; + ue->x_uncalib = sample->ix * mScaleMag + mMagBias[0]; + ue->y_uncalib = sample->iy * mScaleMag + mMagBias[1]; + ue->z_uncalib = sample->iz * mScaleMag + mMagBias[2]; + ue->x_bias = mMagBias[0]; + ue->y_bias = mMagBias[1]; + ue->z_bias = mMagBias[2]; + + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_MAG_UNCALIBRATED, timestamp)) { + ++cnt; } default: break; @@ -815,32 +833,38 @@ void HubConnection::processSample(uint64_t timestamp, uint32_t type, uint32_t se sv->y = sample->y; sv->z = sample->z; sv->status = SENSOR_STATUS_ACCURACY_HIGH; - sendDirectReportEvent(&nev[cnt], 1); - if (mSensorState[sensor].enable) { + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) { ++cnt; } - if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable) { - ue = &initEv(&nev[cnt++], timestamp, - SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED, - COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer; - ue->x_uncalib = sample->x + mAccelBias[0]; - ue->y_uncalib = sample->y + mAccelBias[1]; - ue->z_uncalib = sample->z + mAccelBias[2]; - ue->x_bias = mAccelBias[0]; - ue->y_bias = mAccelBias[1]; - ue->z_bias = mAccelBias[2]; + ue = &initEv(&nev[cnt], timestamp, + SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED, + COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer; + ue->x_uncalib = sample->x + mAccelBias[0]; + ue->y_uncalib = sample->y + mAccelBias[1]; + ue->z_uncalib = sample->z + mAccelBias[2]; + ue->x_bias = mAccelBias[0]; + ue->y_bias = mAccelBias[1]; + ue->z_bias = mAccelBias[2]; + + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_UNCALIBRATED, timestamp)) { + ++cnt; } - if (mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].enable) { - sv = &initEv(&nev[cnt++], timestamp, + if (mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_WRIST_AWARE, timestamp)) { + sv = &initEv(&nev[cnt], timestamp, SENSOR_TYPE_ACCELEROMETER_WRIST_AWARE, COMMS_SENSOR_ACCEL_WRIST_AWARE)->acceleration; sv->x = sample->x; sv->y = (mLefty.accel ? -sample->y : sample->y); sv->z = sample->z; sv->status = SENSOR_STATUS_ACCURACY_HIGH; + ++cnt; } break; case COMMS_SENSOR_GYRO: @@ -849,32 +873,38 @@ void HubConnection::processSample(uint64_t timestamp, uint32_t type, uint32_t se sv->y = sample->y; sv->z = sample->z; sv->status = SENSOR_STATUS_ACCURACY_HIGH; - sendDirectReportEvent(&nev[cnt], 1); - if (mSensorState[sensor].enable) { + sendDirectReportEvent(&nev[cnt], 1); + if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) { ++cnt; } - if (mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].enable) { - ue = &initEv(&nev[cnt++], timestamp, - SENSOR_TYPE_GYROSCOPE_UNCALIBRATED, - COMMS_SENSOR_GYRO_UNCALIBRATED)->uncalibrated_gyro; - ue->x_uncalib = sample->x + mGyroBias[0]; - ue->y_uncalib = sample->y + mGyroBias[1]; - ue->z_uncalib = sample->z + mGyroBias[2]; - ue->x_bias = mGyroBias[0]; - ue->y_bias = mGyroBias[1]; - ue->z_bias = mGyroBias[2]; + ue = &initEv(&nev[cnt], timestamp, + SENSOR_TYPE_GYROSCOPE_UNCALIBRATED, + COMMS_SENSOR_GYRO_UNCALIBRATED)->uncalibrated_gyro; + ue->x_uncalib = sample->x + mGyroBias[0]; + ue->y_uncalib = sample->y + mGyroBias[1]; + ue->z_uncalib = sample->z + mGyroBias[2]; + ue->x_bias = mGyroBias[0]; + ue->y_bias = mGyroBias[1]; + ue->z_bias = mGyroBias[2]; + sendDirectReportEvent(&nev[cnt], 1); + + if (mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_GYRO_UNCALIBRATED, timestamp)) { + ++cnt; } - if (mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].enable) { - sv = &initEv(&nev[cnt++], timestamp, + if (mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_GYRO_WRIST_AWARE, timestamp)) { + sv = &initEv(&nev[cnt], timestamp, SENSOR_TYPE_GYROSCOPE_WRIST_AWARE, COMMS_SENSOR_GYRO_WRIST_AWARE)->gyro; sv->x = (mLefty.gyro ? -sample->x : sample->x); sv->y = sample->y; sv->z = (mLefty.gyro ? -sample->z : sample->z); sv->status = SENSOR_STATUS_ACCURACY_HIGH; + ++cnt; } break; case COMMS_SENSOR_ACCEL_BIAS: @@ -897,20 +927,24 @@ void HubConnection::processSample(uint64_t timestamp, uint32_t type, uint32_t se sv->status = magAccuracyUpdate(sv); sendDirectReportEvent(&nev[cnt], 1); - if (mSensorState[sensor].enable) { + if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) { ++cnt; } - if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable) { - ue = &initEv(&nev[cnt++], timestamp, - SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED, - COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic; - ue->x_uncalib = sample->x + mMagBias[0]; - ue->y_uncalib = sample->y + mMagBias[1]; - ue->z_uncalib = sample->z + mMagBias[2]; - ue->x_bias = mMagBias[0]; - ue->y_bias = mMagBias[1]; - ue->z_bias = mMagBias[2]; + ue = &initEv(&nev[cnt], timestamp, + SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED, + COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic; + ue->x_uncalib = sample->x + mMagBias[0]; + ue->y_uncalib = sample->y + mMagBias[1]; + ue->z_uncalib = sample->z + mMagBias[2]; + ue->x_bias = mMagBias[0]; + ue->y_bias = mMagBias[1]; + ue->z_bias = mMagBias[2]; + sendDirectReportEvent(&nev[cnt], 1); + + if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable + && isSampleIntervalSatisfied(COMMS_SENSOR_MAG_UNCALIBRATED, timestamp)) { + ++cnt; } break; case COMMS_SENSOR_MAG_BIAS: @@ -1404,6 +1438,9 @@ ssize_t HubConnection::processBuf(uint8_t *buf, size_t len) ev.sensor = 0; ev.meta_data.what = META_DATA_FLUSH_COMPLETE; ev.meta_data.sensor = flush.handle; + if (mSensorState[flush.handle].enable) { + updateSampleRate(flush.handle, CONFIG_CMD_FLUSH); + } if (flush.internal) { if (flush.handle == COMMS_SENSOR_ACCEL_WRIST_AWARE) @@ -1657,9 +1694,11 @@ void HubConnection::queueActivate(int handle, bool enable) initConfigCmd(&cmd, handle); ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd))); - if (ret == sizeof(cmd)) + if (ret == sizeof(cmd)) { + updateSampleRate(handle, enable ? CONFIG_CMD_ENABLE : CONFIG_CMD_DISABLE); ALOGV("queueActivate: sensor=%d, handle=%d, enable=%d", cmd.sensorType, handle, enable); + } else ALOGW("queueActivate: failed to send command: sensor=%d, handle=%d, enable=%d", cmd.sensorType, handle, enable); @@ -1971,7 +2010,14 @@ void HubConnection::sendDirectReportEvent(const sensors_event_t *nev, size_t n) auto i = mSensorToChannel.find(nev->sensor); if (i != mSensorToChannel.end()) { for (auto &j : i->second) { - mDirectChannel[j.first]->write(nev); + if ((uint64_t)nev->timestamp > j.second.lastTimestamp + && intervalLargeEnough( + nev->timestamp - j.second.lastTimestamp, + rateLevelToDeviceSamplingPeriodNs( + nev->sensor, j.second.rateLevel))) { + mDirectChannel[j.first]->write(nev); + j.second.lastTimestamp = nev->timestamp; + } } } ++nev; @@ -1981,35 +2027,31 @@ void HubConnection::sendDirectReportEvent(const sensors_event_t *nev, size_t n) } void HubConnection::mergeDirectReportRequest(struct ConfigCmd *cmd, int handle) { + int maxRateLevel = SENSOR_DIRECT_RATE_STOP; + auto j = mSensorToChannel.find(handle); if (j != mSensorToChannel.end()) { - bool enable = false; - rate_q10_t rate; - - if (!j->second.empty()) { - int maxRateLevel = SENSOR_DIRECT_RATE_STOP; + for (auto &i : j->second) { + maxRateLevel = std::max(i.second.rateLevel, maxRateLevel); + } + } + for (auto handle : mSensorState[handle].alt) { + auto j = mSensorToChannel.find(handle); + if (j != mSensorToChannel.end()) { for (auto &i : j->second) { - maxRateLevel = (i.second) > maxRateLevel ? i.second : maxRateLevel; - } - switch(maxRateLevel) { - case SENSOR_DIRECT_RATE_NORMAL: - enable = true; - rate = period_ns_to_frequency_q10(20000000ull); // NORMAL = 50Hz - break; - case SENSOR_DIRECT_RATE_FAST: - enable = true; - rate = period_ns_to_frequency_q10(5000000ull); // FAST = 200Hz - break; - default: - break; + maxRateLevel = std::max(i.second.rateLevel, maxRateLevel); } } + } - if (enable) { - cmd->rate = (rate > cmd->rate || cmd->cmd == CONFIG_CMD_DISABLE) ? rate : cmd->rate; - cmd->latency = 0; - cmd->cmd = CONFIG_CMD_ENABLE; - } + uint64_t period = rateLevelToDeviceSamplingPeriodNs(handle, maxRateLevel); + if (period != INT64_MAX) { + rate_q10_t rate; + rate = period_ns_to_frequency_q10(period); + + cmd->rate = (rate > cmd->rate || cmd->cmd == CONFIG_CMD_DISABLE) ? rate : cmd->rate; + cmd->latency = 0; + cmd->cmd = CONFIG_CMD_ENABLE; } } @@ -2132,7 +2174,7 @@ int HubConnection::configDirectReport(int sensor_handle, int channel_handle, int j->second.erase(channel_handle); if (rate_level != SENSOR_DIRECT_RATE_STOP) { - j->second.insert(std::make_pair(channel_handle, rate_level)); + j->second.insert(std::make_pair(channel_handle, (DirectChannelTimingInfo){0, rate_level})); } Mutex::Autolock autoLock2(mLock); @@ -2152,6 +2194,86 @@ int HubConnection::configDirectReport(int sensor_handle, int channel_handle, int bool HubConnection::isDirectReportSupported() const { return true; } + +void HubConnection::updateSampleRate(int handle, int reason) { + bool affected = mSensorToChannel.find(handle) != mSensorToChannel.end(); + for (size_t i = 0; i < MAX_ALTERNATES && !affected; ++i) { + if (mSensorState[handle].alt[i] != COMMS_SENSOR_INVALID) { + affected |= + mSensorToChannel.find(mSensorState[handle].alt[i]) != mSensorToChannel.end(); + } + } + if (!affected) { + return; + } + + switch (reason) { + case CONFIG_CMD_ENABLE: + // filter out duplicated enable + if (mSensorState[handle].desiredTSample != INT64_MAX) { + break; + } + // fall through + case CONFIG_CMD_FLUSH: { + constexpr uint64_t PERIOD_800HZ = 1250000; + uint64_t period_multiplier = + (frequency_q10_to_period_ns(mSensorState[handle].rate) + PERIOD_800HZ / 2) + / PERIOD_800HZ; + uint64_t desiredTSample = PERIOD_800HZ; + while (period_multiplier /= 2) { + desiredTSample *= 2; + } + mSensorState[handle].desiredTSample = desiredTSample; + ALOGV("DesiredTSample for handle 0x%x set to %" PRIu64, handle, desiredTSample); + break; + } + case CONFIG_CMD_DISABLE: + mSensorState[handle].desiredTSample = INT64_MAX; + ALOGV("DesiredTSample 0x%x set to disable", handle); + break; + default: + ALOGW("%s: unexpected reason = %d, no-op", __FUNCTION__, reason); + break; + } +} + +bool HubConnection::isSampleIntervalSatisfied(int handle, uint64_t timestamp) { + if (mSensorToChannel.find(handle) == mSensorToChannel.end()) { + return true; + } + + if (mSensorState[handle].lastTimestamp >= timestamp + || mSensorState[handle].desiredTSample == INT64_MAX) { + return false; + } else if (intervalLargeEnough(timestamp - mSensorState[handle].lastTimestamp, + mSensorState[handle].desiredTSample)) { + mSensorState[handle].lastTimestamp = timestamp; + return true; + } else { + return false; + } +} + +uint64_t HubConnection::rateLevelToDeviceSamplingPeriodNs(int handle, int rateLevel) const { + if (mSensorToChannel.find(handle) == mSensorToChannel.end()) { + return INT64_MAX; + } + + switch (rateLevel) { + case SENSOR_DIRECT_RATE_VERY_FAST: + // No sensor support VERY_FAST, fall through + case SENSOR_DIRECT_RATE_FAST: + if (handle != COMMS_SENSOR_MAG && handle != COMMS_SENSOR_MAG_UNCALIBRATED) { + return 2500*1000; // 400Hz + } + // fall through + case SENSOR_DIRECT_RATE_NORMAL: + return 20*1000*1000; // 50 Hz + // fall through + default: + return INT64_MAX; + } +} #else // DIRECT_REPORT_ENABLED // nop functions if feature is turned off int HubConnection::addDirectChannel(const struct sensors_direct_mem_t *) { @@ -2175,6 +2297,13 @@ void HubConnection::mergeDirectReportRequest(struct ConfigCmd *, int) { bool HubConnection::isDirectReportSupported() const { return false; } + +void HubConnection::updateSampleRate(int, int) { +} + +bool HubConnection::isSampleIntervalSatisfied(int, uint64_t) { + return true; +} #endif // DIRECT_REPORT_ENABLED } // namespace android diff --git a/sensorhal/hubconnection.h b/sensorhal/hubconnection.h index 3f0a4f9c..7be18aec 100644 --- a/sensorhal/hubconnection.h +++ b/sensorhal/hubconnection.h @@ -173,6 +173,8 @@ private: struct SensorState { uint64_t latency; + uint64_t lastTimestamp; + uint64_t desiredTSample; rate_q10_t rate; uint8_t sensorType; uint8_t primary; @@ -329,12 +331,24 @@ public: private: void sendDirectReportEvent(const sensors_event_t *nev, size_t n); void mergeDirectReportRequest(struct ConfigCmd *cmd, int handle); + bool isSampleIntervalSatisfied(int handle, uint64_t timestamp); + void updateSampleRate(int handle, int reason); #ifdef DIRECT_REPORT_ENABLED int stopAllDirectReportOnChannel( int channel_handle, std::vector<int32_t> *unstoppedSensors); + uint64_t rateLevelToDeviceSamplingPeriodNs(int handle, int rateLevel) const; + inline static bool intervalLargeEnough(uint64_t actual, uint64_t desired) { + return (actual + (actual >> 4)) >= desired; // >= 94.11% of desired + } + + struct DirectChannelTimingInfo{ + uint64_t lastTimestamp; + int rateLevel; + }; Mutex mDirectChannelLock; - //sensor_handle=>(channel_handle, rate_level) - std::unordered_map<int32_t, std::unordered_map<int32_t, int32_t> > mSensorToChannel; + //sensor_handle=>(channel_handle => DirectChannelTimingInfo) + std::unordered_map<int32_t, + std::unordered_map<int32_t, DirectChannelTimingInfo> > mSensorToChannel; //channel_handle=>ptr of Channel obj std::unordered_map<int32_t, std::unique_ptr<DirectChannelBase>> mDirectChannel; int32_t mDirectChannelHandle; |