tutorial_7.cpp

C++ Tutorial Step 7: Initiating a conference call

In the previous tutorial, we wrote a SkypeKit dialer that took a skypename from a command-line argument and initiated a voice call. In this step, we will have two call targets, and we'll form a conference call. Our program will:

Code Walkthrough

Creating a multi-party voice conference is no more difficult than 1-1 calls. The only difference is that we create a conversation object with multiple targets.

skype->CreateConference(conv);
callTargets.append(myCallTarget1);
callTargets.append(myCallTarget2);
conv->AddConsumers(callTargets);
conv->RingOthers();

However, there is one scenario that you will need to handle with your Conversations. Namely, you cannot assume that the participant list of a conversation object stays the same throughout its lifecycle. Even if you do not add more participants yourself, other people might do just that.

In a live conversation, where you will want to display up-to-date list of people in a call (with avatar pictures and voice indicators and such), you will need to handle changes to the participant list. This can be done in Conversation::OnParticipantListChange callback.

A good way would then be to have a Participant::Refs list in your Conversation class, and keep it up-to-date at all times.

void MyConversation::OnParticipantListChange()
{
  this->GetParticipants(participantList, Conversation::ALL);
  fetch(participantList);

  SEString partListAsStr = "New state of participant list:";
  for (uint i = 0; i < participantList.size(); i++)
  {
    SEString identity;
    participantList[i]->GetPropIdentity(identity);
    partListAsStr += " ";
    partListAsStr += identity;
  };
  printf("%s\n", (const char*)partListAsStr);
};

Full code of this example

/****************************************************************************

Getting Started With SkypeKit. Tutorial Application, Step 7.

In the previous tutorial, we wrote a SkypeKit dialer that took a skypename from a command-line argument and initiated 
a voice call. In this step, we will have two call targets, and we'll form a conference call. Our program will:
 1. Create a new Conversation object.
 2. Create an SEStringList and add the skypenames of our call targets to it
 3. Assign the SEStringList to our conference with Conversation::AddConsumers
 4. Get back a list of Participant references
 5. Loop through the list of participants and call Participant::Ring on each one (except ourselves)

**/

#include "skype-embedded_2.h"
#include "keypair.h"
#include "tutorial_common.h"

using namespace Sid;

SEString myAccountName;
SEString myAccountPsw;

SEString myCallTarget1;
SEString myCallTarget2;

//----------------------------------------------------------------------------
// Interface section

class MyParticipant : public Participant
{
public:
  typedef DRef<MyParticipant, Participant> Ref;
  typedef DRefs<MyParticipant, Participant> Refs;

  bool isRinging;
  MyParticipant(unsigned int oid, SERootObject* root) : Participant(oid, root) { isRinging = false; };

  void OnChange(int prop);
};

class MyConversation : public Conversation
{
public:
  typedef DRef<MyConversation, Conversation> Ref;
  typedef DRefs<MyConversation, Conversation> Refs;

  MyParticipant::Refs participantList;
  bool callFinished;
  MyConversation(unsigned int oid, SERootObject* root) : Conversation(oid, root) 
  { 
    callFinished = false; 
  };

  void OnChange(int prop);
  void OnParticipantListChange();
};

class MySkype : public Skype
{
public:
  MySkype() : Skype() {};
  Account*      newAccount(int oid) { return new MyAccount(oid, this); }
  Conversation* newConversation(int oid) { return new MyConversation(oid, this); } 
  Participant*  newParticipant(int oid) { return new MyParticipant(oid, this); }
  bool SetupAudioDevices(uint MicNr, uint SpkNr);
};


//----------------------------------------------------------------------------
// Implementation section

void MyParticipant::OnChange(int prop)
{
  SEString identity;
  GetPropIdentity(identity);

  if (prop == Participant::P_VOICE_STATUS)
  {
    Participant::VOICE_STATUS voiceStatus;
    GetPropVoiceStatus(voiceStatus);
    if (voiceStatus == Participant::RINGING) { isRinging = true; };

    switch (voiceStatus)
    {
      case Participant::RINGING : 
          printf("Calling %s..\n", (const char*)identity);
          break;
      
      case Participant::SPEAKING : 
          printf("%s has joined live state\n", (const char*)identity);
          break;

      case Participant::VOICE_STOPPED : 
          printf("%s has dropped from live state\n", (const char*)identity);
          break;
      
      default:
        // Ignoring other states for now..
        break;
    };
  };
};

void MyConversation::OnParticipantListChange()
{
  this->GetParticipants(participantList, Conversation::ALL);
  fetch(participantList);

  SEString partListAsStr = "New state of participant list:";
  for (uint i = 0; i < participantList.size(); i++)
  {
    SEString identity;
    participantList[i]->GetPropIdentity(identity);
    partListAsStr += " ";
    partListAsStr += identity;
  };
  printf("%s\n", (const char*)partListAsStr);
};

void MyConversation::OnChange(int prop)
{
  if (prop == Conversation::P_LOCAL_LIVESTATUS)
  {
    Conversation::LOCAL_LIVESTATUS liveStatus;
    GetPropLocalLivestatus(liveStatus);
    if ((liveStatus == Conversation::RECENTLY_LIVE) || (liveStatus == Conversation::NONE))
    {
      printf("Call finished.\n");
      this->callFinished = true;
    };
  };
};

bool MySkype::SetupAudioDevices(uint micIdx, uint spkIdx)

{
  SEStringList spkHandles, spkNames, spkProductIDs;
  SEStringList micHandles, micNames, micProductIDs;

  GetAvailableOutputDevices (spkHandles, spkNames,  spkProductIDs);
  GetAvailableRecordingDevices (micHandles, micNames, micProductIDs);

  if (micIdx > (micHandles.size() + 1))
  {
    printf("Invalid mic device no. (%d) passed to MySkype::SetupAudioDevices\n", micIdx);
    return false;
  };

  if (spkIdx > (spkHandles.size() + 1))
  {
    printf("Invalid speaker device no. (%d) passed to MySkype::SetupAudioDevices\n", spkIdx);
    return false;
  };

  printf("Setting mic to %s\n", (const char*)micNames[micIdx]);
  printf("Setting speakers to %s\n", (const char*)spkNames[spkIdx]);

  SelectSoundDevices(micHandles[micIdx], spkHandles[spkIdx], spkHandles[spkIdx]);
  SetSpeakerVolume(100);
  return true;
};


//----------------------------------------------------------------------------
// Main

MySkype* skype;

int main(int argc, char * argv[])
{
  printf("*****************************************************************\n");
  printf(" SkypeKit Tutorial, Step 7. - Initiating voice conference (1 on 2).\n");
  printf("*****************************************************************\n");

  if (argc != 5)
  {
      printf("usage: tutorial_7 <skypename> <password> <1st calltarget> <2nd calltarget>\n");
      return 0;
  };

  myAccountName = argv[1];
  myAccountPsw  = argv[2];
  myCallTarget1 = argv[3];
  myCallTarget2 = argv[4];

  printf("Creating skype ..\n");
  skype = new MySkype();

  // Starting the skype thread and submitting the Application Token.
  getKeyPair ();
  skype->init(keyBuf, inetAddr, portNum, "streamlog.txt");
  skype->start();

  printf("Retrieving account ..\n");
  MyAccount::Ref account;

  if (skype->GetAccount(myAccountName, account))
  {
    printf("Logging in..\n");
    account->LoginWithPassword(myAccountPsw, false, true);
    account->BlockWhileLoggingIn();
    printf("Loggin complete.\n");

    MyConversation::Ref conv;
    SEStringList callTargets;

    skype->CreateConference(conv);
    callTargets.append(myCallTarget1);
    callTargets.append(myCallTarget2);
    conv->AddConsumers(callTargets);

    conv->RingOthers();

    while (!conv->callFinished) {Delay(1);};

    printf("Logging out..\n");
    account->Logout(false);

    account->BlockWhileLoggingOut();
    printf("Logout complete.\n");
  }
  else
  {
      printf("Account does not exist\n");
  };

  printf("Cleaning up.\n");
  skype->stop();
  delete skype;
  printf("Done.\n");
  return 0;
};
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

(c) Skype Technologies S.A. Confidential/Proprietary

Last updated: Fri Mar 16 2012