Author |
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 13 2007 at 2:33pm | IP Logged
|
|
|
Background:
I'm writing a wrapper in C# using the sample C++ applications for reference. I have gotten as far as initializing, configuration, registering with my SIP proxy, placing an outbound call to my cellphone and connecting the call.
Now I am trying to play a wave file. I don't care about hearing it locally on my speakers, so I'm dealing mostly with the IVR transmit APIs at this time. I'm using "Playback wave file.cpp" for reference.
Basically all I hear is some garbage sound when I try to play the wave file. I actually hear it through my cellphone and even on my speakers where the application is running on. Does anyone have any idea what the problem could be?
Thanks,
Adrian
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 13 2007 at 3:19pm | IP Logged
|
|
|
Hi adrian,
Thanks for posting. Do you have a code snippet we can look at? Its probably something simple.
Support
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 13 2007 at 3:38pm | IP Logged
|
|
|
This is the code I run after I've connected. I'm still working on the event handler (TxIvrBufferAvailableEvent). If you want to see any of the wrapper declarations let me know and I can post those as well.
Code:
IntPtr TxIvrBufferAvailableEvent = IntPtr.Zero;
TxIvrBufferA vailableEvent = SipTelephonyApi.CreateEvent((IntPtr)null, false, false, null);
if (TxIvrBufferAvailableEvent == IntPtr.Zero)
{
Console.WriteLine("Unabl e to create TxIvrBufferAvailableEvent");
return;
}
IntPtr hIvrTxHandle = IntPtr.Zero;
// open a Tx IVR channel so we can stream audio data to the phone line.
status = SipTelephonyApi.OpenTxIvrChannel(
hSipEngine, // media engine handle.
0, // the phone line - zero based.
0, // Tx IVR channel on the phone line.
out hIvrTxHandle);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with OpenTxIvrChannel");
return;
}
// tell the Tx IVR interface to let us know when phone line transmit buffers
// become available.
status = SipTelephonyApi.SetTxIvrBufferEvent(hIvrTxHandle, TxIvrBufferAvailableEvent);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with SetTxIvrBufferEvent");
return;
}
// set the type of data we will send to the phone line.
status = SipTelephonyApi.SetTxIvrDataType(hIvrTxHandle, AUDIO_BANDWIDTH.AUDIO_BW_PCM_8K);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with SetTxIvrDataType");
return;
}
// get the size of the sample blocks that can be sent
// to the phone line.
Int32 SamplesPerIvrBuffer = 0;
Int32 BytesPerIvrBuffer = 0;
status = SipTelephonyApi.GetTxIvrSampleBlockSize(
hIvrTxHandle, AUDIO_BANDWIDTH.AUDIO_BW_PCM_8K,
out SamplesPerIvrBuffer, out BytesPerIvrBuffer);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with GetTxIvrSampleBlockSize");
return;
}
// open the wave file we want to play. & nbsp;
status = SipTelephonyApi.OpenWaveFile(
hSipEngine, @"C:\IncorrectMenuSelection.wav",
BytesPerIvrBuffer, out hWaveFileHandle);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with OpenWaveFile");
return;
}
byte [] pWaveBuffer = new byte[BytesPerIvrBuffer];
Int32 NumIvrTxBuffers = 0;
status = SipTelephonyApi.GetNumIvrTxBuffers(hIvrTxHandle, out NumIvrTxBuffers);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with GetNumIvrTxBuffers");
return;
}
int NumSampleBuffers = NumIvrTxBuffers;
// initially queue up sample blocks to the phone line
bool Err = false;
bool Done = false;
for (int cnt = 0; !Err && !Done && (cnt < NumSampleBuffers); cnt++)
{
// read wave data from the file.
if (!SipTelephonyApi.GetWaveBuffer(hWaveFileHandle, ref pWaveBuffer[0]))
{
// all the sample data has been read from the wave file.
Done = true;
}
else
{
// send the wave file data to the phone line.
status = SipTelephonyApi.TransmitInCallIvrData(hIvrTxHandle, ref pWaveBuffer);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
// assume the call has been terminated.
Err = true;
}
else
{
// send the wave file data to the local audio out.
status = SipTelephonyApi.WriteAudioOutData(hAudioOut, ref pWaveBuffer);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Err = true;
}
}
}
}
// at this point, all phone line buffers Tx IVR buffers and local
// audio playback buffers are stuffed. wait for additional Tx IVR
// sample buffers to become available.
while (!Err && !Done)
{
/*
//Currently not working correctly, still investigating
long WaitStatus = SipTelephonyApi.WaitForSingleObject(
TxIvrBufferAvailableEven t,
SipTelephonyApi.INFINITE);
if (WaitStatus != SipTelephonyApi.WAIT_OBJECT_0)
{
// wait error.
Err = true;
}
*/
status = SipTelephonyApi.GetNumIvrTxBuffers(hIvrTxHandle, out NumIvrTxBuffers);
NumSampleBuffers = NumIvrTxBuffers;
for (int cnt = 0; !Err && !Done && (cnt < NumSampleBuffers); cnt++)
{
// read wave data from the file.
if (!SipTelephonyApi.GetWaveBuffer(hWaveFileHandle, ref pWaveBuffer[0]))
{
// all the sample data has been read from the wave file.
Done = true;
}
else
{
// send the wave file data to the phone line.
status = SipTelephonyApi.TransmitInCallIvrData(hIvrTxHandle, ref pWaveBuffer);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
// assume the call has been terminated.
Err = true;
}
else
{
// send the wave file data to the local audio out.
status = SipTelephonyApi.WriteAudioOutData(hAudioOut, ref pWaveBuffer);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Err = true;
}
}
}
}
}
// wait for all the sample data to play.
status = SipTelephonyApi.WaitForIvrTransmitComplete(hIvrTxHandle);
|
|
|
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 13 2007 at 4:35pm | IP Logged
|
|
|
I got the TxIvrBufferAvailableEvent event code working. I was using long for the return type of WaitForSingleObject when it should have been Int32.
Anyways, like I said, all I hear is this garbage noise when it tries to play the wave file.
Thanks,
Adrian
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 14 2007 at 7:15am | IP Logged
|
|
|
Hi adrian,
The code you have looks OK at first review. But there are a few things you can do to locate the problem.
Please obtain the latest trial product image:
We found a few fubars in the last trial product release. Please request a new trial image to test with. We will get it to you as soon as we receive your request. For more info see:
http://www.lanscapecorp.com/forum/forum_posts.asp?TID=262&PN =1
Write the raw wave file samples to a file:
After you read a block of wave file samples, write them to a file. Then use some other application like Cool Edit Pro or equivalent to read the raw samples from the file and play them back. If Cool Edit Pro plays back the samples correctly then we know you are reading them from the wave file image ok.
We are glad you are using the media engine with C#. We should be able to get your issue solved pretty quickly. When you are done, we would like to check out your test code.
Repost as needed,
Support
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 11:25am | IP Logged
|
|
|
I'm currently downloading the new image. In the meantime, I tried to read the wave file and then write it out. When I played it, it sounded the same as what I'm hearing during the call. One thing I noticed is that I can hear the original wave in the background with the noise on top of it.
I tried one more thing. When I play IncorrectMenuSelection.wav as a "Windows PCM" it sounds perfect. When I play it as "PCM Raw Data" it sounds exactly like what I am hearing with the noise.
Here is the code I used to read and write the wave file.
// open the wave file we want to play.
status = SipTelephonyApi.OpenWaveFile(hSipEngine, @"C:\IncorrectMenuSelection.wav", 400000, out hWaveFileHandle);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with OpenWaveFile");
return;
}
byte[] pWaveBuffer = new byte[400000];
SipTelephonyApi.GetWaveBuffer(hWaveFileHandle, ref pWaveBuffer[0]);
FileStream fs = new FileStream(@"C:\sample.wav", FileMode.CreateNew);
fs.Write(pWaveBuffer, 0, pWaveBuffer.Length);
fs.Close();
SipTelephonyApi.CloseWaveFile(hWaveFileHandle);
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 12:05pm | IP Logged
|
|
|
BTW, once I finish downloading can I just install the new one on top of the previous version?
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 12:51pm | IP Logged
|
|
|
I compared the original wave file with the data that I saved. After the wave info (first 43 bytes) everything looks to be the same. So I guess I'm reading it correctly.
I think I may have figured out what is going on. It looks to be a combination of what I'm configuring the media data type to be and what it actually is. I also have to look into what I have my test sip proxy set to accept.
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 14 2007 at 1:15pm | IP Logged
|
|
|
Hi Adrian,
Installing a new version:
To be safe, I would uninstall your current media engine version and then install the new version.
Tx IVR media data type:
You hit it right on the head! As soon as you said this the bulb went on.
The IncorrectMenuSelection.wav file image is 22kHz mono 16 bit samples. Change the code above to use this:
Code:
// set the type of data we will send to the phone line.
status = SipTelephonyApi.SetTxIvrDataType(hIvrTxHandle, AUDIO_BANDWIDTH.AUDIO_BW_PCM_22K);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with SetTxIvrDataType");
return;
}
|
|
|
If you also want to send the wave file PCM samples to the local audio out, you will also have to add this code before you start streaming to the audio output:
Code:
// set the type of data we will send to the local audio out.
status = SipTelephonyApi.SetAudioOutDataType(hAudioOut, AUDIO_BANDWIDTH.AUDIO_BW_PCM_22K);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with SetAudioOutDataType");
return;
}
|
|
|
Good job. Repost as needed,
Support
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 2:23pm | IP Logged
|
|
|
It looks like I need to get all my formats and configurations set correctly. I've been able to go over the debug logs on my Asterisk server and have located some problems.
I'm still trying to get a grasp of all the APIs that deal with setting the audio format. If you can elaborate more on these methods I'd really appreciate it.
Code:
status = SipTelephonyApi.SetAudioMediaFormat(hSipEngine, 0, MEDIA_FORMAT_AUDIO.Media_Format_Pcm22050); |
|
|
This looks like where it communicates the audio format with Asterisk. At this point Asterisk reports an error that it couldn't find a compatible codec. The capabilities it reports back are
g723|gsm|ulaw|alaw|g726|adpcm|slin|lpc10|g729|speex|ilbc
So I set the media format to Media_Format_uLaw8k and I do not get an error back from Asterisk.
As for setting the data type in the IVR transmit functions, I am using AUDIO_BW_PCM_22K.
Code:
status = SipTelephonyApi.SetTxIvrDataType(hIvrTxHandle, AUDIO_BANDWIDTH.AUDIO_BW_PCM_22K);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with SetTxIvrDataType");
return;
}
// get the size of the sample blocks that can be sent
// to the phone line.
Int32 SamplesPerIvrBuffer = 0;
Int32 BytesPerIvrBuffer = 0;
status = SipTelephonyApi.GetTxIvrSampleBlockSize(hIvrTxHandle, AUDIO_BANDWIDTH.AUDIO_BW_PCM_22K, out SamplesPerIvrBuffer, out BytesPerIvrBuffer);
if (status != TELEPHONY_RETURN_VALUE.SipSuccess)
{
Console.WriteLine("Error with GetTxIvrSampleBlockSize");
return;
}
|
|
|
Unfortunately it still doesn't seem to be playing back the wave file correctly. Do I need to use a wave file that is uLaw 8K instead of PCM 22K? I tried to create a sample wave using the Microsoft Sound Recorder and saving it as uLaw 8K mono, but that still didn't work.
Thanks,
Adrian
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 14 2007 at 2:43pm | IP Logged
|
|
|
Sounds like you are gaining on it.
<< You
So I set the media format to Media_Format_uLaw8k and I do not get an error back from Asterisk.
Support >>>
Yes. Exactly.
The SetAudioMediaFormat()API proc is used to set the RTP media type that will be used for the phone call. You must set the media type for each phone line you are going to use. You can see the difference these two procs perform if you look at the INVITE the media engine transmits when you make an outbound call.
When you call the SetAudioMediaFormat() API proc for each phone line, each call will only contain one codec selection that will be used for the call. For your Asterisk setup, you might want to use uLaw, aLaw or G729.
When you call the SetAudioMediaFormats() API proc for each phone line, each call will contain many possible codecs that can be used for the call. In this case, Asterisk will determine which codec out of the many possible that will actually be used.
See the SetAudioMediaFormat() and SetAudioMediaFormats() API procs in the developer’s reference. Use the dev reference as your bible - its all there.
If you are reading the RAW 22k 16 bit PCM sample blocks from the existing wave file, all you have to do is to pass these sample blocks to the phone line Tx IVR input as you are doing.
If you are at a complete loss, zip your project and email it to us.
Support
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 14 2007 at 2:44pm | IP Logged
|
|
|
Note: If you have your C# code do exactly what the C++ sample app does, then you will get it.
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 3:00pm | IP Logged
|
|
|
So the format specified in SetAudioMediaFormat has nothing to do with the one specified in the Tx IVR input functions?
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 14 2007 at 3:15pm | IP Logged
|
|
|
Adrian,
Yes that is correct. SetAudioMediaFormat() just sets the RTP media data type(s) that can be used to stream audio data to/from your Asterisk box.
The format and rate of the Tx IVR channels and the local audio out channels can be totally different. The media engine will handle all format and rate conversions internally as needed.
Support
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 5:44pm | IP Logged
|
|
|
I've converted my test code over to a C++ project and it's playing the wave file correctly. So it looks like I'll have to go over my interop code to see what I might be doing incorrectly. I'll let you know what I find out.
Thanks,
Adrian
|
Back to Top |
|
|
adrian Intermediate
Joined: February 13 2007 Location: United States Posts: 10
|
Posted: February 14 2007 at 5:59pm | IP Logged
|
|
|
Good news, after creating the sample in C++ from scratch and going over everything when I went back over the interop code I was able to find my mistake. I was able to run my C# code successfully without any problems playing the wave file. My problem ended up being my declaration of the TransmitInCallIvrData method. After I corrected it everything worked as expected.
Thank you,
Adrian
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: February 15 2007 at 7:03am | IP Logged
|
|
|
Nice Job! :)
|
Back to Top |
|
|