/******************************************************************************* ** ** Function bta_av_co_audio_peer_supports_codec ** ** Description Check if a connection supports the codec config ** ** Returns TRUE if the connection supports this codec, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index) { int index; UINT8 codec_type; FUNC_TRACE(); /* Configure the codec type to look for */ codec_type = bta_av_co_cb.codec_cfg.id; for (index = 0; index < p_peer->num_sup_snks; index++) { if (p_peer->snks[index].codec_type == codec_type) { switch (bta_av_co_cb.codec_cfg.id) { case BTIF_AV_CODEC_SBC: if (p_snk_index) *p_snk_index = index; return bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps); break; default: APPL_TRACE_ERROR1("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg.id); return FALSE; break; } } } return FALSE; }
/******************************************************************************* ** ** Function bta_av_co_audio_disc_res ** ** Description This callout function is executed by AV to report the ** number of stream end points (SEP) were found during the ** AVDT stream discovery process. ** ** ** Returns void. ** *******************************************************************************/ BTA_API void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk, BD_ADDR addr) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); APPL_TRACE_DEBUG3("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d", hndl, num_seps, num_snk); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR0("bta_av_co_audio_disc_res could not find peer entry"); return; } /* Sanity check : this should never happen */ if (p_peer->opened) { APPL_TRACE_ERROR0("bta_av_co_audio_disc_res peer already opened"); } /* Copy the discovery results */ bdcpy(p_peer->addr, addr); p_peer->num_snks = num_snk; p_peer->num_seps = num_seps; p_peer->num_rx_snks = 0; p_peer->num_sup_snks = 0; }
void TransactionBase::ReDestructAll() { FUNC_TRACE(uin_); ReDestruct(); ReDestructBase(); }
/******************************************************************************* ** ** Function bta_av_co_audio_peer_reset_config ** ** Description Reset the peer codec configuration ** ** Returns Nothing ** *******************************************************************************/ static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer) { FUNC_TRACE(); /* Indicate that there is no currently selected sink */ p_peer->p_snk = NULL; }
/******************************************************************************* ** ** Function bta_av_co_peer_cp_supported ** ** Description Checks if the peer supports CP ** ** Returns TRUE if the peer supports CP ** *******************************************************************************/ BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl) { tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_sink; UINT8 index; FUNC_TRACE(); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR0("bta_av_co_peer_cp_supported could not find peer entry"); return FALSE; } for (index = 0; index < p_peer->num_sup_snks; index++) { p_sink = &p_peer->snks[index]; if (p_sink->codec_type == A2D_MEDIA_CT_SBC) { return bta_av_co_audio_sink_has_scmst(p_sink); } } APPL_TRACE_ERROR0("bta_av_co_peer_cp_supported did not find SBC sink"); return FALSE; }
/******************************************************************************* ** ** Function bta_av_co_audio_codec_build_config ** ** Description Build the codec configuration ** ** Returns TRUE if the codec was built successfully, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg) { FUNC_TRACE(); memset(p_codec_cfg, 0, AVDT_CODEC_SIZE); switch (bta_av_co_cb.codec_cfg.id) { case BTIF_AV_CODEC_SBC: /* only copy the relevant portions for this codec to avoid issues when comparing codec configs covering larger codec sets than SBC (7 bytes) */ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg.info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF+1); /* Update the bit pool boundaries with the codec capabilities */ p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; APPL_TRACE_EVENT2("bta_av_co_audio_codec_build_config : bitpool min %d, max %d", p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); break; default: APPL_TRACE_ERROR1("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg.id); return FALSE; break; } return TRUE; }
/******************************************************************************* ** ** Function bta_av_co_audio_start ** ** Description This function is called by AV when the audio streaming data ** transfer is started. ** ** ** Returns void ** *******************************************************************************/ BTA_API void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr) { FUNC_TRACE(); APPL_TRACE_DEBUG0("bta_av_co_audio_start"); }
void TransactionBase::ReDestructBase() { FUNC_TRACE(uin_); id_ = 0; uin_ = 0; phase_ = 0; curr_cmd_ = 0; timeout_timer_id_ = 0; }
/** * @brief: 进入下一个阶段 * * @param phase 阶段ID * @param interval_usec 超时时间 * @param waiting_cmd 进入的阶段要等待的CMD */ void TransactionBase::EnterPhase(unsigned int phase, TransactionWaitInterval interval_usec, unsigned int waiting_cmd) { FUNC_TRACE(uin_); SetPhase(phase); SetTimeoutTimer(interval_usec); SetCurrCmd(waiting_cmd); }
int TransactionBase::ProcessTimeout(size_t timer_id) { FUNC_TRACE(uin_); if (timeout_timer_id_ == timer_id) { timeout_timer_id_ = 0; state_ = STATE_TIMEOUT; } return OnEvent(); }
/******************************************************************************* ** ** Function bta_av_co_cp_set_flag ** ** Description Set content protection flag ** BTA_AV_CP_SCMS_COPY_NEVER ** BTA_AV_CP_SCMS_COPY_ONCE ** BTA_AV_CP_SCMS_COPY_FREE ** ** Returns TRUE if setting the SCMS flag is supported else FALSE ** *******************************************************************************/ BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag) { FUNC_TRACE(); #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) #else if (cp_flag != BTA_AV_CP_SCMS_COPY_FREE) { return FALSE; } #endif bta_av_co_cb.cp.flag = cp_flag; return TRUE; }
//XXX: 这几个接口返回值 小于 0 都是退出事务 // 收到第一个消息 // 第一个消息比较特殊,用于创建事务时做一些初始化 int TransactionBase::ProcessFirstFrame(const AppFrame& app_frame) { FUNC_TRACE(uin_); app_frame_ = app_frame; memcpy(&bus_header_, app_frame.bus_header, sizeof(bus_header_)); memcpy(&app_header_, app_frame.app_header, sizeof(app_header_)); // bus_header_ = app_frame.bus_header; // app_header_ = app_frame.app_header; uin_ = app_header_.uiUin; return OnEvent(); }
/******************************************************************************* ** ** Function bta_av_co_audio_codec_reset ** ** Description Reset the current codec configuration ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_codec_reset(void) { GKI_disable(); FUNC_TRACE(); /* Reset the current configuration to SBC */ bta_av_co_cb.codec_cfg.id = BTIF_AV_CODEC_SBC; if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btif_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS) { APPL_TRACE_ERROR0("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed"); } GKI_enable(); }
/******************************************************************************* ** ** Function bta_av_co_audio_sink_supports_cp ** ** Description Check if a sink supports the current content protection ** ** Returns TRUE if the sink supports this CP, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK *p_sink) { FUNC_TRACE(); /* Check if content protection is enabled for this stream */ if (bta_av_co_cp_get_flag() != BTA_AV_CP_SCMS_COPY_FREE) { return bta_av_co_audio_sink_has_scmst(p_sink); } else { APPL_TRACE_DEBUG0("bta_av_co_audio_sink_supports_cp: not required"); return TRUE; } }
/******************************************************************************* ** ** Function bta_av_co_get_peer ** ** Description find the peer entry for a given handle ** ** Returns the control block ** *******************************************************************************/ static tBTA_AV_CO_PEER *bta_av_co_get_peer(tBTA_AV_HNDL hndl) { UINT8 index; FUNC_TRACE(); index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl); /* Sanity check */ if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) { APPL_TRACE_ERROR1("bta_av_co_get_peer peer index out of bounds:%d", index); return NULL; } return &bta_av_co_cb.peers[index]; }
int TransactionBase::SetTimeoutTimer(TransactionWaitInterval interval_usec) { FUNC_TRACE(uin_); SetCurrCmd(0); CancelTimeoutTimer(); int ret = TransactionMgrSigleton::get_mutable_instance().SetTimer(id_, interval_usec, timeout_timer_id_); if (0 != ret) { TNT_LOG_ERROR(0, uin_, "set timer error|%u", id_); return -1; } return 0; }
/******************************************************************************* ** ** Function bta_av_co_audio_discard_config ** ** Description Discard the codec configuration of a connection ** ** Returns Nothing ** *******************************************************************************/ void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR0("bta_av_co_audio_discard_config could not find peer entry"); return; } /* Reset the peer codec configuration */ bta_av_co_audio_peer_reset_config(p_peer); }
/******************************************************************************* ** ** Function bta_av_co_init ** ** Description Initialization ** ** Returns Nothing ** *******************************************************************************/ void bta_av_co_init(void) { FUNC_TRACE(); /* Reset the control block */ memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb)); bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_NEVER); #else bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_FREE); #endif /* Reset the current config */ bta_av_co_audio_codec_reset(); }
/******************************************************************************* ** ** Function bta_av_co_cp_is_scmst ** ** Description Check if a content protection service is SCMS-T ** ** Returns TRUE if this CP is SCMS-T, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo) { UINT16 cp_id; FUNC_TRACE(); if (*p_protectinfo >= BTA_AV_CP_LOSC) { p_protectinfo++; STREAM_TO_UINT16(cp_id, p_protectinfo); if (cp_id == BTA_AV_CP_SCMS_T_ID) { APPL_TRACE_DEBUG0("bta_av_co_cp_is_scmst: SCMS-T found"); return TRUE; } } return FALSE; }
/******************************************************************************* ** ** Function bta_av_co_audio_init ** ** Description This callout function is executed by AV when it is ** started by calling BTA_AvRegister(). This function can be ** used by the phone to initialize audio paths or for other ** initialization purposes. ** ** ** Returns Stream codec and content protection capabilities info. ** *******************************************************************************/ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index) { FUNC_TRACE(); APPL_TRACE_DEBUG1("bta_av_co_audio_init: %d", index); #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) { UINT8 *p = p_protect_info; /* Content protection info - support SCMS-T */ *p_num_protect = 1; *p++ = BTA_AV_CP_LOSC; UINT16_TO_STREAM(p, BTA_AV_CP_SCMS_T_ID); } #else /* By default - no content protection info */ *p_num_protect = 0; *p_protect_info = 0; #endif /* reset remote preference through setconfig */ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; switch (index) { case BTIF_SV_AV_AA_SBC_INDEX: /* Set up for SBC codec */ *p_codec_type = BTA_AV_CODEC_SBC; /* This should not fail because we are using constants for parameters */ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info); /* Codec is valid */ return TRUE; default: /* Not valid */ return FALSE; } }
/******************************************************************************* ** ** Function bta_av_co_audio_src_data_path ** ** Description This function is called to manage data transfer from ** the audio codec to AVDTP. ** ** Returns Pointer to the GKI buffer to send, NULL if no buffer to send ** *******************************************************************************/ BTA_API void * bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, UINT32 *p_len, UINT32 *p_timestamp) { BT_HDR *p_buf; FUNC_TRACE(); p_buf = btif_media_aa_readbuf(); if (p_buf != NULL) { switch (codec_type) { case BTA_AV_CODEC_SBC: /* In media packet SBC, the following information is available: * p_buf->layer_specific : number of SBC frames in the packet * p_buf->word[0] : timestamp */ /* Retrieve the timestamp information from the media packet */ *p_timestamp = *((UINT32 *) (p_buf + 1)); /* Set up packet header */ bta_av_sbc_bld_hdr(p_buf, p_buf->layer_specific); break; default: APPL_TRACE_ERROR1("bta_av_co_audio_src_data_path Unsupported codec type (%d)", codec_type); break; } #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) { UINT8 *p; if (bta_av_co_cp_is_active()) { p_buf->len++; p_buf->offset--; p = (UINT8 *)(p_buf + 1) + p_buf->offset; *p = bta_av_co_cp_get_flag(); } } #endif } return p_buf; }
int TransactionBase::CancelTimeoutTimer() { FUNC_TRACE(uin_); if (0 == timeout_timer_id_) { return 0; } int ret = TransactionMgrSigleton::get_mutable_instance().CancelTimer(timeout_timer_id_); if (0 != ret) { TNT_LOG_ERROR(0, uin_, "cancel timer error|%u|%lu", id_, timeout_timer_id_); return -1; } timeout_timer_id_ = 0; return 0; }
/******************************************************************************* ** ** Function bta_av_co_audio_media_supports_config ** ** Description Check if the media source supports a given configuration ** ** Returns TRUE if the media source supports this config, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) { FUNC_TRACE(); switch (codec_type) { case BTA_AV_CODEC_SBC: if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps)) { return FALSE; } break; default: APPL_TRACE_ERROR1("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); return FALSE; break; } return TRUE; }
/******************************************************************************* ** ** Function bta_av_co_audio_open ** ** Description This function is called by AV when the audio stream connection ** is opened. ** ** ** Returns void ** *******************************************************************************/ BTA_API void bta_av_co_audio_open(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT16 mtu) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); APPL_TRACE_DEBUG2("bta_av_co_audio_open mtu:%d codec_type:%d", mtu, codec_type); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR0("bta_av_co_audio_setconfig could not find peer entry"); } else { p_peer->opened = TRUE; p_peer->mtu = mtu; } }
// 重新构造 // 因为对象是一直存在的,所以再次使用需要初始化 // 另外由于子类数据也有可能需要初始化, 为了避免子类重载该函数后 // 忘记调用基类的方法,所以将基类和子类的函数分开 void TransactionBase::ReConstructBase() { FUNC_TRACE(uin_); static unsigned int trans_id_generator_ = TransactionMgrSigleton::get_const_instance().trans_id_begin_; ++trans_id_generator_; if (0 == trans_id_generator_) { ++trans_id_generator_; } id_ = trans_id_generator_; state_ = STATE_AWAKE; TNT_LOG_DEBUG(0, 0, "%u|%u", id_, trans_id_generator_); return; }
/******************************************************************************* ** ** Function bta_av_co_audio_codec_cfg_matches_caps ** ** Description Check if a codec config matches a codec capabilities ** ** Returns TRUE if it codec config is supported, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_codec_cfg_matches_caps(UINT8 codec_id, const UINT8 *p_codec_caps, const UINT8 *p_codec_cfg) { FUNC_TRACE(); switch(codec_id) { case BTIF_AV_CODEC_SBC: APPL_TRACE_EVENT4("bta_av_co_audio_codec_cfg_matches_caps : min %d/%d max %d/%d", p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); /* Must match all items exactly except bitpool boundaries which can be adjusted */ if (!((p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF] & p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF]) && (p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF] & p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]))) { APPL_TRACE_EVENT4("FALSE %x %x %x %x", p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF], p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF], p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF], p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]); return FALSE; } break; default: APPL_TRACE_ERROR1("bta_av_co_audio_codec_cfg_matches_caps: unsupported codec id %d", codec_id); return FALSE; break; } APPL_TRACE_EVENT0("TRUE"); return TRUE; }
/******************************************************************************* ** ** Function bta_av_co_audio_close ** ** Description This function is called by AV when the audio stream connection ** is closed. ** ** ** Returns void ** *******************************************************************************/ BTA_API void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); APPL_TRACE_DEBUG0("bta_av_co_audio_close"); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer) { /* Mark the peer closed and clean the peer info */ memset(p_peer, 0, sizeof(*p_peer)); } else { APPL_TRACE_ERROR0("bta_av_co_audio_close could not find peer entry"); } /* reset remote preference through setconfig */ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; }
// 收到其他消息 int TransactionBase::ProcessOtherFrame(const AppFrame& app_frame) { FUNC_TRACE(uin_); // 检查是否是期望的CMD // 为了和之前的兼容,这里如果没有设置curr_cmd_,则设置一下 if (GetCurrCmd() == 0) { SetCurrCmd(app_frame.app_header->ushCmdID); } else if (GetCurrCmd() != app_frame.app_header->ushCmdID) { TNT_LOG_WARN(0, uin_, "not waiting cmd|0X%08X|0X%08X", GetCurrCmd(), app_frame.app_header->ushCmdID); return -1; } app_frame_ = app_frame; memcpy(&bus_header_, app_frame.bus_header, sizeof(bus_header_)); memcpy(&app_header_, app_frame.app_header, sizeof(app_header_)); return OnEvent(); }
/******************************************************************************* ** ** Function bta_av_co_audio_sink_has_scmst ** ** Description Check if a sink supports SCMS-T ** ** Returns TRUE if the sink supports this CP, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink) { UINT8 index; const UINT8 *p; FUNC_TRACE(); /* Check if sink supports SCMS-T */ index = p_sink->num_protect; p = &p_sink->protect_info[0]; while (index) { if (bta_av_co_cp_is_scmst(p)) { return TRUE; } /* Move to the next SC */ p += *p + 1; /* Decrement the SC counter */ index--; } APPL_TRACE_DEBUG0("bta_av_co_audio_sink_has_scmst: SCMS-T not found"); return FALSE; }
/** * @brief: 状态机输入 * * @return: < 0 退出事务 */ int TransactionBase::OnEvent() { FUNC_TRACE(uin_); // 取消定时器 CancelTimeoutTimer(); int ret = 0; TransactionReturn trans_ret = RETURN_EXIT; // 2012-06-15 // 决定在这里加个异常扑捉,虽然不建议在代码中使用异常 // 但是确实没有想到比异常更合适的办法 // 因为子类是未知的,子类的实现也是未知的 // 无法保证每一个实现都是严谨的 // // 不过发生异常时是应该让程序继续呢还是果断退出? // try { switch (state_) { case STATE_AWAKE: { trans_ret = OnAwake(); break; } case STATE_ACTIVE: { trans_ret = OnActive(); break; } case STATE_TIMEOUT: { trans_ret = OnTimeout(); break; } default: { TNT_LOG_ERROR(0, uin_, "error state %u", state_); } } } catch (std::exception& e) { TNT_LOG_ERROR(0, uin_, "exception|0X%08X|%u|%u|%u|%s", cmd_, id_, state_, phase_, e.what()); // 让这个事务退出吧。。。 trans_ret = RETURN_EXIT; } switch (trans_ret) { case RETURN_WAIT: { if (0 == timeout_timer_id_) { //2013-08-19, jamey //进入等待却又忘了设置时间, 还是让其退出吧 state_ = STATE_IDLE; TNT_LOG_DEBUG(0, uin(), "no timer trans exit|%u|%u", id(), cmd()); TransactionMgrSigleton::get_mutable_instance().FreeTransaction(this); } else { state_ = STATE_ACTIVE; } break; } case RETURN_CONTINUE: { state_ = STATE_ACTIVE; return OnEvent(); } case RETURN_EXIT: { state_ = STATE_IDLE; TNT_LOG_DEBUG(0, uin(), "trans exit|%u|%u", id(), cmd()); TransactionMgrSigleton::get_mutable_instance().FreeTransaction(this); // ret = -1; break; } } return ret; }