Running Skype on an embedded device - audio. Part 2

Last time In the article Running Skype on an embedded device. Part 1 I have described how to install and build the SkypeKit API wrapper and the Skype client demo application. I admit it was quite boring mainly because the demo even didn't run. This time I will describe how to build the voice loopback host and a voice host that works with several Linux audio drivers such as ALSA and OSS.

There are two possible voice hosts implementations possible, PCM and RTP. The RTP host is obsolete and has been discontinued in the 4.3 and higher versions so I'm not gonna spend too much time with it.

RTP voice host

The RTP host takes the raw RTP samples with the encoded audio packets, decodes them and play them via an audio device. Similarly for the output audio output the RTP host is responsible for capturing the audio, encoding it and pushing the encoded samples to the SkypeKit. Since this API was discontinued I'm not gonna deal with it.

PCM voice host

works on the PCM level with the SkypeKit which means the developer of his host needs to select, configure and open the audio IO and read audio samples from microphone or other input and feed them to the SkypeKit via its API. The same holds good for the audio output. In general this is quite easy since all audio drivers works with the PCM samples. This is how the skype interfaces with the PCM host.

You can see the SkypeKit handles things such as audio codecs, echo cancellation,  AGC and jitter buffer.

There are three PCM host reference implementation in the SkypeKit

  • voicepcmhost-file
    Uses a files for audio IO. We would run it like

    ./voicepcmhost-file -i myInput.wav -o myOutput.wav
  • voicepcmhost-loopback
    As the name says, it take the received audio and forward it back. This is the basic host I'm gonna build first.
  • voicepcmhost-rtaudio
    This is the more complete voice host that can actually read audio from a microphone and play it out on speakers.

Building and running the voicepcmhost-loopback host

In order to run the examples from the SDK we need to build at least one voice PCM  backend (host) from the reference implementations in the directory

sdp-distro-skypekit_3.7.1.331_1823867/reference/

We are going to build the loopback one so go to corresponding directory

$ cd sdp-distro-skypekit_3.7.1.331_1823867/reference/voicepcmhost-loopback

and run make with the architecture name and the tool chain prefix. The architecture must be on of the sub-directories in the bin dir.

  • linux-armv5le-eabi
  • linux-armv6le-eabi
  • linux-armv7le-eabi
  • linux-mips32be
  • linux-mips32le
  • mac-x86
  • windows-x86
  • linux-x86

This toolchain is the string in front of the "g++" in the file name of you ARM cross compiler. My compiler file name is arm-none-linux-gnueabi-g++

make TARGET_ARCH=armv7le-eabi TOOLCHAIN_PREFIX=arm-angstrom-linux-gnueabi-

Here I encountered a few problems. Firstly I didn't have the premake4 tool which is used by the build scripts. This is where I got it: http://industriousone.com/premake

When the build finishes you should get voicepcmhost-loopback binary in the build directory

sdp-distro-skypekit_3.7.1.331_1823867/reference/voicepcmhost-loopback/build/voicepcmhost-loopback

Now you just need to copy this file on your ARM device, or a filesystem accessible from the ARM device and you are ready to run the Skype client!

To do that we need to run the voice host first, then the Skype runtime and then the skype client application. For this experimentation we want to run a console window for each process so we can nicely see all log messages.

First we run the voice PCM backend

$ ./voicepcmhost-loopback
AVTransportWrapper (/tmp/pcm_from_skypekit_key): connected!
AVTransportWrapper (/tmp/pcm_to_skypekit_key): connected!
Init
UseDefaultDevice: INPUT_DEVICE
UseDefaultDevice: OUTPUT_DEVICE
UseDefaultDevice: NOTIFICATION_DEVICE
GetCurrentDevice: INPUT_DEVICE, guid0
UseDevice: INPUT_DEVICE, guid0
UseDevice: OUTPUT_DEVICE, guid0
UseDefaultDevice: NOTIFICATION_DEVICE
GetCurrentDevice: INPUT_DEVICE, guid0
GetDevices: INPUT_DEVICE
GetDevices: OUTPUT_DEVICE
Stop: INPUT_DEVICE
Stop: OUTPUT_DEVICE
Stop: NOTIFICATION_DEVICE
UseDevice: INPUT_DEVICE, guid0
UseDevice: OUTPUT_DEVICE, guid0
UseDefaultDevice: NOTIFICATION_DEVICE
GetCurrentDevice: INPUT_DEVICE, guid0
UseDevice: INPUT_DEVICE, guid0
UseDevice: OUTPUT_DEVICE, guid0
UseDefaultDevice: NOTIFICATION_DEVICE
GetCurrentDevice: INPUT_DEVICE, guid0
GetCurrentDevice: INPUT_DEVICE, guid0
Start: INPUT_DEVICE
Stop: INPUT_DEVICE
GetCurrentDevice: OUTPUT_DEVICE, guid0
GetCurrentDevice: NOTIFICATION_DEVICE, guid0
Start: OUTPUT_DEVICE
Stop: OUTPUT_DEVICE
Stop: INPUT_DEVICE
Stop: OUTPUT_DEVICE
Stop: NOTIFICATION_DEVICE

Then the SkypeKit runtime

$ ./linux-armv7-skypekit-voicepcm-novideo 
SkypeRuntime Copyright (C) 2003-2012 Skype Technologies S.A.
SkypeRuntime Version: 3.7/linux-armv7-skypekit-voicepcm-novideo_3.7.1.343_1823908
Proprietary and confidential, do not share this application.
AVTransportWrapper (/tmp/pcm_to_skypekit_key): connected!
AVTransportWrapper (/tmp/pcm_from_skypekit_key): connected!

And finally the Skype client. Remember you need to pass the development certificate to the client app.

$ ./skypekitclient -t av_test_arm_v1.pem
::: Connected to skypekit
3.7/linux-armv7-skypekit-voicepcm-novideo_3.7.1.343_1823908

New account oid 37

::: Type ? for list of available commands

If you get a similar response everything is fine. In my case it worked on first try. Now you can login to your Skype account but typing

aL

You will be asked for you username and password.

When you make an audio call on this Skype client you will get an audio echo. The loopback host simply forwards the audio that is received back to the caller.

Btw the call is answered/terminated from the command line by typing

Ca - answer
Ce - hangup

Building and running the voicepcmhost-rtaudio host

voicepcmhost-rtaudio is another reference implementation of the audio backend that comes with the SkypeKit. This host provides an interface for these audio implementations

  • Windows (DirectSound and ASIO)
  • Macintosh OS X (CoreAudio and JACK)
  • Linux (native ALSA, JACK, and OSS)

The voicepcmhost-rtaudio reference implementation that comes with the Skypekit relies on an open source library rtAudio. The SkypeKit sdp-distro-skypekit_3.7.1.331_1823867 needs rtaudio version 4.0.6 which can be downloaded from http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.6.tar.gz It may well run with the latest one which is by the time of writing this article 4.0.11 but I haven't tried it.

Download the rtaudio and uncompress it to the this directory

sdp-distro-skypekit_3.7.1.331_1823867/reference/voicepcmhost-rtaudio/rtaudio-4.0.6

You don't have to build the rtaudio beforehand. The rtaudio is very simple project consisting of only three source files that the voicepcmhost-rtaudio compiles and links itself. Got here

sdp-distro-skypekit_3.7.1.331_1823867/reference/voicepcmhost-rtaudio/

and run

make PCMHOST=rtaudio TARGET_ARCH=armv7le-eabi TOOLCHAIN_PREFIX=arm-angstrom-linux-gnueabi-

When the build finishes you should get voicepcmhost-rtaudio in the build directory

sdp-distro-skypekit_3.7.1.331_1823867/reference/voicepcmhost-rtaudio/build/voicepcmhost-rtaudio

The voicepcmhost-rtaudio uses the default audio IO device. This is correct for the audio output but not for the audio input on my platform. Currently I'm testing the audio input from a webcam microphone which works as a standalone sound card with just audio capture interface. To make the voicepcmhost-rtaudio to correctly connect to the webcam microphone I had to set the device ID =1 in the StartInputDevice() function in the RtAudioPCMInterface.cpp file

int RtAudioPCMInterface::startInputDevice(RtAudio *device)
{
   uint buffer_frames = 512;
   uint fs = RATE;
   RtAudio::StreamParameters params;
   // params.deviceId = 0;//device;
   params.deviceId = 1;//device;
   params.nChannels = IN_CHANNELS;//channels;
   params.firstChannel = 0;

   try {
      device->openStream(NULL, &params, FORMAT, fs, &buffer_frames, &input_callback, (void *)this);
      device->startStream();
   }
   catch (RtError& e) {
      std::cout << '\n' << e.getMessage() << '\n' << std::endl;
      return 0;
   }
   return 1;
}

After a rebuild I copied the voicepcmhost-rtaudio on my platform and again run the whole skype circus by executing the following processes in this order:

  1. voicepcmhost-rtaudio
  2. linux-armv7-skypekit-voicepcm-novideo
  3. skypekitclient -t av_test_arm_v1.pem

And voila, the audio IO works like a dream:-) Next time I will focus on the video side of the thing, and again as with the audio I will build the video loopback host first.

For now all the best....

This entry was posted in ARM, Embedded, Skype, Software development, VoIP. Bookmark the permalink.

Leave a Reply