/**
 * \brief 超时检测线程
 *
 */
int voice_card_control::timeout_check()
{
	BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "语音通道超时检测线程已开启";
	while (true)
	{
		//既用来休眠100毫秒, 同时用来做 interrupt() 函数的 中断点, 无此函数调用, interrupt() 函数无效		
		boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
		for (size_t i = 0; i < m_trunk_vector.size(); i++)
		{		
			boost::shared_ptr<trunk> trunk = m_trunk_vector.at(i);
			boost::unique_lock<boost::mutex> unique_lock_(trunk->m_trunk_mutex, boost::defer_lock);
			if (trunk->elpased() >= m_timeout_elapse){
				if (!unique_lock_.try_lock())
				{
					continue;
				}
				if (trunk->m_step != TRK_IDLE && trunk->m_call_out_param != nullptr)
				{
					// 如果当前语音卡组件为非响一声挂机, 则m_hungup_by_echo_tone值为false, 在cti_hangUp函数中不会做挂断处理, 所以在此处改值为true
					if (!trunk->m_call_out_param->m_hungup_by_echo_tone){
						trunk->m_call_out_param->m_hungup_by_echo_tone = true;
					}
					BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trunk->m_call_out_param->m_ch_msg->m_procbuffer_msg.transid() << " 语音通道超时, 强制挂断处理, 语音卡通道号 : " << i;
					unique_lock_.unlock();
					cti_hangUp(i, CIA_CALL_FAIL);
				}
			}
		}
	}
}
void voice_card_control::deal_hungup_strategy()
{
	int chID;
	while (true)
	{
		try
		{
			chID = m_sleep_channel_queue.take();
		}
		catch (std::out_of_range)
		{
			boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
			continue;
		}
		boost::shared_ptr<trunk> t = m_trunk_vector.at(chID);
		t->m_trunk_mutex.lock();
		int sleeping_elapse = m_cti_sleeping_elapse - t->elpased();
		if (sleeping_elapse > 0)
		{
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << t->m_transId << " 通道号: " << chID
				<< "触发延迟挂机条件, 开始休眠" << sleeping_elapse << "毫秒";
			boost::this_thread::sleep_for(boost::chrono::milliseconds(sleeping_elapse));
		}
		else
		{
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << t->m_transId << " 通道号: " << chID
				<< "睡个毛, 去干活. 睡眠时间为:" << sleeping_elapse << "毫秒";
		}
		t->m_step = TRK_HUNGUP;
		t->m_trunk_mutex.unlock();
		cti_hangUp(chID, CIA_CALL_SUCCESS);
	}
}
void voice_card_control::deal_hungup_strategy()
{
	int chID;
	while (true)
	{
		try
		{
			chID = m_sleep_channel_queue.take();
		}
		catch (std::out_of_range)
		{
			boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
			continue;
		}
		boost::shared_ptr<trunk> t = m_trunk_vector.at(chID);
		boost::unique_lock<boost::mutex> unique_lock_(t->m_trunk_mutex);
		if (t->m_step != TRK_SLEEP)
		{
			// 重复挂机, 可能因为电话接听等原因此次呼叫已经被挂断
			return;
		}
		std::string trans_id_ = t->m_call_out_param->m_ch_msg->m_procbuffer_msg.transid();
		int sleeping_elapse = m_cti_sleeping_elapse - t->elpased();
		if (sleeping_elapse > 0)
		{
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_ << " 通道号:" << chID
				<< "触发延迟挂机条件, 开始休眠" << sleeping_elapse << "毫秒";
			boost::this_thread::sleep_for(boost::chrono::milliseconds(sleeping_elapse));
		}
		else
		{
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_ << " 通道号:" << chID
				<< "睡个毛, 去干活. 睡眠时间为:" << sleeping_elapse << "毫秒";
		}
		t->m_step = TRK_HUNGUP;
		unique_lock_.unlock();
		cti_hangUp(chID, CIA_CALL_SUCCESS);
	}
}
int voice_card_control::deal_e_proc_auto_dial(int nReference, DWORD dwParam, DWORD dwUser)
{
	int channelID = nReference;
	if (m_trunk_vector.at(channelID)->m_call_out_param == nullptr)
	{
		BOOST_LOG_SEV(cia_g_logger, Critical) << "严重:触发deal_e_proc_auto_dial的通道没有关联呼叫请求对象, 通道号码" << channelID;
		return 1;
	}
	std::string trans_id_ = m_trunk_vector.at(nReference)->m_call_out_param->m_ch_msg->m_procbuffer_msg.transid();
	switch (dwParam)
	{
	case DIAL_STANDBY:	            // 通道空闲,没有执行AutoDial任务
		break;
	case DIAL_DIALING:
	{
		BOOST_LOG_SEV(cia_g_logger, Debug) << "业务流水:" << trans_id_
			<< " DIAL_DIALING 事件: 正在发送被叫号码. 外呼通道号:" << channelID;
		boost::shared_ptr<trunk> t = m_trunk_vector.at(nReference);
		boost::unique_lock<boost::mutex> unique_lock_(t->m_trunk_mutex);
		t->m_step = TRK_CALLOUT_DAIL;
		t->m_callTime.start();
		break;
	}
	case DIAL_ECHOTONE:	            // TUP/ISUP通道:表明驱动程序收到对端交换机的地址齐消息(ACM)
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " 在判断ACM后, 接收到 DIAL_ECHOTONE 事件, 挂机. 通道号码:" << channelID;
		BOOST_LOG_SEV(cia_g_logger, CalloutMsg) << "业务流水:" << trans_id_
			<< " 本次从呼叫到检测振铃, 共用时: " << m_trunk_vector.at(nReference)->elpased();
		{
			boost::shared_ptr<trunk> t = m_trunk_vector.at(nReference);
			if (t->m_step != TRK_CALLOUT_DAIL && t->m_step != TRK_WAIT_CONNECT)
			{
				BOOST_LOG_SEV(cia_g_logger, Critical) << "严重:触发振铃时通道不是TRK_CALLOUT_DAIL 或 TRK_WAIT_CONNECT状态, 通道的状态:"
					<< t->m_step << " 流水号 : " << trans_id_ << "通道号码:" << channelID;
				return 1;
			}
			if (m_use_strategy)
			{
				if (t->elpased() <= m_cti_warning_elapse)
				{
					BOOST_LOG_SEV(cia_g_logger, CalloutMsg) << "业务流水:" << trans_id_ << " 本次呼叫触发延迟策略";
					if (t->m_trunk_mutex.try_lock())
					{
						t->m_step = TRK_SLEEP;
						t->m_trunk_mutex.unlock();
						m_sleep_channel_queue.put(channelID);//放入需要做延迟挂机处理的队列中
					}
					else
					{
						BOOST_LOG_SEV(cia_g_logger, Critical) << "业务流水:" << trans_id_ << "将通道号码放入延迟队列前,尝试改变通道状态, 但试图锁定通道失败";
					}
					return 1;
				}
			}
			cti_hangUp(channelID, CIA_CALL_SUCCESS);
		}
		break;
	case DIAL_NO_DIALTONE:
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " 没有在线路上检测到拨号音,AutoDial 任务失败. 通道号码:" << channelID;
		cti_hangUp(channelID, CIA_CALL_FAIL);
		break;
	case DIAL_BUSYTONE:
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " DIAL_BUSYTONE 事件,被叫用户忙. 依然返回成功, 因为用户已经可以看到验证码, 通道号码:" << channelID;
		cti_hangUp(channelID, CIA_CALL_SUCCESS);
		break;
	case DIAL_ECHO_NOVOICE:	        // 拨号完成后,线路上先是出现了回铃音,然后保持静默。AutoDial任务终止。只适用于模拟中继线通道
	case DIAL_NOVOICE:	            // 拨号完成后,线路上没有检测到回铃音,一直保持静默。AutoDial任务终止。只适用于模拟中继线通道
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " 拨号完成, 线路保持沉默, 通道号码:" << channelID;
		break;
	case DIAL_VOICE:	            // 被叫用户摘机,AutoDial任务完成
	case DIAL_VOICEF1:	            // 被叫用户摘机(检测到F1频率的应答信号),AutoDial任务完成。只适用于模拟中继线通道
	case DIAL_VOICEF2:	            // 被叫用户摘机(检测到F2频率的应答信号),AutoDial任务完成。只适用于模拟中继线通道
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " E_PROC_AutoDial事件,板卡接通挂机, 通道号码:" << channelID;
		cti_hangUp(channelID, CIA_CALL_SUCCESS);
		break;
	case DIAL_NOANSWER:	            // 被叫用户在指定时间内没有摘机,AutoDial失败。不适用于IP卡SIP通道
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " DIAL_NOANSWER 事件,被叫用户在指定时间内没有摘机,AutoDial失败, 通道号码:" << channelID;
		cti_hangUp(channelID, CIA_CALL_FAIL);
		break;
	case DIAL_FAILURE:	            // AutoDial任务失败。失败原因可以通过函数SsmGetAutoDialFailureReason获得
	{
		int fail_reason = SsmGetAutoDialFailureReason(channelID);
		if (fail_reason == ATDL_NULL)
		{
			return 1;
		}
		BOOST_LOG_SEV(cia_g_logger, Critical) << "业务流水:" << trans_id_
			<< " SsmGetAutoDialFailureReason 函数返回错误代码: " << SsmGetAutoDialFailureReason(channelID)
			<< "DIAL_FAILURE 事件, AutoDial失败, 通道号码:" << channelID;
		cti_hangUp(channelID, CIA_CALL_FAIL);
	}
		break;
	case DIAL_INVALID_PHONUM:
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << trans_id_
			<< " 被叫号码无效, 通道号码:" << channelID;
		cti_hangUp(channelID, CIA_CALL_FAIL);
		break;
	case DIAL_SESSION_PROCEEDING:	// IP卡SIP通道收到18X消息(180除外)
	case DIAL_ISDN_PROGRESS:	    // ISDN通道收到对端交换机的PROGRESS消息。详细的消息内容可通过函数SsmISDNGetProgressMsg获得
		BOOST_LOG_SEV(cia_g_logger, Critical) << "业务流水:" << trans_id_
			<< " 触发其他类AutoDial事件, 请注意观察, 通道号码:" << channelID;
		break;
	}
	return 1;
}