mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-12 20:27:19 +00:00
390 lines
11 KiB
C++
390 lines
11 KiB
C++
/*
|
|
* Copyright 2008-2010 Arsen Chaloyan
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* $Id: verifiersession.cpp 1778 2010-08-27 17:34:52Z achaloyan $
|
|
*/
|
|
|
|
#include "verifiersession.h"
|
|
#include "verifierscenario.h"
|
|
#include "mrcp_message.h"
|
|
#include "mrcp_generic_header.h"
|
|
#include "mrcp_verifier_header.h"
|
|
#include "mrcp_verifier_resource.h"
|
|
#include "apt_nlsml_doc.h"
|
|
#include "apt_log.h"
|
|
|
|
struct VerifierChannel
|
|
{
|
|
/** MRCP control channel */
|
|
mrcp_channel_t* m_pMrcpChannel;
|
|
/** IN-PROGRESS VERIFY request */
|
|
mrcp_message_t* m_pVerificationRequest;
|
|
/** Streaming is in-progress */
|
|
bool m_Streaming;
|
|
/** File to read audio stream from */
|
|
FILE* m_pAudioIn;
|
|
/** Estimated time to complete (used if no audio_in available) */
|
|
apr_size_t m_TimeToComplete;
|
|
|
|
VerifierChannel() :
|
|
m_pMrcpChannel(NULL),
|
|
m_pVerificationRequest(NULL),
|
|
m_Streaming(false),
|
|
m_pAudioIn(NULL),
|
|
m_TimeToComplete(0) {}
|
|
};
|
|
|
|
VerifierSession::VerifierSession(const VerifierScenario* pScenario) :
|
|
UmcSession(pScenario),
|
|
m_pVerifierChannel(NULL),
|
|
m_ContentId("request1@form-level")
|
|
{
|
|
}
|
|
|
|
VerifierSession::~VerifierSession()
|
|
{
|
|
}
|
|
|
|
bool VerifierSession::Start()
|
|
{
|
|
/* create channel and associate all the required data */
|
|
m_pVerifierChannel = CreateVerifierChannel();
|
|
if(!m_pVerifierChannel)
|
|
return false;
|
|
|
|
/* add channel to session (send asynchronous request) */
|
|
if(!AddMrcpChannel(m_pVerifierChannel->m_pMrcpChannel))
|
|
{
|
|
delete m_pVerifierChannel;
|
|
m_pVerifierChannel = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool VerifierSession::Stop()
|
|
{
|
|
if(!UmcSession::Stop())
|
|
return false;
|
|
|
|
if(!m_pVerifierChannel)
|
|
return false;
|
|
|
|
mrcp_message_t* pStopMessage = CreateMrcpMessage(m_pVerifierChannel->m_pMrcpChannel,VERIFIER_STOP);
|
|
if(!pStopMessage)
|
|
return false;
|
|
|
|
return SendMrcpRequest(m_pVerifierChannel->m_pMrcpChannel,pStopMessage);
|
|
}
|
|
|
|
bool VerifierSession::OnSessionTerminate(mrcp_sig_status_code_e status)
|
|
{
|
|
if(m_pVerifierChannel)
|
|
{
|
|
FILE* pAudioIn = m_pVerifierChannel->m_pAudioIn;
|
|
if(pAudioIn)
|
|
{
|
|
m_pVerifierChannel->m_pAudioIn = NULL;
|
|
fclose(pAudioIn);
|
|
}
|
|
|
|
delete m_pVerifierChannel;
|
|
m_pVerifierChannel = NULL;
|
|
}
|
|
return UmcSession::OnSessionTerminate(status);
|
|
}
|
|
|
|
static apt_bool_t ReadStream(mpf_audio_stream_t* pStream, mpf_frame_t* pFrame)
|
|
{
|
|
VerifierChannel* pVerifierChannel = (VerifierChannel*) pStream->obj;
|
|
if(pVerifierChannel && pVerifierChannel->m_Streaming)
|
|
{
|
|
if(pVerifierChannel->m_pAudioIn)
|
|
{
|
|
if(fread(pFrame->codec_frame.buffer,1,pFrame->codec_frame.size,pVerifierChannel->m_pAudioIn) == pFrame->codec_frame.size)
|
|
{
|
|
/* normal read */
|
|
pFrame->type |= MEDIA_FRAME_TYPE_AUDIO;
|
|
}
|
|
else
|
|
{
|
|
/* file is over */
|
|
pVerifierChannel->m_Streaming = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* fill with silence in case no file available */
|
|
if(pVerifierChannel->m_TimeToComplete >= CODEC_FRAME_TIME_BASE)
|
|
{
|
|
pFrame->type |= MEDIA_FRAME_TYPE_AUDIO;
|
|
memset(pFrame->codec_frame.buffer,0,pFrame->codec_frame.size);
|
|
pVerifierChannel->m_TimeToComplete -= CODEC_FRAME_TIME_BASE;
|
|
}
|
|
else
|
|
{
|
|
pVerifierChannel->m_Streaming = false;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
VerifierChannel* VerifierSession::CreateVerifierChannel()
|
|
{
|
|
mrcp_channel_t* pChannel;
|
|
mpf_termination_t* pTermination;
|
|
mpf_stream_capabilities_t* pCapabilities;
|
|
apr_pool_t* pool = GetSessionPool();
|
|
|
|
/* create channel */
|
|
VerifierChannel* pVerifierChannel = new VerifierChannel;
|
|
|
|
/* create source stream capabilities */
|
|
pCapabilities = mpf_source_stream_capabilities_create(pool);
|
|
GetScenario()->InitCapabilities(pCapabilities);
|
|
|
|
static const mpf_audio_stream_vtable_t audio_stream_vtable =
|
|
{
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
ReadStream,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
pTermination = CreateAudioTermination(
|
|
&audio_stream_vtable, /* virtual methods table of audio stream */
|
|
pCapabilities, /* capabilities of audio stream */
|
|
pVerifierChannel); /* object to associate */
|
|
|
|
pChannel = CreateMrcpChannel(
|
|
MRCP_VERIFIER_RESOURCE, /* MRCP resource identifier */
|
|
pTermination, /* media termination, used to terminate audio stream */
|
|
NULL, /* RTP descriptor, used to create RTP termination (NULL by default) */
|
|
pVerifierChannel); /* object to associate */
|
|
if(!pChannel)
|
|
{
|
|
delete pVerifierChannel;
|
|
return NULL;
|
|
}
|
|
|
|
pVerifierChannel->m_pMrcpChannel = pChannel;
|
|
return pVerifierChannel;
|
|
}
|
|
|
|
bool VerifierSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
|
|
{
|
|
if(!UmcSession::OnChannelAdd(pMrcpChannel,status))
|
|
return false;
|
|
|
|
if(status != MRCP_SIG_STATUS_CODE_SUCCESS)
|
|
{
|
|
/* error case, just terminate the demo */
|
|
return Terminate();
|
|
}
|
|
|
|
return StartVerification(pMrcpChannel);
|
|
}
|
|
|
|
bool VerifierSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
|
|
{
|
|
if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage))
|
|
return false;
|
|
|
|
VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel);
|
|
if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE)
|
|
{
|
|
/* received MRCP response */
|
|
if(pMrcpMessage->start_line.method_id == VERIFIER_START_SESSION)
|
|
{
|
|
/* received the response to START-SESSION request */
|
|
/* create and send VERIFY request */
|
|
mrcp_message_t* pMrcpMessage = CreateVerificationRequest(pMrcpChannel);
|
|
if(pMrcpMessage)
|
|
{
|
|
SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage);
|
|
}
|
|
}
|
|
else if(pMrcpMessage->start_line.method_id == VERIFIER_END_SESSION)
|
|
{
|
|
/* received the response to END-SESSION request */
|
|
Terminate();
|
|
}
|
|
else if(pMrcpMessage->start_line.method_id == VERIFIER_VERIFY)
|
|
{
|
|
/* received the response to VERIFY request */
|
|
if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS)
|
|
{
|
|
VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel);
|
|
if(pVerifierChannel)
|
|
pVerifierChannel->m_pVerificationRequest = GetMrcpMessage();
|
|
|
|
/* start to stream the speech to Verify */
|
|
if(pVerifierChannel)
|
|
pVerifierChannel->m_Streaming = true;
|
|
}
|
|
else
|
|
{
|
|
/* create and send END-SESSION request */
|
|
mrcp_message_t* pMrcpMessage = CreateEndSessionRequest(pMrcpChannel);
|
|
if(pMrcpMessage)
|
|
{
|
|
SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* received unexpected response */
|
|
}
|
|
}
|
|
else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT)
|
|
{
|
|
if(pMrcpMessage->start_line.method_id == VERIFIER_VERIFICATION_COMPLETE)
|
|
{
|
|
if(pVerifierChannel)
|
|
pVerifierChannel->m_Streaming = false;
|
|
|
|
VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel);
|
|
if(pVerifierChannel)
|
|
pVerifierChannel->m_pVerificationRequest = NULL;
|
|
|
|
/* create and send END-SESSION request */
|
|
mrcp_message_t* pMrcpMessage = CreateEndSessionRequest(pMrcpChannel);
|
|
if(pMrcpMessage)
|
|
{
|
|
SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage);
|
|
}
|
|
}
|
|
else if(pMrcpMessage->start_line.method_id == VERIFIER_START_OF_INPUT)
|
|
{
|
|
/* received start-of-input, do whatever you need here */
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool VerifierSession::StartVerification(mrcp_channel_t* pMrcpChannel)
|
|
{
|
|
VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel);
|
|
/* create and send Verification request */
|
|
mrcp_message_t* pMrcpMessage = CreateStartSessionRequest(pMrcpChannel);
|
|
if(pMrcpMessage)
|
|
{
|
|
SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage);
|
|
}
|
|
|
|
const mpf_codec_descriptor_t* pDescriptor = mrcp_application_source_descriptor_get(pMrcpChannel);
|
|
pVerifierChannel->m_pAudioIn = GetAudioIn(pDescriptor,GetSessionPool());
|
|
if(!pVerifierChannel->m_pAudioIn)
|
|
{
|
|
/* no audio input availble, set some estimated time to complete instead */
|
|
pVerifierChannel->m_TimeToComplete = 5000; // 5 sec
|
|
}
|
|
return true;
|
|
}
|
|
|
|
mrcp_message_t* VerifierSession::CreateStartSessionRequest(mrcp_channel_t* pMrcpChannel)
|
|
{
|
|
mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,VERIFIER_START_SESSION);
|
|
if(!pMrcpMessage)
|
|
return NULL;
|
|
|
|
mrcp_verifier_header_t* pVerifierHeader;
|
|
|
|
/* get/allocate verifier header */
|
|
pVerifierHeader = (mrcp_verifier_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
|
|
if(pVerifierHeader)
|
|
{
|
|
const VerifierScenario* pScenario = GetScenario();
|
|
const char* pRepositoryURI = pScenario->GetRepositoryURI();
|
|
if(pRepositoryURI)
|
|
{
|
|
apt_string_set(&pVerifierHeader->repository_uri,pRepositoryURI);
|
|
mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_REPOSITORY_URI);
|
|
}
|
|
const char* pVoiceprintIdentifier = pScenario->GetVoiceprintIdentifier();
|
|
if(pVoiceprintIdentifier)
|
|
{
|
|
apt_string_set(&pVerifierHeader->voiceprint_identifier,pVoiceprintIdentifier);
|
|
mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_VOICEPRINT_IDENTIFIER);
|
|
}
|
|
const char* pVerificationMode = pScenario->GetVerificationMode();
|
|
if(pVerificationMode)
|
|
{
|
|
apt_string_set(&pVerifierHeader->verification_mode,pVerificationMode);
|
|
mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_VERIFICATION_MODE);
|
|
}
|
|
}
|
|
return pMrcpMessage;
|
|
}
|
|
|
|
mrcp_message_t* VerifierSession::CreateEndSessionRequest(mrcp_channel_t* pMrcpChannel)
|
|
{
|
|
return CreateMrcpMessage(pMrcpChannel,VERIFIER_END_SESSION);
|
|
}
|
|
|
|
mrcp_message_t* VerifierSession::CreateVerificationRequest(mrcp_channel_t* pMrcpChannel)
|
|
{
|
|
mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,VERIFIER_VERIFY);
|
|
if(!pMrcpMessage)
|
|
return NULL;
|
|
|
|
mrcp_verifier_header_t* pVerifierHeader;
|
|
|
|
/* get/allocate verifier header */
|
|
pVerifierHeader = (mrcp_verifier_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
|
|
if(pVerifierHeader)
|
|
{
|
|
pVerifierHeader->no_input_timeout = 5000;
|
|
mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_NO_INPUT_TIMEOUT);
|
|
pVerifierHeader->start_input_timers = TRUE;
|
|
mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_START_INPUT_TIMERS);
|
|
}
|
|
return pMrcpMessage;
|
|
}
|
|
|
|
FILE* VerifierSession::GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const
|
|
{
|
|
const VerifierScenario* pScenario = GetScenario();
|
|
const char* pVoiceprintIdentifier = pScenario->GetVoiceprintIdentifier();
|
|
if(!pVoiceprintIdentifier)
|
|
{
|
|
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Voiceprint Specified");
|
|
return NULL;
|
|
}
|
|
|
|
const char* pFileName = apr_psprintf(pool,"%s-%dkHz.pcm",
|
|
pVoiceprintIdentifier,
|
|
pDescriptor ? pDescriptor->sampling_rate/1000 : 8);
|
|
apt_dir_layout_t* pDirLayout = pScenario->GetDirLayout();
|
|
const char* pFilePath = apt_datadir_filepath_get(pDirLayout,pFileName,pool);
|
|
if(!pFilePath)
|
|
return NULL;
|
|
|
|
FILE* pFile = fopen(pFilePath,"rb");
|
|
if(!pFile)
|
|
{
|
|
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Cannot Find [%s]",pFilePath);
|
|
return NULL;
|
|
}
|
|
|
|
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source",pFilePath);
|
|
return pFile;
|
|
}
|