Author |
|
Jalal Vetran
Joined: April 24 2006 Location: Iran Posts: 188
|
Posted: April 09 2007 at 7:15am | IP Logged
|
|
|
Hi,
1- What sort of wave file is supported by OpenWaveFile API function? Does it support alaw,ulaw or Microsoft ADPCM ? How about different PCM rates?
2- We are using OpenWaveFile to play a wave file using TransmitInCallIvrData just as your samples do. When we read data with GetWaveBuffer what is the exact format of data returned in the buffer by this function? Should we set different audio formats with SetTxIvrDataType to play different wave files?
Regards,
Jalal
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: April 17 2007 at 4:45pm | IP Logged
|
|
|
Hi Jalal,
Item 1:
What sort of wave file is supported by OpenWaveFile API function?
Support >>>
The OpenWaveFile() API proc can open any Windows supported wave file regardless of its rate and format.
However, its usefulness is geared towards an app’s ability to stream wave file sample data to Tx IVR phone line outputs or to the media engine local audio outputs.
Normally source wave file data that is opened and read by the media engine using the OpenWaveFile() and GetWaveBuffer() procs should generally be in aLaw, uLaw or a a PCM format that is supported by the media engine’s Tx IVR phone line outputs or the media engine local audio outputs.
We will update the developer reference to explain this more fully.
Item 2:
When we read data with GetWaveBuffer() what is the exact format of data returned in the buffer by this function?
Support >>>
This API proc reads byte blocks of raw sample data from the wave file. If the source wave file is aLaw or uLaw, then each byte represents one wave file sample. If the source wave file is PCM, then each 2 bytes represents one 16 bit (short) wave file sample.
Item 3:
Should we set different audio formats with SetTxIvrDataType to play different wave files?
Support >>>
Yes. Exactly.
Support
|
Back to Top |
|
|
Jalal Vetran
Joined: April 24 2006 Location: Iran Posts: 188
|
Posted: April 21 2007 at 10:14am | IP Logged
|
|
|
Hi,
So do you agree with this: OpenWaveFile and GetWaveBuffer just open wave files and seek 44 bytes from begin of file (for bypassing the wave header) and read BytesPerWaveBuffer bytes to pDest buffer in each call to GetWaveBuffer. There is no data converstion when reading with GetWaveBuffer.
Regards,
Jalal
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: April 23 2007 at 10:38am | IP Logged
|
|
|
That is correct.
|
Back to Top |
|
|
Jalal Vetran
Joined: April 24 2006 Location: Iran Posts: 188
|
Posted: May 02 2007 at 10:58am | IP Logged
|
|
|
Hi,
In fact this thread started when we encountered a problem playing ulaw music wave files when the call was holded. It started to play the ulaw file fast and noisy. To check we have done everything correct we changed your DualLineIVRServer sample as below. And we replace the greeting.wav file to a ulaw wav file recorded with CoolEdit Pro 2000 (I will send you this wav file directly to your mail). Unfortunately the result was the same as our code result. So noise and fast played file.
Code:
void CDualLineIVRServerDlg::PhoneCallActive(SIPHANDLE hSipEngine, int PhoneLine, LINE_STATE *pLineState)
{
// open a transmit IVR channel so we can stream audio data directly
// to the phone line.
if(OpenTxIvrChannel(hSipEngine ,PhoneLine,0,&(hIvrTransmit[PhoneLine])) == SipSuccess)
{
// set the data type that we will be sending directly to the phone line.
// all IVR wave file data has been recorded using this rate and format.
if(SetTxIvrDataType(hIvrTransmit [PhoneLine],AUDIO_BW_ULAW_8K ) == SipSuccess)
{
// get the number of samples in an ivr buffer.
GetTxIvrSampleBlockSize(
hIvrTransmit[PhoneLine],
AUDIO_BW_ULAW_8K,
&(SamplesPerTxIvrBuffer[PhoneLine]),
&(BytesPerTxIvrBuffer[PhoneLine])
);
// tell the Tx IVR interface to signal our event when he has more transmit buffers.
SetTxIvrBufferEvent(hIvrTransm it[PhoneLine],TransmitBufferAvailable[PhoneLine]);
// wait a second before we start to play the IVR greeting.
Sleep(1000);
// set the greeting state.
IvrState [PhoneLine] = STATE_GREETING;
WavePlay(PhoneLine,WAVE_GREETI NG,TRUE);
// signal that the call is up and we can receive DTMF from
// the phone line.
CallIsActive [PhoneLine] = TRUE;
}
}
}
|
|
|
Please check this issue and report me if we have done something wrong.
Regards,
Jalal
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: May 02 2007 at 12:07pm | IP Logged
|
|
|
Hi Jalal,
The Greeting.wav file image you gave us access to is recorded using 8k mono aLaw sampled data. It is not 8k mono uLaw data.
Here is some code that will help you change your dual line IVR server sample app so it does what you want. Note: After making the changes below, all your dual line IVR server wave files must contain aLaw sampled data.
See the “Dual Line IVR ServerDlg.cpp” module and change the code as shown below.
For changes, see the TEST_JALAL_WAVE_FILE_PLAYBACK macro.
Code:
void CDualLineIVRServerDlg::PhoneCallActive(SIPHANDLE hSipEngine, int PhoneLine, LINE_STATE *pLineState)
{
BOOL IsByteArray;
// open a transmit IVR channel so we can stream audio data directly
// to the phone line.
if(OpenTxIvrChannel(hSipEngine ,PhoneLine,0,&(hIvrTransmit[PhoneLine])) == SipSuccess)
{
// set the data type that we will be sending directly to the phone line.
// all IVR wave file data has been recorded using this rate and format.
#if TEST_JALAL_WAVE_FILE_PLAYBACK
if(SetTxIvrDataType(hIvrTransmit [PhoneLine],AUDIO_BW_ALAW_8K) == SipSuccess)
#else
if(SetTxIvrDataType(hIvrTransmit [PhoneLine],AUDIO_BW_PCM_22K) == SipSuccess)
#endif
{
// get the number of samples in an ivr buffer.
GetTxIvrSampleBlockSize(
hIvrTransmit[PhoneLine],
#if TEST_JALAL_WAVE_FILE_PLAYBACK
AUDIO_BW_ALAW_8K,
#else
AUDIO_BW_PCM_22K,
#endif
&(SamplesPerTxIvrBuffer[PhoneLine]),
&(BytesPerTxIvrBuffer[PhoneLine]),
&IsByteArray
);
// tell the Tx IVR interface to signal our event when he has more transmit buffers.
SetTxIvrBufferEvent(hIvrTransm it[PhoneLine],TransmitBufferAvailable[PhoneLine]);
// wait a second before we start to play the IVR greeting.
Sleep(1000);
// set the greeting state.
IvrState [PhoneLine] = STATE_GREETING;
WavePlay(PhoneLine,WAVE_GREETI NG,TRUE);
// signal that the call is up and we can receive DTMF from
// the phone line.
CallIsActive [PhoneLine] = TRUE;
}
}
}
|
|
|
Code:
//////////////////////////////////////////////////////////// //////////////////////////
//
// This thread is used to stream audio wave file data to the proper phone line.
// The DTMF state threads direct this thread to start and stop particular audio
// playback prompts.
//
//
//////////////////////////////////////////////////////////// //////////////////////////
void PlaybackThreadCallback(void *pData)
{
DWORD status;
PLAYBACK_THREAD_DATA *pPlaybackThreadData;
CDualLineIVRServerDlg *pDlg;
int PhoneLine;
BOOL *pHaltReq;
HANDLE PlaybackEvent;
HWAVEFILE hWaveFile;
int NumIvrTxBuffers;
int cnt;
int NumBytesPerWaveBuffer;
TELEPHONY_RETURN_VALUE SipStatus;
BYTE *pWaveBuffer;
int BytesPerSample;
// change the thread priority. the thread priority will
// be restored when this object's destructor is called.
CPriority ChangeThreadPriority(THREAD_PRIORITY_TIME_CRITICAL);
// access the instance data.
pPlaybackThreadData = (PLAYBACK_THREAD_DATA *)pData;
pDlg = pPlaybackThreadData->pDlg;
PhoneLine = pPlaybackThreadData->PhoneLine;
pHaltReq = &(pDlg->PlaybackThread[PhoneLine].HaltThreadReq);
PlaybackEvent = pDlg->PlaybackEvent[PhoneLine];
// execute until terminated.
while(*pHaltReq == FALSE)
{
pPlaybackThreadData->StartPlayback = FALSE;
pPlaybackThreadData->PlayBackHalted = TRUE;
status = WaitForSingleObject(PlaybackEvent,INFINITE);
pPlaybackThreadData->PlaybackRunningCount++;
pPlaybackThreadData->PlayBackHalted = FALSE;
if(status != WAIT_OBJECT_0)
{
// error.
Sleep(500);
}
else
{
if(*pHaltReq)
{
// terminate.
break;
}
else
{
#if TEST_JALAL_WAVE_FILE_PLAYBACK
// for non PCM data, the number of bytes per sample is assumed
// to be 1.
NumBytesPerWaveBuffer = pDlg->SamplesPerTxIvrBuffer[PhoneLine];
#else
NumBytesPerWaveBuffer = pDlg->SamplesPerTxIvrBuffer[PhoneLine] * 2;
#endif
// create new wave buffer.
pWaveBuffer = new BYTE[NumBytesPerWaveBuffer];
if(pWaveBuffer)
{
hWaveFile = 0;
OpenWaveFile(
pDlg->hSipEngine,
pPlaybackThreadData->pWaveFileName,
NumBytesPerWaveBuffer,
&hWaveFile,
&BytesPerSample
);
if(hWaveFile)
{
// get the current number of IVR transmit buffers available.
GetNumIvrTxBuffers(pDlg->hIvrTransmit [PhoneLine],&NumIvrTxBuffers);
// only prime the first few buffers. this will keep the spectrum analyzer
// display close to real time (each sample block buffer is 20ms).
if(NumIvrTxBuffers > 4)
{
NumIvrTxBuffers = 4;
}
// fill all available IVR tx buffers.
for(cnt=0;(cnt<NumIvrTxBuffers) && pPlaybackThreadData->StartPlayback;cnt++)
{
// read buffers from the wave file and pass off to IVR
if(GetWaveBuffer(hWaveFile,pWa veBuffer))
{
// send the data out the phone line.
TransmitInCallIvrData(pDlg->hIvrTransmit [PhoneLine],pWaveBuffer);
}
}
// continue to stream data to the phone line until we are told to
// quit or we run out of wave data.
while((*pHaltReq == FALSE) && pPlaybackThreadData->StartPlayback)
{
// wait for IVR transmit buffers to become available.
// the method used here waits for IVR transmit buffers
// to become available. we will be notified when tx buffers
// are available via the event.
status = WaitForSingleObject(pDlg->TransmitBufferAvailable[PhoneLine],500);
if(status != WAIT_OBJECT_0)
{
// either an error or we timed out waiting for additional
// transmit buffers to become available. blow some time so
// this thread does not "spin tight".
}
else
{
// get another sample block.
if(GetWaveBuffer(hWaveFile,pWa veBuffer))
{
// send the data out the phone line. Note: if the call was terminated
// at the far end, this proc will return the "call not active" error
// which indicates that we need to stop streaming data to the phone
// line. you can also call the GetLineStatus() API proc to get the line
// state when you transmit IVR data. you should only stream data to the
// phone line when the line is in the "SipInCall" state.
SipStatus = TransmitInCallIvrData(pDlg->hIvrTransmit[PhoneLine],pWaveBuffer);
// send sample block data to spectrum analyzers for display.
pDlg->UpdateSpectrumAnalyze rs(PhoneLine,pWaveBuffer);
if(SipStatus == SipNoCallActive)
{
// the call left the "in call" state. this can happen when any of the
// following occurs:
//
// The call was placed "on hold" at this end,
// The call was terminated at this end.
// The call was terminated by the far end.
//
// this step is not necessary but is here to show how to terminate the
// IVR data that is being transmitted. This call stops the transmission
// of all audio data that may still be queued internally.
//
StopIvrTransmit(pDlg->hIvrTransmit [PhoneLine]);
break;
}
else if(SipStatus == SipFarEndHoldOn)
{
// the far end put us on hold. terminate streaming of data.
StopIvrTransmit(pDlg->hIvrTransmit [PhoneLine]);
// this is an IVR server. if anyone puts us on hold, we hang up on them.
TerminateCall(pDlg->hSipEngine,PhoneLine,FALSE,0);
break;
}
}
else
{
// no more data to transmit. wait for all audio that is queued to finish being
// transmitted out the phone line.
WaitForIvrTransmitComplete(pDl g->hIvrTransmit[PhoneLine]);
break;
}
}
}
if((*pHaltReq == FALSE) && pPlaybackThreadData->StartPlayback && pPlaybackThreadData->SnapTimeoutTime)
{
// now that the prompt has been played. snap the current time so we can
// monitor our hang up timeout.
pDlg->IvrTimeouts [PhoneLine] = GetTickCount();
}
CloseWaveFile(hWaveFile);
hWaveFile = 0;
}
delete pWaveBuffer;
pWaveBuffer = 0;
}
}
}
}
}
|
|
|
Let us know what your results are using this code.
Support
|
Back to Top |
|
|
Jalal Vetran
Joined: April 24 2006 Location: Iran Posts: 188
|
Posted: May 03 2007 at 11:09am | IP Logged
|
|
|
Hi,
Yes, you were right. I was a little confused when I sent you the wav file. It was not the real wav file we were testing. Indeed the problem did exist and it is solved now by your source sample. Our mistake was we trusted your sample source code.
As I mentioned in my previous post we just changed PhoneCallActive function to use AUDIO_BW_ULAW_8K. We did not any change to PlaybackThreadCallback function. After you sent this sample we changed PlaybackThreadCallback function as you described and our problem is solved now.
Regards,
Jalal
|
Back to Top |
|
|
|
|