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

285 lines
8.0 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: synthsession.cpp 1586 2010-03-12 19:39:02Z achaloyan $
*/
#include "synthsession.h"
#include "synthscenario.h"
#include "mrcp_message.h"
#include "mrcp_generic_header.h"
#include "mrcp_synth_header.h"
#include "mrcp_synth_resource.h"
struct SynthChannel
{
/** MRCP channel */
mrcp_channel_t* m_pMrcpChannel;
/** IN-PROGRESS SPEAK request */
mrcp_message_t* m_pSpeakRequest;
/** File to write audio stream to */
FILE* m_pAudioOut;
SynthChannel() : m_pMrcpChannel(NULL), m_pSpeakRequest(NULL), m_pAudioOut(NULL) {}
};
SynthSession::SynthSession(const SynthScenario* pScenario) :
UmcSession(pScenario),
m_pSynthChannel(NULL)
{
}
SynthSession::~SynthSession()
{
}
bool SynthSession::Start()
{
if(!GetScenario()->IsSpeakEnabled())
return false;
/* create channel and associate all the required data */
m_pSynthChannel = CreateSynthChannel();
if(!m_pSynthChannel)
return false;
/* add channel to session (send asynchronous request) */
if(!AddMrcpChannel(m_pSynthChannel->m_pMrcpChannel))
{
delete m_pSynthChannel;
m_pSynthChannel = NULL;
return false;
}
return true;
}
bool SynthSession::Stop()
{
if(!UmcSession::Stop())
return false;
if(!m_pSynthChannel)
return false;
mrcp_message_t* pStopMessage = CreateMrcpMessage(m_pSynthChannel->m_pMrcpChannel,SYNTHESIZER_STOP);
if(!pStopMessage)
return false;
if(m_pSynthChannel->m_pSpeakRequest)
{
mrcp_generic_header_t* pGenericHeader;
/* get/allocate generic header */
pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pStopMessage);
if(pGenericHeader)
{
pGenericHeader->active_request_id_list.count = 1;
pGenericHeader->active_request_id_list.ids[0] =
m_pSynthChannel->m_pSpeakRequest->start_line.request_id;
mrcp_generic_header_property_add(pStopMessage,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
}
m_pSynthChannel->m_pSpeakRequest = NULL;
}
return SendMrcpRequest(m_pSynthChannel->m_pMrcpChannel,pStopMessage);
}
bool SynthSession::OnSessionTerminate(mrcp_sig_status_code_e status)
{
if(m_pSynthChannel)
{
FILE* pAudioOut = m_pSynthChannel->m_pAudioOut;
if(pAudioOut)
{
m_pSynthChannel->m_pAudioOut = NULL;
fclose(pAudioOut);
}
delete m_pSynthChannel;
m_pSynthChannel = NULL;
}
return UmcSession::OnSessionTerminate(status);
}
static apt_bool_t WriteStream(mpf_audio_stream_t* pStream, const mpf_frame_t* pFrame)
{
SynthChannel* pSynthChannel = (SynthChannel*) pStream->obj;
if(pSynthChannel && pSynthChannel->m_pAudioOut)
{
fwrite(pFrame->codec_frame.buffer,1,pFrame->codec_frame.size,pSynthChannel->m_pAudioOut);
}
return TRUE;
}
SynthChannel* SynthSession::CreateSynthChannel()
{
mrcp_channel_t* pChannel;
mpf_termination_t* pTermination;
mpf_stream_capabilities_t* pCapabilities;
apr_pool_t* pool = GetSessionPool();
/* create channel */
SynthChannel* pSynthChannel = new SynthChannel;
/* create sink stream capabilities */
pCapabilities = mpf_sink_stream_capabilities_create(pool);
GetScenario()->InitCapabilities(pCapabilities);
static const mpf_audio_stream_vtable_t audio_stream_vtable =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
WriteStream
};
pTermination = CreateAudioTermination(
&audio_stream_vtable, /* virtual methods table of audio stream */
pCapabilities, /* capabilities of audio stream */
pSynthChannel); /* object to associate */
pChannel = CreateMrcpChannel(
MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
pTermination, /* media termination, used to terminate audio stream */
NULL, /* RTP descriptor, used to create RTP termination (NULL by default) */
pSynthChannel); /* object to associate */
if(!pChannel)
{
delete pSynthChannel;
return NULL;
}
pSynthChannel->m_pMrcpChannel = pChannel;
return pSynthChannel;
}
bool SynthSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
{
if(!UmcSession::OnChannelAdd(pMrcpChannel,status))
return false;
SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel);
if(status != MRCP_SIG_STATUS_CODE_SUCCESS)
{
/* error case, just terminate the demo */
return Terminate();
}
/* create MRCP message */
mrcp_message_t* pMrcpMessage = CreateSpeakRequest(pMrcpChannel);
if(pMrcpMessage)
{
SendMrcpRequest(pSynthChannel->m_pMrcpChannel,pMrcpMessage);
}
const mpf_codec_descriptor_t* pDescriptor = mrcp_application_sink_descriptor_get(pMrcpChannel);
pSynthChannel->m_pAudioOut = GetAudioOut(pDescriptor,GetSessionPool());
return true;
}
bool SynthSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
{
if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage))
return false;
if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE)
{
/* received MRCP response */
if(pMrcpMessage->start_line.method_id == SYNTHESIZER_SPEAK)
{
/* received the response to SPEAK request */
if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS)
{
SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel);
if(pSynthChannel)
pSynthChannel->m_pSpeakRequest = GetMrcpMessage();
/* waiting for SPEAK-COMPLETE event */
}
else
{
/* received unexpected response, terminate the session */
Terminate();
}
}
else
{
/* received unexpected response */
}
}
else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT)
{
/* received MRCP event */
if(pMrcpMessage->start_line.method_id == SYNTHESIZER_SPEAK_COMPLETE)
{
SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel);
if(pSynthChannel)
pSynthChannel->m_pSpeakRequest = NULL;
/* received SPEAK-COMPLETE event, terminate the session */
Terminate();
}
}
return true;
}
mrcp_message_t* SynthSession::CreateSpeakRequest(mrcp_channel_t* pMrcpChannel)
{
mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,SYNTHESIZER_SPEAK);
if(!pMrcpMessage)
return NULL;
const SynthScenario* pScenario = GetScenario();
mrcp_generic_header_t* pGenericHeader;
mrcp_synth_header_t* pSynthHeader;
/* get/allocate generic header */
pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pMrcpMessage);
if(pGenericHeader)
{
/* set generic header fields */
apt_string_assign(&pGenericHeader->content_type,pScenario->GetContentType(),pMrcpMessage->pool);
mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_TYPE);
/* set message body */
if(pScenario->GetContent())
apt_string_assign(&pMrcpMessage->body,pScenario->GetContent(),pMrcpMessage->pool);
}
/* get/allocate synthesizer header */
pSynthHeader = (mrcp_synth_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
if(pSynthHeader)
{
/* set synthesizer header fields */
pSynthHeader->voice_param.age = 28;
mrcp_resource_header_property_add(pMrcpMessage,SYNTHESIZER_HEADER_VOICE_AGE);
}
return pMrcpMessage;
}
FILE* SynthSession::GetAudioOut(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const
{
char* pFileName = apr_psprintf(pool,"synth-%dkHz-%s.pcm",
pDescriptor ? pDescriptor->sampling_rate/1000 : 8, GetMrcpSessionId());
apt_dir_layout_t* pDirLayout = GetScenario()->GetDirLayout();
char* pFilePath = apt_datadir_filepath_get(pDirLayout,pFileName,pool);
if(!pFilePath)
return NULL;
return fopen(pFilePath,"wb");
}