2011. 9. 2. 14:45

이 글에서는 스카이프 api를 이용하여 채팅, 전화 걸기, 전화 받기 할 것입니다.

api만 이용하여 스카이프를 컨트롤하기 위해서는 클라이언트가 로그인되어 있어야 합니다.

C#에서 스카이프를 사용하기 위해서는 재공된 Skype4COM.dll를 마샬링 해주어야 하는데......

 

이미 누군가가 해논게 있습니다. ㅋ

코드 플랙스 -

Skype for VisualStudio

이곳에서는 비주얼 스튜디오 SDK를 이용하여 스카이프 프로젝트를 생성할 수 있게 되어 있지만 굳이 그렇게까지 쓸 필요는 없고 'SKYPE4COMLib'만 유징 해서 사용하시면 됩니다.

 

0. UI 구성

저는 wpf 프로젝트로 하겠습니다만....

C#프로젝트라면 별 상관은 없습니다.

(레이아웃 코드만 다를 뿐이니까요 ㅎㅎㅎ)

 

전역변수로 스카이프 클래스를 하나 선언해 두셔야 합니다.

/// <summary>
/// 스카이프 클래스 
/// </summary>
private SkypeClass oSkype = null;

이 객체가 지금 떠 있는 스카이프의 객체입니다.

스카이프API에 접근하기 위해서는 이 개채를 통해야 합니다.

 

 

1. 친구 목록 받아오기

일단 친구 목록이 있어야 메시지를 보내든 통화를 하든 하지 않겠습니까?ㅎㅎㅎ

친구 목록 받아오는 방법부터 알아보겠습니다.

//친구 목록
void butGetFriend_Click(object sender, RoutedEventArgs e)
{
    //친구 목록을 가저 옵니다.

    Friend oFriend = null;
    User user = null;

    //친구 목록을 받아 옵니다.
    UserCollection listTemp = this.oSkype.Friends;
    int nMax = listTemp.Count;

    //리스트 삭제
    lbFriend.Items.Clear();

    //인덱스가 1부터 시작이라 여러가지로 불편하네-_-;
    for( int i = 1; i <= nMax ; ++i )
    {
        user = listTemp[i];
        oFriend = new Friend();
        oFriend.labName.Content = user.FullName;
        lbFriend.Items.Add(oFriend);
    }

}

/// <summary>
/// 리스트에 선택된 유저의 인덱스를 받아 옵니다.
/// </summary>
private int GetSeletUserIndex()
{
    //사용자 인덱스를 받아온다.
    int nSelectIndex = lbFriend.SelectedIndex;

    //인덱스가 1부터 시작하기 때문에 인덱스를 더해 준다.
    ++nSelectIndex;

    return nSelectIndex;
}

 

친구 목록이 가져와 진다!

참고로 Echo / Sound Test Service는 api로 접근하면 생성되는 유저입니다.

테스트용으로 사용할 수 있습니다.

 

 

2. 메시지 주고 받기

일종의 메신저 기능인 메시지 주고 받기를 해보겠습니다.

 

2-1. 메시지 받기

당연한 이야기겠지만 메시지를 받기 위해서는 연결된 이벤트가 필요합니다.

생성자()
{
    //메시지가 오면 발생합니다.
    this.oSkype.MessageStatus += new _ISkypeEvents_MessageStatusEventHandler(oSkype_MessageStatus);
}

/// <summary>
/// 메시지가 오면 발생합니다.
/// </summary>
/// <param name="pMessage"></param>
/// <param name="Status"></param>
void oSkype_MessageStatus(ChatMessage pMessage, TChatMessageStatus Status)
{
      //다른사람이 보낸 메시지 인지?
      if (Status == TChatMessageStatus.cmsReceived)
      {
            //메시지를 발생시킨다.
            ChatMessage(pMessage.Sender, pMessage.Body);
            TextBox1.Text = TextBox1.Text + "\n" + pMessage.Sender.FullName + " : " + pMessage.Body;
      }
}

이렇게 하면 메시지를 받을 수 있습니다.

 

 

 

2-2. 메시지 보내기

친구목록을 받은 후 선택한 친구에게 메시지를 보내봅시다.

//샌드 클릭
void btnSend_Click(object sender, RoutedEventArgs e)
{
    //메시지를 날리다.
    User oUser = this.oSkype.Friends[GetSeletUserIndex()];
    oSkype.SendMessage(oUser.Handle, txtSendText.Text);
}

참 쉽죠?

 

사실 예외처리가 안들어가서 그렀습니다 ㅡ.-;;;;

예외처를 넣으면 좀 복잡해 집니다.

 

 

 

3. 통화하기

스카이프의 꽃!!!!!

꽃보다 무료 통화!!!!

네 바로 통화입니다.

 

 

3-1. 전화 받기

전화도 메시지와 마찬가지로 이벤트가 넘어옵니다.

전화가 오는 이벤트는 '_ISkypeEvents_Event_CallStatus'입니다.

/// <summary>
/// 받은 전화의 아이디.
/// </summary>
private int m_nRingingID = 0;

생성자()
{
    //통화 상태 변경되면 발생합니다.
    this.oSkype._ISkypeEvents_Event_CallStatus += new _ISkypeEvents_CallStatusEventHandler(oSkype__ISkypeEvents_Event_CallStatus);
}

void oSkype__ISkypeEvents_Event_CallStatus(Call pCall, TCallStatus Status)
{
	//콜이 왔다!

	//객체 id 복사
	this.m_nRingingID = pCall.Id;

	switch(Status)
	{
		case TCallStatus.clsRinging:	//전화가 왔다.
			TextBox1.Text = TextBox1.Text + "\n" + e.CallDisplayName + " : " + "전화 왔음";
			break;
		case TCallStatus.clsFinished:	//전화 종료
			TextBox1.Text = TextBox1.Text + "\n" + e.CallDisplayName + " : " + "전화 종료";
			break;
	}
}

void btnResponse_Click(object sender, RoutedEventArgs e)
{
	//전화를 받는다.
	try
	{
		this.oSkype.get_Call(this.m_nRingingID).Answer();
	}
	catch
	{
	}
}

void btnFinish_Click(object sender, RoutedEventArgs e)
{
	//전화를 끊는다.
	try
	{
		this.oSkype.get_Call(this.m_nRingingID).Finish();
	}
	catch
	{
	}
}

 

일단 전화에 관련된 이벤트가 발생하면 '_ISkypeEvents_Event_CallStatus'가 호출됩니다.

어떤 이벤트인지는 'TCallStatus Status'로 넘어오죠.

 

이때 'TCallStatus.clsRinging'는 상대방으로부터 전화가 왔다는 것이고

'TCallStatus.clsFinished'가 오면 전화가 끊겼다(어떤 식으로든 통화가 종료되면) 것입니다.

 

여기서 주의할 점은 내가 이 콜을 컨트롤하기위해서는 콜의 id가 필요하다는 것입니다.

그렇기 때문에 전역변수로 'm_nRingingID'를 선언하여 이 콜을 컨트롤하기위해서 콜이 왔을 때 해당 정보를 백업해 둡니다.

그 후 'this.oSkype.get_Call(this.m_nRingingID)'를 이용해 컨트롤하려는 콜을 불러와 사용합니다.

 

여기서도 예외 처리가 빠진 것이 있는데 현재 콜의 아이디가 '_ISkypeEvents_Event_CallStatus'에서 온 콜아이디와 같은 것인지 확인을 안하고 있습니다.

이렇게 되면 콜을 여러 개 받는 경우 원하는 대로 컨트롤이 안 될수 있습니다.

 

콜이 왔다!

 

통화 잘되고 있음
전화가 끊겼네

 

 

3-2. 전화 걸기

메시지 보내기와 마찬가지로 전화 걸기로 친구 목록을 가져오고 난 뒤 선택하고 걸기를 하셔야 합니다.

void btnCall_Click(object sender, RoutedEventArgs e)
{
	//전화를 건다.
 
    //사용자가 오프라인 상태인 경우 PlaceCall 명령은 실패합니다. 실패를 방지하려면 사용자 상태를 확인하고 필요한 경우 온라인으로 변경 :
    if (TUserStatus.cusOffline == this.oSkype.CurrentUserStatus)
    {
         this.oSkype.ChangeUserStatus(TUserStatus.cusOnline);
    }

    //열려있는 콜이 있으면 닫는다.
    CallFinish();

    //사용자 개채를 만든다            
    User oUser = null;

    try
    {
		oUser = this.oSkype.Friends[GetSeletUserIndex()];
    }
    catch
    {
         //유저를 찾지 못했습니다.
         return;
    }

    //전화 하는 장소:
    m_oCall = this.oSkype.PlaceCall(oUser.Handle, "", "", "");
}

'PlaceCall'를 이용하여 통화요청을 할 수 있으며 이후 동작은 전화 받을 때와 같습니다.

'PlaceCall'의 매개변수는 모두 유저 핸들이며 여러 명에게 한 번에 걸 때는 해당 유저 핸들러를 넣으시면 됩니다.

 

원래는 'PlaceCall'을 요청한 뒤 받는 콜의 상태가 변해야 하는데....

버그인지 아니면 이것이 예전 버전과 안 맞는 것인지 도움말 파일에 들어있는 샘플 코드대로 만들면 계속 같은 값만 들어오는 현상이 있습니다.

 

그래서 몇 가지 태스트를 해보았으나.... 딱히 변하는 값을 전달하는 것을 찾지 못했습니다.

결국 다른 콜이 올 때나 요청할 때 가지고 있는 콜(m_oCall)을 끝내주는 방법을 사용하셔야 합니다.

어차피 가지고 있는 콜이 끝나지 않은 상태에서도 다른 동작에는 이상이 없기 때문에 이렇게 처리하셔도 됩니다.

뭐....그 이후에 오는 내용(응답 없음, 통화 실패 등등..)을 처리할 방법이 없습니다만......조만간 찾을 수 있겠죠? ㅎㅎㅎ

 

우리에 테스트양에게 전화를 걸어 보았습니다.

 

 

마무리

간단하게 '.NET'으로 스카이프API를 사용해 봤습니다.