Thanks Uber,
You seem to know more about DTMF with Skype than anybody else. The VB code behind this ActiveX is much as expected - FFT Goertzel style.
I have Delphi code that can detect DTMF embedded in a .wav file
I need to better understand how to map the bytestream output from a 'pCall.OutputDevice[callIoDeviceTypePort]' assigned port into my FFT function.
Can I use the raw bytestream from the port or is some sort of codec needed?
Your '5*' implementation to work around the 'multiple digit' issue is a good idea.
Several posts point to pages on testing.onlytherightanswers.com, but these seem broken just now.
minerva
I need to answer this in a very long-winded-complicated way so that not only you, but others understand what the issues are that can/will be encountered when decoding DTMF in real time using the Skype API/Skype4COM voice stream interface.
1. You can't use the .wav file options, because the Skype client locks the file(s) when opened, so you can't read data from them or write data to them in real time ("Using normal methods"). This means real time DTMF processing for calls must be done using the "Port" option.
2. You can only use the PORT interface as well as the .wav file interface When/While a call is in progress, and you can't be using the same voice API methods for more than one call. This means for example, if you are the host of a conference call, you can not be looking for DTMF on more than one call at a time in the conference call.
3. Don't be frugal, use a 64K buffer size for data from the Skype client for the port data, in C#:
CODE
int BufferSize = 65536;
handler.BeginReceive(state.buffer, 0, BufferSize, 0,
new AsyncCallback(ReadCallback), state);
4. The Microsoft Wave file format states, I quote from:
http://ccrma.stanford.edu/CCRMA/Courses/42...cts/WaveFormat/"8-bit samples are stored as unsigned bytes, ranging from 0 to 255. 16-bit samples are stored as 2's-complement signed integers, ranging from -32768 to 32767."
So, since we are getting bytes from the Skype client we need to make sure that before these bytes are made into 16 bit samples that they are "2's-complement signed integer" 16 bit samples and NOT 16 Bit unsigned integer 16 bit samples. Example using one byte:
-1 = Signed Int vs 255 = Unsigned Int - from Byte 1111 1111
See:
http://academic.evergreen.edu/projects/bio...ram/2s_comp.htmSo, as you can see if we don't sew these bytes back together again
properly, we can create BAD 16 bit samples that will not be decoded correctly by our DTMF decoder code.
In C# we would do this, 2 bytes at a time from the bytes read on the port from our byte buffer, we need to sew them together from bytes to a "2's-complement signed integer" so that 2 bytes become one 16 bit samples and then pass that 16 bit sample to our DTMF decoder code, one 16 bit sample at a time:
CODE
for (int index = 0; index < bytesRead; index+=2)
{
Int16 sample = BitConverter.ToInt16(byte_buffer, index);
// The above int sample contains 2 bytes now Signed Int
// which is 1 sample of 16 bit PCM
// Your DTMF Processing goes here;
}
5. We also have some other issues:
a. If we are using a single threaded application we need to process this Port data from Skype and not wait for the data to arrive, we need to do other things as well asynchronously. We can do this by using a Asynchronous Server Socket. More here:
http://msdn.microsoft.com/en-us/library/5w7b7x5f.aspxNOTE:
The Above Microsoft example code can fail in some cases, for the "StartListening" section, the reason being is that Vista defaults to IPv6 of TCP/IP and XP and older Windows use IPv4 of TCP/IP, so to set a listener that will work on ALL Windows operating systems including IPv6 Vista, you need to do this, example in C#:Replace these two lines in the Microsoft Example code listed at the above link, under "Start Listner", with the one line below it:
BAD in some cases, only supports IPv4 ("XP and before but NOT Vista")
CODE
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0],11000);
See:
http://bytes.com/forum/thread406011.htmlGood IPv4 and Ipv6 (Vista, XP and all operating systems prior that support .NET)
CODE
IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Loopback,11000);
See:
http://msdn.microsoft.com/en-us/library/sy...s.loopback.aspxb. We want to make sure we only support/allow one open of this port, we can't support more than one call in progress anyway and we don't want any hacker code trying to open ports with our application. Example in C# for 1 accept on the port:
CODE
listener.Listen(0);
The Windows Example shows;
CODE
listener.Listen(10);
We don't want to manage 10 opens on this port let allow another program to open the port 9 other times besides the open we need

for the Skype Client to send data.
c. We want to make sure that this port is available and that the call is in progress before we call the 'pCall.OutputDevice[callIoDeviceTypePort]' code.
d. We also do want to not accept any open on the port, if there is NOT a call in progress, see .b, to avoid any hacking attempts as well. Why take the chance when we can avoid it.
NOTES: .b .d, call me paranoid, I don't take chances, if I have server code that is waiting to accept port opens, and I know it should only be done when a call is in progress, well then I do this, after the call has finished, in C#:
CODE
if (handler.Connected)
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
Just before getting data from the port from Skype, once a call is in progress to accept request to open I do this, in C#:
CODE
if (handler.Connected)
{
handler.BeginReceive(state.buffer, 0, BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
else
{
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
I am moving my web site to another hosting company so it is a mess for the moment. It will be back to normal soon however.