void voice_card_control::cti_callout(boost::shared_ptr<cti_call_out_param> cti_call_out_param_)
{
	std::size_t chID;
	ciaMessage& msg_ = cti_call_out_param_->m_ch_msg->m_procbuffer_msg;
	try
	{
		chID = m_channel_queue.take();
	}
	catch (std::out_of_range)
	{
		//BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << msg_.transid() << " 获取通道失败, 通道全部繁忙";
		//继续下一次呼叫
		cti_callout_again(cti_call_out_param_);
		return;
	}
	int ch_state = SsmGetChState(chID);
	if (ch_state != 0 && ch_state != 123) //空闲或本地闭塞
	{
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << msg_.transid() << " , 获取到得通道状态为:" << ch_state << ", 不可用,将此通道重新放回。通道号码:" << chID;
		m_channel_queue.put(chID);
		cti_callout_again(cti_call_out_param_);
		return;
	}
	//BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << msg_.transid() << ", 获取到的通道号码:" << chID;
	SsmSetTxCallerId(chID, msg_.authcode().c_str());
	boost::shared_ptr<trunk> t = m_trunk_vector.at(chID);
	boost::unique_lock<boost::mutex> unique_lock_(t->m_trunk_mutex);
	if (SsmAutoDial(chID, msg_.pn().c_str()) == 0){
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << msg_.transid() << " 已发送请求, 已将此通道对应状态清空, 通道号码:" << chID;				
		t->reset_trunk(cti_call_out_param_);
	}
	else {
		show_error();
		unique_lock_.unlock();
		m_channel_queue.put(chID);
		//上一次呼叫失败,继续呼叫
		if (cti_call_out_param_->m_repeat_call_out)
		{
			cti_call_out_param_->m_repeat_call_out = false;
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << msg_.transid() << "上一次呼叫失败,继续呼叫, 失败原因向上查询SsmGetLastErrMsg";
			cti_callout_again(cti_call_out_param_);
		}
		//已经连续两次呼叫失败, 直接返回失败
		else
		{
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << msg_.transid() << "已经连续两次呼叫失败, 直接返回失败, 失败原因向上查询SsmGetLastErrMsg";
			std::string transid_ = msg_.transid();
			msg_.Clear();
			msg_.set_type(CIA_CALL_RESPONSE);
			msg_.set_transid(transid_);
			msg_.set_status(CIA_CALL_FAIL);
			cti_call_out_param_->m_base_client->do_write(cti_call_out_param_->m_ch_msg);
			return;
		}
	}
}
void voice_card_control::init_cti()
{
	BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "读取语音卡配置文件";
	if (SsmStartCti("ShConfig.ini", "ShIndex.ini") != 0)
	{
		show_error();
		BOOST_LOG_SEV(cia_g_logger, Critical) << "读取语音卡配置文件失败";
		throw std::runtime_error("读取语音卡配置文件失败");
	}
	else{
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "语音卡配置文件读取成功";
	}
	//设置驱动程序抛出事件的模式

	EVENT_SET_INFO EventMode;
	EventMode.dwWorkMode = EVENT_CALLBACK;                               // 事件回调模式
	EventMode.lpHandlerParam = (LPVOID)voice_card_control::cti_callback; // 注册回调函数

	SsmSetEvent(0xffff, -1, true, &EventMode);	                         // 启动事件触发模式

	//如果要在程序中获取SS7消息, 则需要同时注意以下两点
	//配置文件 ShConfig.ini 中, GetMsuOnAutoHandle = 1
	//程序中: SsmSetEvent(E_RCV_Ss7Msu, -1, true, &EventMode);
	SsmSetEvent(E_RCV_Ss7Msu, -1, true, &EventMode);

	BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "正在初始化语音卡通道, 预期耗时10秒";
	while (SsmSearchIdleCallOutCh(160, 0x1E0000) < 0){	                 // 循环等待, 直到能够获取语音卡空闲通道号, 语音卡初始化完毕
		boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
	}
	BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "语音卡通道初始化完毕";
	for (std::size_t i = 0; i < m_numChannelCount; i++){
		m_channel_queue.put(i);
		SsmBlockRemoteCh(i);	                                         // 设置通道远端堵塞(禁止来话,但仍可以呼出)
	}
}
int voice_card_control::cti_hangUp(std::size_t channelID, std::string status)
{
	int retVal = 0;
	boost::shared_ptr<trunk> t = m_trunk_vector.at(channelID);
	boost::unique_lock<boost::mutex> unique_lock_(t->m_trunk_mutex, boost::defer_lock);
	if (!unique_lock_.try_lock())
	{
		BOOST_LOG_SEV(cia_g_logger, Warning) << "cti_hangUp函数尝试锁定通道失败, 放弃挂机, 当前通道Step值为:" << t->m_step;
		return -1;
	}
	else
	{
		switch (t->m_step)
		{
		case TRK_IDLE:
			BOOST_LOG_SEV(cia_g_logger, Warning) << "依据当前通道状态判断可能出现重复挂机, 请在后续版本调查原因, 通道号码:" << channelID;
			return -1;
		case TRK_SLEEP:
			BOOST_LOG_SEV(cia_g_logger, Warning) << "当前通道正在延迟挂机, 通道号码:" << channelID;
			return -1;
		default:
			break;
		}
		if (!t->m_call_out_param->m_hungup_by_echo_tone)
		{
			BOOST_LOG_SEV(cia_g_logger, CalloutMsg) << "由于设置非响一声挂断, 未挂断本次呼叫请求, 等待超时挂断, 通道号码:" << channelID;
			return -1;
		}
		retVal = SsmHangup(channelID);
		if (retVal == -1){
			show_error();
			BOOST_LOG_SEV(cia_g_logger, Warning) << "挂机失败, 请在后续版本调查原因, 通道号码:" << channelID;
		}
		else{
			BOOST_LOG_SEV(cia_g_logger, CalloutMsg) << "已挂断本次呼叫请求, 通道号码:" << channelID;
		}
		ciaMessage& msg_ = t->m_call_out_param->m_ch_msg->m_procbuffer_msg;
		std::string transid_ = msg_.transid();
		msg_.Clear();
		msg_.set_type(CIA_CALL_RESPONSE);
		msg_.set_transid(transid_);
		msg_.set_status(status);
		if (t->m_call_out_param == nullptr)
		{
			BOOST_LOG_SEV(cia_g_logger, Critical) << "严重异常: 挂机时发现客户端socket为空";
		}
		else
		{
			LOG_MSG_QUEUE.put(boost::make_shared<LOG_MSG>(Debug, "呼叫返回数据:\n" + t->m_call_out_param->m_ch_msg->m_procbuffer_msg.DebugString()));
			t->m_call_out_param->m_base_client->do_write(t->m_call_out_param->m_ch_msg);
		}
		t->realseTrunk();
		unique_lock_.unlock();
		m_channel_queue.put(channelID);
	}
	return retVal;
}
void voice_card_control::cti_callout(boost::shared_ptr<cti_call_out_param> cti_call_out_param_)
{
	std::size_t chID;
	try
	{
		chID = m_channel_queue.take();
	}
	catch (std::out_of_range)
	{
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << cti_call_out_param_->m_transId << " 获取通道失败, 通道全部繁忙";
		//继续下一次呼叫
		cti_callout_again(cti_call_out_param_);
		return;
	}
	BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << cti_call_out_param_->m_transId << " 获取到得通道状态为:" << SsmChkAutoDial(chID) << ", 通道号码:" << chID;
	SsmSetTxCallerId(chID, cti_call_out_param_->m_authCode.c_str());
	if (SsmAutoDial(chID, cti_call_out_param_->m_pn.c_str()) == 0){
		BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << cti_call_out_param_->m_transId << " 已发送请求, 已将此通道对应状态清空, 通道号码:" << chID;
		boost::shared_ptr<trunk> t = m_trunk_vector.at(chID);
		boost::unique_lock<boost::mutex> unique_lock_(t->m_trunk_mutex, boost::defer_lock);
		if (unique_lock_.try_lock())
		{
			t->m_client_socket = cti_call_out_param_->m_base_client;
			t->m_transId = cti_call_out_param_->m_transId;
			t->m_caller_id = cti_call_out_param_->m_authCode;
			t->m_called_id = cti_call_out_param_->m_pn;
			t->m_hungup_by_echo_tone = cti_call_out_param_->m_hungup_by_echo_tone;
			t->m_step = TRK_CALLOUT_DAIL;
			t->m_callTime.restart();
		}
		else
		{
			BOOST_LOG_SEV(cia_g_logger, Critical) << "业务流水:" << cti_call_out_param_->m_transId << ", 严重异常, 被分配的语音通道处于占用状态, 请程序猿通宵解决问题";
		}
	}
	else {
		m_channel_queue.put(chID);
		//上一次呼叫失败,继续呼叫
		if (cti_call_out_param_->m_repeat_call_out)
		{
			cti_call_out_param_->m_repeat_call_out = false;
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << cti_call_out_param_->m_transId << "上一次呼叫失败,继续呼叫";
			cti_callout_again(cti_call_out_param_);
		}
		//已经连续两次呼叫失败, 直接返回失败
		else
		{
			BOOST_LOG_SEV(cia_g_logger, RuntimeInfo) << "业务流水:" << cti_call_out_param_->m_transId << "已经连续两次呼叫失败, 直接返回失败";
			ciaMessage msg;
			msg.set_type(CIA_CALL_RESPONSE);
			msg.set_transid(cti_call_out_param_->m_transId);
			msg.set_status(CIA_CALL_FAIL);
			cti_call_out_param_->m_base_client->do_write(chat_message(msg));
			return;
		}
	}
}
int voice_card_control::cti_hangUp(std::size_t channelID, std::string status)
{
	int retVal = 0;
	boost::shared_ptr<trunk> t = m_trunk_vector.at(channelID);
	boost::unique_lock<boost::mutex> unique_lock_(t->m_trunk_mutex, boost::defer_lock);
	if (!unique_lock_.try_lock())
	{
		BOOST_LOG_SEV(cia_g_logger, Warning) << "业务流水:" << t->m_transId << "cti_hangUp函数尝试锁定通道失败, 放弃挂机, 当前通道Step值为:" << t->m_step;
		return -1;
	}
	else
	{
		if (!t->m_hungup_by_echo_tone)
		{
			BOOST_LOG_SEV(cia_g_logger, CalloutMsg) << "业务流水:" << t->m_transId << " 由于设置非响一声挂断, 未挂断本次呼叫请求, 通道号码:" << channelID;
			return -1;
		}
		switch (t->m_step)
		{
		case TRK_IDLE:
			BOOST_LOG_SEV(cia_g_logger, Warning) << "业务流水:" << t->m_transId << " 依据当前通道状态判断可能出现重复挂机, 请在后续版本调查原因, 通道号码:" << channelID;
			return -1;
		case TRK_SLEEP:
			BOOST_LOG_SEV(cia_g_logger, Warning) << "业务流水:" << t->m_transId << " 当前通道正在延迟挂机, 通道号码:" << channelID;
			return -1;
		default:
			break;
		}
		retVal = SsmHangup(channelID);
		if (retVal == -1){
			show_error();
			BOOST_LOG_SEV(cia_g_logger, Warning) << "业务流水:" << t->m_transId << " 挂机失败, 请在后续版本调查原因, 通道号码:" << channelID;
		}
		else{
			BOOST_LOG_SEV(cia_g_logger, CalloutMsg) << "业务流水:" << t->m_transId << " 已挂断本次呼叫请求, 通道号码:" << channelID;
		}
		ciaMessage msg;
		msg.set_type(CIA_CALL_RESPONSE);
		msg.set_transid(t->m_transId);
		msg.set_status(status);
		t->m_client_socket->do_write(chat_message(msg));
		t->realseTrunk();
		m_channel_queue.put(channelID);
	}
	return retVal;
}
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;
}