arrowHome arrow TechBlog Monday, 23 April 2018  
Main Menu
Home
Quality Snaps
TechBlog
PennCharts
Blog
Family
Auld Frosties
Links
Players
Players (uni)
Players (camb)
Contact Us
Pennchart Recent
pennchart radio

Wow, that was actually easy (skype api)

Requirement
To use skype API to place a call at a future point in time, navigate through some phone options (”press one for…”) and leave a voicemail from a WAV file.

This would likely be a bat file called make_call
make_call.exe [phone_number] [wav_file] [navigation_sequence]

Background

Babies...Phones

Childcare is frequently referred to as healthcare in my household — a necessary break to recharge the adult batteries. In fact, we chose our gym based on its provision of such services. The problem is that requests to have little johnny taken care of are over-subscribed; too much demand (parents) chasing too few services (daycare). So the gym in question has a policy of only allowing parents to book 2 days ahead. And a day, in its eyes, starts at midnight. The result is that we have to make a reservation by phone at one minute past midnight. In days of old this would have been no problemo, but now it’s a non-starter to infringe on precious sleeping rights

Skype API
As it would happen, there are 3 APIs out there; Python, Java & COM. Trying to be impartial, I decided to use whichever API had the most samples. Which was Microsoft, of course :)

The Good
Although I did read something giving the API a good slaggin for speed, it seemed mighty easy to program against.
ICall call = skype.PlaceCall(callee);
That’s code even a numpty like me can believe in. The whole thing took <4 hours to get going. Va va vooooom!

The Bad
Changing audio properties for playback of the WAV required installation of an (albeit free) driver, Virtual Audio Cable. All documented here.
It was all made a little trickier by testing via Remote Desktop. Remember to click the Local Resources options tab and configure Remote Audio.

The Ugly
The only rubbish part of the whole thing is that the API doesn’t allow you to authenticate, meaning you had better check the “sign me in automatically” option to skype or you will nae get it working. It also forced me to use a scheduled task as opposed to “at”, which would have been preferable.

OK, another rubbish part is that WAV files have to conform to this spec
File: WAV PCM
Sockets: raw PCM samples
16 KHz mono, 16 bit

and the otherwise loveable Windows 7 doesn’t have a proper sound recorder anymore (grrrr…Microsoft). Their one records in _wma_ format. WTB?? Anyway, you can grab a copy of XP’s sndrec32.exe and continue to use that (albeit with dodgy warnings). But this isn’t skype’s fault, so let’s move on.

C# Code
Precious little to it beyond sleeping and getting duration on the WAV.


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using SKYPE4COMLib;

namespace SkypeTest
{
class Program
{
static void Main(string[] args)
{
try
{
string DTMF = "";
if (args.Length < 3)
{
Usage();
System.Environment.Exit(0);
}
string callee = args[0];
string wavFile = args[1];
int answerDelay = Convert.ToInt32(args[2]);
if (args.Length == 4)
{
DTMF = args[3];
}
int millisecondsToWait = GetSoundLength(wavFile);
SKYPE4COMLib.Skype skype = new Skype();

if (skype.Client.IsRunning == false)
{
skype.Client.Start(true, true);
}
skype.Attach(6, true);
ICall call = skype.PlaceCall(callee, null, null, null);

while (call.Status != TCallStatus.clsInProgress)
{
if (call.Status == TCallStatus.clsBusy ||
call.Status == TCallStatus.clsCancelled ||
call.Status == TCallStatus.clsRefused ||
call.Status == TCallStatus.clsFailed)
{
throw new ArgumentException("Call problems");
}

Thread.Sleep(500);
}
Thread.Sleep(answerDelay);
if (DTMF != "")
{
call.DTMF = DTMF;
Thread.Sleep(1500);
}
call.set_InputDevice(TCallIoDeviceType.callIoDeviceTypeFile, wavFile);
Thread.Sleep(millisecondsToWait);
Thread.Sleep(500); // half a second for luck

// Night night
if (call.Status != TCallStatus.clsFinished) call.Finish();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static private void Usage()
{
Console.WriteLine("Usage: SkypeTest [phone_number/user] [wav_file] [delay_seconds] [[control char]]");
Console.WriteLine("Example: SkypeTest ppenn11 #c:\temp\applause.wav 3 #");
}
static int GetWavFileLength(string wavFile)
{
FileInfo fi = new FileInfo(wavFile);
long fileSize = fi.Length;
double secondsExact = ((fileSize - 44)/(44100*(16/2))/2);
return Convert.ToInt32(Math.Ceiling(secondsExact));
}
[DllImport("winmm.dll")]
private static extern uint mciSendString(
string command,
StringBuilder returnValue,
int returnLength,
IntPtr winHandle);

public static int GetSoundLength(string fileName)
{

StringBuilder lengthBuf = new StringBuilder(32);

mciSendString(string.Format("open \"{0}\" type waveaudio alias wave", fileName), null, 0, IntPtr.Zero);
mciSendString("status wave length", lengthBuf, lengthBuf.Capacity, IntPtr.Zero);
mciSendString("close wave", null, 0, IntPtr.Zero);

int length = 0;
int.TryParse(lengthBuf.ToString(), out length);

return length;

}

}
}

Respect to some geez called the uberoverlord.

No Comments

Add your own comment...

Frosties RandomSnap
top of page