Skype Meeting を API (REST, Web) で処理する (Skype for Business)


Skype for Business API 開発

こんにちは。

これまで、Skype (Skype fro Business) の Online Meeting の処理 (プログラムからの作成など) をアプリケーションに組み込みたいというニーズは多かったのですが、非常に困難でした。
しかし、UCWA (REST API) や Skype Web SDK が Office 365 対応したことで、Office 365 上で Online Meeting を柔軟に扱えるようになりました。(さらに、Skype Web SDK、Outlook REST API にも、Online Meeting 関連の処理がかなり追加されました。)

本投稿では、Online Meeting の作成から参加までの一連の流れを、最新の API (REST API や JavaScript API) を使って実装する方法 (考え方) を紹介します。

なお、ここで解説する機能は、今後解説するであろう Skype for Business App SDK でも活躍しますので (B2C シナリオと共に、いずれご紹介します)、Online Meeting の処理に興味がない方も、Skype による Real-time Communication のプログラミングに興味がある方は、是非、概念をおぼえておいてください。(2016/05/12 追記 : この Skype for Business App SDK を使ったプログラミングについて、「Skype for Business App SDK 紹介」に記載しました。)

Skype for Business の Meeting の概要

まずは基本的な話ですが、Skype for Business では、1:1 の Conversation と、Group Conversation (以降、Meeting と表現) は別のオブジェクトです。(なお、Conversation に 3 名以上の User が登録されると、自動的に Group Conversation に昇格されます。)

また、Group Conversation (Meeting) には、Outlook から あらかじめ作成する Scheduled Meeting (Pre-scheduled Meeting) と、その場で開催する Ad-hoc Meeting (On-demand Meeting) があり、これらも微妙に扱いが異なっています。

補足 : Skype for Business Web Scheduler (https://sched.lync.com) を使用すると、Outlook を使用せずに (Skype for Business のみを使って) Scheduled Meeting の作成や、作成された会議一覧の確認 (および編集) が可能です。

Outlook による Scheduled Meeting の作成

「今すぐ会議」(Meet Now) による Ad-hoc Meeting の作成

このあと、API を使ったプログラミングの具体例を紹介しますが、「どのオブジェクトの」、「どのような状態の」といったことを理解しながら読んでください。

Ad-hoc Meeing の作成 (API)

上述の通り、同じ Conversation でも、1 : 1 の Conversation と、Meeting (= Group Conversation) では扱いが異なります。
これまでの「Skype Web SDK 紹介 (Skype for Business Online)」などのサンプル コードでは、すべて前者 (つまり、1 : 1 の Conversation) を例に紹介しましたが、Skype Web SDK で Meeting (Group Conversation) を扱う場合は、「Skype Web SDK 紹介 (Skype for Business Online)」で解説した ソースコードを、下記太字の通り、createConversation() に変更します。(ここでは、Chat (Text Messaging) を処理しています。)

なお、同様にして Audio、Video の Group Conversation も作成できます。(「Skype Web SDK の Audio / Video プログラミング」で解説したように、audioService.start()videoService.start() に変更するだけです。)

補足 : 下記は uri() 関数を使用しているため、JavaScript の strict mode ('use strict') は使用できません。

Create Add-hoc Meeting (Web SDK)

document.getElementById('btnStartMeetNow').onclick = function () {
  //// when start as 1:1 conversation
  //conver = app.conversationsManager.getConversation(person);

  // when start as ad-hoc meeting (group conversation)
  conver = app.conversationsManager.createConversation();
  var part = conver.createParticipant(person);
  conver.participants.add(part);
  // (repeat adding person ...)
  //var part2 = conver.createParticipant(person2);
  //conver.participants.add(part2);
  //...
  app.conversationsManager.conversations.add(conver);

  conver.selfParticipant.chat.state.changed(function (state) {
    if (state == 'Connected') {
      alert('connected');
    }
  });
  
  conver.chatService.start().then(function () {
    meetingUri = conver.uri();
    alert(meetingUri);
  });

  // (receiving message !)
  conver.historyService.activityItems.added(function (item) {
    if (item.type() == 'TextMessage') {
      if (item.direction() == 'Incoming') {
        alert('received message: ' + item.text());
      }
    };
  });

  alert('set-up finished');  
}

上記は Skype Web SDK を使った JavaScript の例ですが、同じ処理を UCWA の REST API でおこなうこともできます。
下記の順番で REST API を呼び出します。

  1. Ad-hoc Meeing の作成 (onlineMeetingInvitations)
  2. Text Messaging の開始 (messagingInvitation)
  3. 参加者の追加 (participantInvitation)
  4. Text Message の送信 (messages)

今回は、下記の通り、ポイントとなる処理部分だけ抜き出しますが、実際のフローは単純に 4 つの HTTP Request を投げるのではなく、「UCWA 開発入門」で解説したように、処理とイベント取得を 1 つのプログラム内で並行で処理しながら実装します。(下記で、各 id の情報は、この Event から取得されたものと仮定します。)

なお、「UCWA 開発入門」で解説したように、xxxxx.infra.lync.com の箇所は Autodiscover で検出したドメインを設定します。また、operationId は Client 側で一意な UUID を作成し、threadId は会話 (Conversation) を通して一意に使う識別子を使用してください。

1. Create Ad-hoc Meeting (UCWA)

POST https://xxxxx.infra.lync.com/ucwa/oauth/v1/applications/11339658058/communication/onlineMeetingInvitations?onlineMeetingUri=adhoc
Accept: application/json
Content-Type: application/json
Authorization: Bearer {access token}

{
  "operationId": "2ffb82e3-fdb2-43fb-80d6-75892b96701f",
  "threadId": "AdGUbu6uJy2bv7AITgejPcfRPTOmYg==",
  "subject": "",
  "importance": "Normal"
}
HTTP/1.1 201 Created

2. Start Text Messaging (UCWA)

POST https://xxxxx.infra.lync.com/ucwa/oauth/v1/applications/11339658058/communication/messagingInvitations?conversation=d2e24803-5a72-4c4e-a9c2-944846d00399
Accept: application/json
Content-Type: application/json
Authorization: Bearer {access token}

{
  "operationId": "579afffd-0282-439c-ac6e-99053fd1e420",
  "threadId": "AdGUbu6uJy2bv7AITgejPcfRPTOmYg=="
}
HTTP/1.1 201 Created

3. Add Participant (UCWA)

POST https://xxxxx.infra.lync.com/ucwa/oauth/v1/applications/11339658058/communication/participantInvitations?conversation=d2e24803-5a72-4c4e-a9c2-944846d00399
Accept: application/json
Content-Type: application/json
Authorization: Bearer {access token}

{
  "to":"sip:demouser01@o365directory.onmicrosoft.com"
}
HTTP/1.1 201 Created

以降、UCWA を使って Text Message の送信もおこなえますが、これについては「UCWA 開発入門」を参照してください。

Scheduled Meeting の作成 (API)

Exchange, Skype for Business を組み合わせて使用されたことがある方はご存じの通り、利用者は、Outlook 上から、あらかじめ予定された Meeting (Scheduled Meeting) を作成できます。(下図)

Skype Web SDK を使って Scheduled Meeting を作成するには、下記の通り createMeeting() を使用します。

今回、accessLevel を Everyone に設定して、誰でも (外部の Guest ユーザーでも) 会議に参加可能にしていますが、組織 (テナント) 内のユーザーに制限する場合は SameEnterprise を指定します。

Create Scheduled Meeting (Web SDK)

document.getElementById('btnScheduleMeeting').onclick = function () {
  // start as scheduled meeting (group conversation)
  conver = app.conversationsManager.createMeeting();
  conver.accessLevel("Everyone");
  conver.subject("Demo Meeting");
  conver.expirationTime("2016-04-30T14:00:00.000Z");
  conver.attendees.set(["sip:demouser01@o365directory.onmicrosoft.com", "sip:demouser02@o365directory.onmicrosoft.com"]);
  conver.onlineMeetingUri.get().then(function(meetingUri) {
    alert(meetingUri);
  });
}

同じく、UCMA を使って Scheduled Meeting を作成するには、下記の通り HTTP 呼び出しをおこないます。

Create Scheduled Meeting (UCWA)

POST https://xxxxx.infra.lync.com/ucwa/oauth/v1/applications/114145966763/onlineMeetings/myOnlineMeetings
Authorization: Bearer {access token}
Content-Type: application/json

{
  "accessLevel": "Everyone",
  "attendanceAnnouncementsStatus":"Disabled",
  "description":"This is a sample scheduled meeting.",
  "subject":"Please review (Demo01)",
  "expirationTime" : "\/Date(1462060800000)\/",
  "attendees":[
    "sip:demouser01@o365directory.onmicrosoft.com",
    "sip:demouser02@o365directory.onmicrosoft.com"
  ],
  "leaders":[]
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "accessLevel": "Everyone",
  "entryExitAnnouncement": "Disabled",
  "attendees": [
    "sip:demouser01@o365directory.onmicrosoft.com",
    "sip:demouser02@o365directory.onmicrosoft.com"
  ],
  "automaticLeaderAssignment": "Disabled",
  "description": "This is a sample scheduled meeting.",
  "expirationTime": "\/Date(1462060800000)\/",
  "leaders": [
  ],
  "onlineMeetingId": "CIL8FYNJ",
  "onlineMeetingUri": "sip:tsmatsuz@o365directory.onmicrosoft.com;gruu;opaque=app:conf:focus:id:CIL8FYNJ",
  "legacyOnlineMeetingUri": "conf:sip:tsmatsuz@o365directory.onmicrosoft.com;gruu;opaque=app:conf:focus:id:CIL8FYNJ?conversation-id=CIL8FYNJ",
  "onlineMeetingRel": "myOnlineMeetings",
  "organizerUri": "sip:tsmatsuz@o365directory.onmicrosoft.com",
  "phoneUserAdmission": "Disabled",
  "lobbyBypassForPhoneUsers": "Disabled",
  "subject": "Please review (Demo01)",
  "joinUrl": "https://meet.lync.com/o365directory/tsmatsuz/CIL8FYNJ",
  "f7058cc5-a354-41c3-b5d1-39883b1be0fd": "please pass this in a PUT request",
  "_links": {
    "self": {
      "href": "/ucwa/oauth/v1/applications/114145966763/onlineMeetings/myOnlineMeetings/CIL8FYNJ"
    },
    "onlineMeetingExtensions": {
      "href": "/ucwa/oauth/v1/applications/114145966763/onlineMeetings/myOnlineMeetings/CIL8FYNJ/extensions"
    },
    "ms:rtc:saas:communication": {
      "href": "https://xxxxx.infra.lync.com/ucap/v1/applications?confUrl=sip:tsmatsuz@o365directory.onmicrosoft.com;gruu;opaque=app:conf:focus:id:CIL8FYNJ"
    }
  },
  "rel": "myOnlineMeeting",
  "etag": "3931105825"
}

この HTTP Response で取得される joinUrl が、Outlook の予定 (Calendar) などに記載されている Skype for Business を起動するためのリンクになります。このため、Scheduled Meeting の作成後は、Outlook のように、皆さんのアプリケーションにもこの URL を添付しておくことなどが可能です。

補足 : Outlook を使用せず、上記の通り、Skype 側だけで Scheduled Meeting を作成した場合、Outlook の Calendar 上に予定は作成されません。(単純に、Skype for Business 内で Scheduled Meeting が作成されるだけです。)
こうしたアプリケーション連携機能 (例 : Outlook - Skype 連携など) は、アプリケーション開発者自身がおこないます。

Meeting URI と Join (API)

Meeting (Sheduled Meeting と Ad-hoc Meeting の双方) には、Meeting Uri が割り当てられています。(Meeting Uri は、sip:tsmatsuz@o365directory.onmicrosoft.com;gruu;opaque=app:conf:focus:id:ITL0OQ9P といったフォーマットです。)
この Meeting Uri の最後の Part (この例の場合、ITL0OQ9P) は Meeting の識別子 (id) であり、この識別子から導出される https://meet.lync.com/o365directory/tsmatsuz/ITL0OQ9P の形式の URL は Join Url と呼ばれていて、この URL にブラウザーを使ってアクセスすることで Skype for Business が起動され、この Meeting (会議) に参加できます。(PC の場合には、アドインを使ってブラウザーだけで Meeting に参加することも可能です。)

UCWA や Skype Web SDK を使って、こうした Meeting Uri を使った処理も可能です。

まず、Meeting Uri の取得方法ですが、Skype Web SDK の場合、下記太字の通り Meeting Uri を取得できます。(既に上述のサンプル コードには、この Uri の取得処理も入れています。)

補足 : uri() 関数は、strict mode ('use strict') では使用できないので注意してください。

Get Ad-hoc Meeting Uri (Web SDK)

document.getElementById('btnStartMeetNow').onclick = function () {
  // start as ad-hoc meeting (group conversation)
  conver = app.conversationsManager.createConversation();        
  var part = conver.createParticipant(person);
  conver.participants.add(part);
  app.conversationsManager.conversations.add(conver);

  conver.selfParticipant.chat.state.changed(function (state) {
    if (state == 'Connected') {
      alert('connected');
    }
  });
  
  conver.chatService.start().then(function () {
    meetingUri = conver.uri();
    alert(meetingUri);
  });

  // (receiving message !)
  conver.historyService.activityItems.added(function (item) {
    if (item.type() == 'TextMessage') {
      if (item.direction() == 'Incoming') {
        alert('received message: ' + item.text());
      }
    };
  });

  alert('set-up finished');  
}

Get Scheduled Meeting Uri (Web SDK)

document.getElementById('btnScheduleMeeting').onclick = function () {
  // start as scheduled meeting (group conversation)
  conver = app.conversationsManager.createMeeting();
  conver.accessLevel("Everyone");
  conver.subject("Demo Meeting");
  conver.expirationTime("2016-04-30T14:00:00.000Z");
  conver.attendees.set(["sip:demouser01@o365directory.onmicrosoft.com", "sip:demouser02@o365directory.onmicrosoft.com"]);
  conver.onlineMeetingUri.get().then(function(meetingUri) {
    alert(meetingUri);
  });
}

UCWA を使って Meeting Uri を取得するには、下記の通り呼び出します。(Scheduled Meeting の場合は、上述の通り、作成時の HTTP Response に Meeting Uri も含まれているので、これを使用してください。)

Get Meeting Uri (UCWA)

GET https://xxxxx.infra.lync.com/ucwa/oauth/v1/applications/111192445507/communication/conversations/9d1b1889-d7f9-474d-a44a-20dfc64e7414/onlineMeeting
Authorization: Bearer {access token}
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8

{
  "onlineMeetingUri": "sip:tsmatsuz@o365directory.onmicrosoft.com;gruu;opaque=app:conf:focus:id:ITL0OQ9P",
  "organizerUri": "sip:tsmatsuz@o365directory.onmicrosoft.com",
  "organizerName": "Tsuyoshi Matsuzaki",
  "disclaimerBody": "",
  "disclaimerTitle": "",
  "hostingNetwork": "SameEnterprise",
  "largeMeeting": "Disabled",
  "joinUrl": "https://meet.lync.com/o365directory/tsmatsuz/ITL0OQ9P",
  "_links": {
    "self": {
      "href": "/ucwa/oauth/v1/applications/111192445507/communication/conversations/9d1b1889-d7f9-474d-a44a-20dfc64e7414/onlineMeeting"
    },
    "conversation": {
      "href": "/ucwa/oauth/v1/applications/111192445507/communication/conversations/9d1b1889-d7f9-474d-a44a-20dfc64e7414"
    },
    "organizer": {
      "href": "/ucwa/oauth/v1/applications/111192445507/people/tsmatsuz@o365directory.onmicrosoft.com"
    },
    "phoneDialInInformation": {
      "href": "/ucwa/oauth/v1/applications/111192445507/communication/conversations/9d1b1889-d7f9-474d-a44a-20dfc64e7414/onlineMeeting/phoneDialInInformation"
    }
  },
  "rel": "onlineMeeting"
}

API を使って Meeting (会議) に参加するには、Join Url ではなく、この Meeting Uri を使います。
例えば、取得した Meeting Uri を使って、Skype Web SDK からこの会議に参加する場合は、下記の通り記述します。(下記のサンプルでは、btnJoinIM という名前のボタンを作成して、このボタンが押されたら参加します。)
もちろん、Skype for Business クライアントが起動するのではありません。これまで同様、プログラムが接続しています。(Skype for Business クライアントは不要です。)

Join Exsisting Meeting (Web SDK)

document.getElementById('btnJoinIM').onclick = function () {
  conver = app.conversationsManager.getConversationByUri(document.getElementById('txtMeetingUri').value);
  conver.chatService.start().then(function () {
      conver.chatService.sendMessage('Hello !');
  });        
}

UCWA を使って参加する場合は、下記の通りです。

Join Exsisting Meeting (UCWA)

POST https://xxxxx.infra.lync.com/ucwa/oauth/v1/applications/11325683038/communication/onlineMeetingInvitations
Authorization: Bearer {access token}
Content-Type: application/json
Accept: application/json

{
  "operationId": "0d5f4a1d-3eaf-4303-975c-2e8f29095874",
  "threadId": "AdGVpxEQcW1lGN3sQDm6tI5QnHNOZw==",
  "onlineMeetingUri": "sip:tsmatsuz@o365directory.onmicrosoft.com;gruu;opaque=app:conf:focus:id:ITL0OQ9P"
}
HTTP/1.1 201 Created

今回は API で Meeting を作成して、API で その Meeting に Join (参加) するステップで紹介していますが、最新の Outlook REST API では、Skype Meeting が設定されている場合、REST を使って Join Url も取得できます。(下記参照)
このため、Outlook から作成した予定 (Event) の Online Meeting に API から Join するアプリも構築できます。

Get "Join Url" (Outlook REST API)

GET https://outlook.office.com/api/beta/me/calendarview?startDateTime=2016-04-01T00:00:00&endDateTime=2016-04-30T23:59:59
Accept: application/json
Authorization: Bearer {access token}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "@odata.context": "https://outlook.office.com/api/beta/$metadata#Me/CalendarView",
  "value": [
    {
      "@odata.id": "https://outlook.office.com/api/beta/Users('e71b5...')/Events('AAMkA...')",
      "@odata.etag": "W/\"paYEgdxRx0+kT9IUGW+ljQAAd7NvGQ==\"",
      "Id": "AAMkA...",
      "CreatedDateTime": "2016-04-14T01:36:22.9969887Z",
      "LastModifiedDateTime": "2016-04-14T01:36:51.3109081Z",
      "ChangeKey": "paYEgdxRx0+kT9IUGW+ljQAAd7NvGQ==",
      "Categories": [
      ],
      "OriginalStartTimeZone": "Tokyo Standard Time",
      "OriginalEndTimeZone": "Tokyo Standard Time",
      "ResponseStatus": {
        "Response": "Organizer",
        "Time": "0001-01-01T00:00:00Z"
      },
      "iCalUId": "04000...",
      "ReminderMinutesBeforeStart": 15,
      "IsReminderOn": true,
      "HasAttachments": false,
      "Subject": "Document Review",
      "Body": {
        "ContentType": "HTML",
        "Content": "<html><head>..."
      },
      "BodyPreview": "Hi, ...",
      "Importance": "Normal",
      "Sensitivity": "Normal",
      "Start": {
        "DateTime": "2016-04-20T00:00:00.0000000",
        "TimeZone": "UTC"
      },
      "End": {
        "DateTime": "2016-04-20T01:00:00.0000000",
        "TimeZone": "UTC"
      },
      "Location": {
        "DisplayName": "\u30aa\u30f3\u30e9\u30a4\u30f3\u4f1a\u8b70"
      },
      "IsAllDay": false,
      "IsCancelled": false,
      "IsOrganizer": true,
      "Recurrence": null,
      "ResponseRequested": true,
      "SeriesMasterId": null,
      "ShowAs": "Busy",
      "Type": "SingleInstance",
      "Attendees": [
      ],
      "Organizer": {
        "EmailAddress": {
          "Name": "Demo Taro",
          "Address": "demouser01@o365directory.onmicrosoft.com"
        }
      },
      "WebLink": "https://outlook.office365.com/owa/?ItemID=AAMkA...&exvsurl=1&viewmodel=ICalendarItemDetailsViewModelFactory",
      "OnlineMeetingUrl": "https://meet.lync.com/o365directory/demouser01/Y3B24B2M"
    }
    ...

  ]
}

 

最後に、今回作成したサンプル全体を掲載しておきます。

<?php
// (Please change this in-memory session, if production. because not scaling)
session_start();

if(isset($_GET['code'])) {
  //
  // When auth code is supplied, get access token
  //
  $authreq = curl_init();  
  curl_setopt($authreq, CURLOPT_URL,
    'https://login.microsoftonline.com/common/oauth2/token');
  curl_setopt($authreq, CURLOPT_POST, true);  
  curl_setopt($authreq, CURLOPT_HTTPHEADER,
    array('Content-Type: application/x-www-form-urlencoded'));
  // (Please do the admin consent first, if production)
  curl_setopt($authreq, CURLOPT_POSTFIELDS, http_build_query(array(
    'grant_type' => 'authorization_code',
    'code' => $_GET['code'],
    'client_id' => '205de2e9-6fbc-40ec-aed9-9da7b48bee21',
    'client_secret' => 'WaBfOMLgHG...',
    'redirect_uri' => 'https://mydeploy.azurewebsites.net/skype_meeting.php',
  )));
  curl_setopt($authreq, CURLOPT_RETURNTRANSFER, true);
  // (Please change the following SSL verify mode, if production)
  curl_setopt($authreq, CURLOPT_SSL_VERIFYPEER, false);
  $authres = json_decode(curl_exec($authreq));
  curl_close($authreq);
  $_SESSION['access_token'] = $authres->access_token;
}

//
// If initial access, redirect page to get auth code
//
if(!isset($_SESSION['access_token']))
  header('Location: https://login.microsoftonline.com/common/oauth2/authorize'
    .'?response_type=code'
    .'&client_id='
    .'205de2e9-6fbc-40ec-aed9-9da7b48bee21'
    .'&resource='
    .urlencode('https://webdir.online.lync.com')
    .'&redirect_uri='
    .urlencode('https://mydeploy.azurewebsites.net/skype_meeting.php'));

// (Please check token, if production)
// see https://blogs.msdn.microsoft.com/tsmatsuz/2015/02/17/azure-ad-service-access-token-validation-check/
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
  <meta charset="utf-8" />
</head>
<body>
  <script src="https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js"></script>
  <button id="btnInit">1.Initialize</button>
  <button id="btnSignIn">2.Sign In</button>
  <button id="btnGetPerson">3.Get Person</button>
  <button id="btnStartMeetNow">4.Start Ad-hoc Meeting</button>
  <button id="btnScheduleMeeting">5.Schedule Meeting</button>
  <button id="btnSendIM">6.Send text message</button>
  <button id="btnJoinMeeting">7.Join Meeting</button>
  Meeting Uri:<input id="txtMeetingUri" type="text"/>
  <script>
    (function () {
      var Application;
      var app;
      var person;
      var conver;

      //
      // 1.Initialize Skype Web SDK
      //
      document.getElementById('btnInit').onclick = function () {
        Skype.initialize({
          apiKey: 'a42fcebd-5b43-4b89-a065-74450fb91255',
        }, function (api) {
          Application = api.application;
          app = new Application();
          alert('initialize succeed');
        }, function (err) {
          alert('initialize error: ' + err);
        });
      }

      //
      // 2.SignIn
      //
      document.getElementById('btnSignIn').onclick = function () {
        app.signInManager.signIn({
          "client_id": "205de2e9-6fbc-40ec-aed9-9da7b48bee21",
          "origins": ["https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root"],
          "cors": true,
          "version": 'SkypeOnlinePreviewApp/1.0.0',
          "redirect_uri": 'https://mydeploy.azurewebsites.net/skype_meeting.php'
        }).then(function () {
          alert('signed in');
        }).then(null, function (err) {
          alert('signin error: ' + err);
        });
      }

      //
      // 3.Get Person to communicate (Show status)
      //
      document.getElementById('btnGetPerson').onclick = function () {
        var personSearchQuery =
          app.personsAndGroupsManager.createPersonSearchQuery();
        personSearchQuery.text('Demo Taro');
        personSearchQuery.limit(50);
        personSearchQuery.getMore(
        ).then(function (results) {
          person = results[0].result;
          person.status.get().then(function (status) {
            alert('Status is: ' + status);
          });
        }).then(null, function (err) {
          alert('Search error: ' + err);
        });
      }

      //
      // 4.Create Meeting (Ad-hoc) and Start
      //
      document.getElementById('btnStartMeetNow').onclick = function () {
        // start as ad-hoc meeting (group conversation)
        conver = app.conversationsManager.createConversation();        
        var part = conver.createParticipant(person);
        conver.participants.add(part);
        app.conversationsManager.conversations.add(conver);

        conver.selfParticipant.chat.state.changed(function (state) {
          if (state == 'Connected') {
            alert('connected');
          }
        });
        
        conver.chatService.start().then(function () {
          alert('arrived');
          meetingUri = conver.uri();
          document.getElementById('txtMeetingUri').value = meetingUri;
        });

        // (receiving message !)
        conver.historyService.activityItems.added(function (item) {
          if (item.type() == 'TextMessage') {
            if (item.direction() == 'Incoming') {
              alert('received message: ' + item.text());
            }
          };
        });

        alert('set-up finished');  
      }
      
      //
      // 5.Create Meeting (Scheduled)
      //
      document.getElementById('btnScheduleMeeting').onclick = function () {
        // start as scheduled meeting (group conversation)
        conver = app.conversationsManager.createMeeting();
        conver.accessLevel("Everyone");
        conver.subject("Demo Meeting");
        conver.expirationTime("2016-04-30T14:00:00.000Z");
        conver.attendees.set(["sip:demouser01@o365directory.onmicrosoft.com", "sip:demouser02@o365directory.onmicrosoft.com"]);
        conver.onlineMeetingUri.get().then(function(meetingUri) {
          document.getElementById('txtMeetingUri').value = meetingUri;
        });
      }
      
      //
      // 6.Send text message
      //
      document.getElementById('btnSendIM').onclick = function () {
        conver.chatService.sendMessage('hello world !');
      }

      //
      // 7.Join conversation
      //
      document.getElementById('btnJoinMeeting').onclick = function () {
        conver = app.conversationsManager.getConversationByUri(document.getElementById('txtMeetingUri').value);
        conver.chatService.start().then(function () {
            conver.chatService.sendMessage('Hello !');
        });        
      }

    }());
  </script>
</body>
</html>
Comments (0)

Skip to main content