freeswitch/libs/unimrcp/platforms/umc/src/verifiersession.cpp

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;
}