12
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Quad incAdvent Calendar 2015

Day 24

会社のインターホン代わりを作る <ブラウザから電話編>

Last updated at Posted at 2015-12-24

前回SMSを飛ばすサンプルプログラムの実行までを試しましたが、今回はTwilio クライアント JavaScript APIを使用し電話をかける部分を作ります。

※ローカルの開発環境の方は、この先のTwilio クライアント JavaScript APIを使用した電話発信には外部公開サーバが必要です。ローカル環境からの発信には最下部を参照して下さい。

###1.TwiML APPSを作成する
スクリーンショット_2015-12-24_20_37_13.png

###2.アプリ構成
・quadclient.php (メイン画面&コール)
・quad-client-twiml.php (電話番号選定)
・base.css
・normalize.css https://github.com/necolas/normalize.css/

それからTwilio-phpヘルパーライブラリー
https://jp.twilio.com/docs/php/install

###3.画面を作成
こんなページを作成しました。
スクリーンショット 2015-12-24 20.48.17.png

こちらのソースコードをベースにしています。

https://jp.twilio.com/docs/quickstart/php/client/outgoing-calls

quadclient.php
<?php
include '../twilio-php/Services/Twilio/Capability.php';

// put your Twilio API credentials here
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken  = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY';

// put your Twilio Application Sid here
// 取得したTwiml APP のSidを設定
$appSid     = 'APZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ';

// put your default Twilio Client name here
$clientName = 'QuadPhone';

// get the Twilio Client name from the page request parameters, if given
if (isset($_REQUEST['client'])) {
    $clientName = $_REQUEST['client'];
}

$capability = new Services_Twilio_Capability($accountSid, $authToken);
$capability->allowClientOutgoing($appSid);
$capability->allowClientIncoming($clientName);
$token = $capability->generateToken();
?>

<!DOCTYPE html>
<html>
  <head>
    <title>Quad Client</title>
		<meta charset="utf-8">
		<meta name="viewport" content="initial-scale=1.0">
		<link href="css/normalize.css" rel="stylesheet" type="text/css">
		<link href="css/base.css" rel="stylesheet" type="text/css">
		<link href='https://fonts.googleapis.com/css?family=Roboto:400,100,300,500,700,900' rel='stylesheet' type='text/css'>

    <script type="text/javascript"
      src="//static.twilio.com/libs/twiliojs/1.2/twilio.min.js"></script>
    <script type="text/javascript"
      src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
    </script>

  	</head>

    <script type="text/javascript">

      Twilio.Device.setup("<?php echo $token; ?>");

      Twilio.Device.ready(function (device) {
        $("#log").text("Client '<?php echo $clientName ?>' is ready");
      });

      Twilio.Device.error(function (error) {
        $("#log").text("Error: " + error.message);
      });

      Twilio.Device.connect(function (conn) {
        $("#log").text("Successfully established call");
      });

      Twilio.Device.disconnect(function (conn) {
        $("#log").text("Call ended");
      });

      Twilio.Device.incoming(function (conn) {
        $("#log").text("Incoming connection from " + conn.parameters.From);
        // accept the incoming connection and start two-way audio
        conn.accept();
      });

      Twilio.Device.presence(function (pres) {
        if (pres.available) {
          // create an item for the client that became available
          $("<li>", {id: pres.from, text: pres.from}).click(function () {
            $("#number").val(pres.from);
            call();
          }).prependTo("#people");
        }
        else {
          // find the item by client name and remove it
          $("#" + pres.from).remove();
        }
      });

      // クリックされた要素でコール先を変更する仕様に改変
      function call(obj) {
        // get the phone number or client to connect the call to
        params = {"PhoneNumber": obj.id};
        Twilio.Device.connect(params);
      }

      function hangup() {
        Twilio.Device.disconnectAll();
      }
    </script>
  </head>
  <body>

		<div class="title-area">
      <h1><div id="log">Loading...</div></h1>
		</div>

		<div class="container">
			<ul class="glid-block">
				<li class="glid-cell">
          <button onClick="call(this);" id="fushimi">
  					<div class="image-block">
  						<img src="img/face.png" alt="">
  					</div>
  					<p class="number">fushimi</p>
          </button>
				</li>
        
				<li class="glid-cell">
          <button onClick="call(this);" id="segawa">
						<div class="image-block">
							<img src="img/face.png" alt="">
						</div>
						<p>segawa</p>
					</button>
				</li>
				<li class="glid-cell">
          <button onClick="call(this);" id="sasaki">
						<div class="image-block">
							<img src="img/face.png" alt="">
						</div>
						<p>sasaki</p>
					</button>
				</li>
			</ul>
		</div>

		<div class="general-foot">
  		<li>
        <button class="hangup general-hangup" onclick="hangup();">
          Hangup
        </button>
  		</li>
  		<li>
        <button class="call general-call" onclick="call(this);" id="office">
          Call to main phone
        </button>
  		</li>
		</div>
  </body>
</html>

quad-client-twiml.php
<?php
header('Content-type: text/xml');

// put a phone number you've verified with Twilio to use as a caller ID number
$callerId = "+16698004184";

// put your default Twilio Client name here, for when a phone number isn't given
$number   = "+81358296297";

$member = array("fushimi" => "+818000000000",
                "segawa" =>  "+818000000001",
                "sasaki" =>  "+818000000002",
                "office" => "+813000000003");

// 受け取ったパラメータの名前でコール先を決定
if (isset($_REQUEST['PhoneNumber'])) {
  if (array_key_exists(htmlspecialchars($_REQUEST['PhoneNumber']),$member)){
    $number = $member[htmlspecialchars($_REQUEST['PhoneNumber'])];
  }
}

// wrap the phone number or client name in the appropriate TwiML verb
// by checking if the number given has only digits and format symbols
if (preg_match("/^[\d\+\-\(\) ]+$/", $number)) {
    $numberOrClient = "<Number>" . $number . "</Number>";
} else {
    $numberOrClient = "<Client>" . $number . "</Client>";
}
?>

<Response>
    <Dial callerId="<?php echo $callerId ?>">
          <?php echo $numberOrClient ?>
    </Dial>
</Response>

base.css
button{
  border: none;
  background: none;
}

/* line 4, ../scss/_original.scss */
body {
  background-color: #f7f7f7;
  font-family: 'Roboto', sans-serif;
  position: relative; }

/* line 10, ../scss/_original.scss */
.title-area {
  padding: 40px 0; }
/* line 13, ../scss/_original.scss */
.title-area h1 {
  font-size: 48px;
  font-weight: 100;
  text-align: center;
  margin: 0; }

/* line 21, ../scss/_original.scss */
.container {
  display: block;
  overflow: scroll;
  padding: 0 10%;
  width: 100%;
  max-height: 76%; }

/* line 38, ../scss/_original.scss */
.glid-block {
  display: block;
  width: 100%;
  height: auto;
  padding: 0;
  margin: 0; }
/* line 45, ../scss/_original.scss */
.glid-block:after {
  content: "";
  display: table;
  clear: both; }

/* line 52, ../scss/_original.scss */
.glid-cell {
  display: block;
  width: 33.333333%;
  padding: 16px 20px;
  float: left; }
/* line 59, ../scss/_original.scss */
.glid-cell a {
  display: block;
  width: 100%;
  height: 100%;
  color: #333;
  text-decoration: none; }
/* line 68, ../scss/_original.scss */
.glid-cell .image-block {
  display: block;
  width: 100%;
  border-radius: 50%;
  background-color: #fff;
  overflow: hidden;
  line-height: 0; }
/* line 76, ../scss/_original.scss */
.glid-cell .image-block img {
  width: 100%; }
/* line 81, ../scss/_original.scss */
.glid-cell p {
  text-align: center;
  font-size: 16px; }

/* line 88, ../scss/_original.scss */
.general-foot {
  display: table;
  width: 100%;
  padding: 40px 10%;
  position: fixed;
  bottom: 0;
  background-color: #f7f7f7; }
/* line 96, ../scss/_original.scss */
.general-foot li{
  display: table-cell;
  vertical-align: middle;
  text-align: center;
  width: 50%;
  padding-left: 10px;
  padding-right: 10px;
}
.general-foot .general-call {
  display: block;
  text-align: center;
  text-decoration: none;
  font-size: 16px;
  color: #fff;
  width: 100%;
  border-radius: 24px;
  padding: 1em;
  background-color: #4dce52; }
.general-foot .general-hangup {
  display: block;
  text-align: center;
  text-decoration: none;
  font-size: 16px;
  color: #fff;
  width: 100%;
  border-radius: 24px;
  padding: 1em;
  background-color: #e65172; }

/* line 10, ../scss/base.scss */
* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  -ms-box-sizing: border-box;
  -o-box-sizing: border-box;
  box-sizing: border-box; }

/* line 19, ../scss/base.scss */
html {
  font-size: 62.5%; }
@media screen and (max-width: 800px) {
  /* line 19, ../scss/base.scss */
  html {
    font-size: 54.7%; } }

/* line 29, ../scss/base.scss */
body {
  font-size: 1.0rem;
  line-height: 1;
  color: #363636;
  word-wrap: break-word;
  vertical-align: middle; }

/* line 42, ../scss/base.scss */
html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  position: relative; }

今回iPadでいい感じに見えるように組んで、いざiPad Air(iOS9.1)で検証してみるとTwilio APIがLoadingのまま止まってしまい、iPadのSafariでは動かなかった。
PCの方はOSX(El Capitan)のSafari9で動作確認済み。
iPadで使えるようにするにはアプリ化するか、と思ったクリスマスイブの夜でした。。

おまけ。
ローカル開発環境から電話発信する場合にはApp SIDが不要な下記の記述で可能です。

<?php
// Get the PHP helper library from twilio.com/docs/php/install
require_once('twilio-php/Services/Twilio.php'); // 環境に合わせて変えて下さい
 
// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 
$token = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"; 
$client = new Services_Twilio($sid, $token);
 
$call = $client->account->calls->create("+1NNNNNNNNNN", "+81NNNNNNNNNN", "http://demo.twilio.com/docs/voice.xml", array());
// echo $call->sid;

最終的には社内に居てSlackで着席状況を確認してコール可能な人だけ、表示するなどステータス更新できると良いなと。
Slack botも強化が必要そうだ。。

12
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?