Skip to content

Commit 784ba64

Browse files
Merge pull request #287 from opentok/feature/sip-enhancements
Feature/sip enhancements
2 parents 1bf0c0f + 4fc7997 commit 784ba64

File tree

6 files changed

+209
-4
lines changed

6 files changed

+209
-4
lines changed

src/OpenTok/OpenTok.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ public function dial($sessionId, $token, $sipUri, $options = [])
743743
'headers' => [],
744744
'secure' => true,
745745
'from' => null,
746+
'video' => false,
746747
);
747748
$options = array_merge($defaults, array_intersect_key($options, $defaults));
748749
list($headers, $secure, $from) = array_values($options);
@@ -763,6 +764,29 @@ public function dial($sessionId, $token, $sipUri, $options = [])
763764
return new SipCall($sipJson);
764765
}
765766

767+
/**
768+
* Plays a DTMF string into a session or to a specific connection
769+
*
770+
* @param string $sessionId The ID of the OpenTok session that the participant being called
771+
* will join.
772+
*
773+
* @param string $digits DTMF digits to play
774+
* Valid DTMF digits are 0-9, p, #, and * digits. 'p' represents a 500ms pause if a delay is
775+
* needed during the input process.
776+
*
777+
* @param string $connectionId An optional parameter used to send the DTMF tones to a specific connection in a session.
778+
*
779+
* @return void
780+
*/
781+
public function playDTMF(string $sessionId, string $digits, string $connectionId = null): void
782+
{
783+
Validators::validateSessionIdBelongsToKey($sessionId, $this->apiKey);
784+
Validators::validateDTMFDigits($digits);
785+
786+
$this->client->playDTMF($sessionId, $digits, $connectionId);
787+
788+
}
789+
766790
/**
767791
* Sends a signal to clients (or a specific client) connected to an OpenTok session.
768792
*

src/OpenTok/Util/Client.php

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OpenTok\Util;
44

5+
use Exception as GlobalException;
56
use OpenTok\Layout;
67
use Firebase\JWT\JWT;
78
use OpenTok\MediaMode;
@@ -13,6 +14,7 @@
1314
use Psr\Http\Message\RequestInterface;
1415
use OpenTok\Exception\ArchiveException;
1516
use GuzzleHttp\Exception\ClientException;
17+
use GuzzleHttp\Exception\GuzzleException;
1618
use GuzzleHttp\Exception\ServerException;
1719
use OpenTok\Exception\BroadcastException;
1820
use GuzzleHttp\Exception\RequestException;
@@ -475,7 +477,18 @@ public function setStreamClassLists($sessionId, $payload)
475477
}
476478
}
477479

478-
480+
/**
481+
* @param string $sessionId
482+
* @param string $token
483+
* @param string $sipUri
484+
* @param array{secure: bool, headers?: array<string, string>, auth?: array{username: string, password: string}, from?: string, video?: boolean} $options
485+
* @return array{id: string, streamId: string, connectId: string}
486+
* @throws AuthenticationException
487+
* @throws DomainException
488+
* @throws UnexpectedValueException
489+
* @throws GlobalException
490+
* @throws GuzzleException
491+
*/
479492
public function dial($sessionId, $token, $sipUri, $options)
480493
{
481494
$body = array(
@@ -487,17 +500,22 @@ public function dial($sessionId, $token, $sipUri, $options)
487500
)
488501
);
489502

490-
if (isset($options) && array_key_exists('headers', $options) && count($options['headers']) > 0) {
503+
if (array_key_exists('headers', $options) && count($options['headers']) > 0) {
491504
$body['sip']['headers'] = $options['headers'];
492505
}
493506

494-
if (isset($options) && array_key_exists('auth', $options)) {
507+
if (array_key_exists('auth', $options)) {
495508
$body['sip']['auth'] = $options['auth'];
496509
}
497-
if (isset($options) && array_key_exists('from', $options)) {
510+
511+
if (array_key_exists('from', $options)) {
498512
$body['sip']['from'] = $options['from'];
499513
}
500514

515+
if (array_key_exists('video', $options)) {
516+
$body['sip']['video'] = (bool) $options['video'];
517+
}
518+
501519
// set up the request
502520
$request = new Request('POST', '/v2/project/' . $this->apiKey . '/call');
503521

@@ -510,9 +528,35 @@ public function dial($sessionId, $token, $sipUri, $options)
510528
} catch (\Exception $e) {
511529
$this->handleException($e);
512530
}
531+
513532
return $sipJson;
514533
}
515534

535+
public function playDTMF(string $sessionId, string $digits, string $connectionId = null): void
536+
{
537+
$route = sprintf('/v2/projects/%s/session/%s/play-dtmf', $this->apiKey, $sessionId);
538+
if ($connectionId) {
539+
$route = sprintf(
540+
'/v2/projects/%s/session/%s/connection/%s/play-dtmf',
541+
$this->apiKey,
542+
$sessionId,
543+
$connectionId
544+
);
545+
}
546+
547+
$request = new Request('POST', $route);
548+
try {
549+
$this->client->send($request, [
550+
'debug' => $this->isDebug(),
551+
'json' => [
552+
'digits' => $digits
553+
]
554+
]);
555+
} catch (\Exception $e) {
556+
$this->handleException($e);
557+
}
558+
}
559+
516560
/**
517561
* Signal either an entire session or a specific connection in a session
518562
*

src/OpenTok/Util/Validators.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ public static function validateDefaultTimeout($timeout)
327327
}
328328
}
329329

330+
public static function validateDTMFDigits(string $digits): void
331+
{
332+
if (preg_match('/^[\dp\#\*]+$/', $digits)) {
333+
return;
334+
}
335+
336+
throw new InvalidArgumentException('DTMF digits can only support 0-9, p, #, and * characters');
337+
}
338+
330339
// Helpers
331340

332341
// credit: http://stackoverflow.com/a/173479

tests/OpenTokTest/OpenTokTest.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@
77
use OpenTok\OpenTok;
88
use OpenTok\MediaMode;
99
use ArgumentCountError;
10+
use DomainException;
11+
use Exception;
12+
use GuzzleHttp\Exception\GuzzleException;
1013
use OpenTok\OutputMode;
1114
use OpenTok\ArchiveMode;
1215
use OpenTok\Util\Client;
1316
use GuzzleHttp\Middleware;
1417
use GuzzleHttp\HandlerStack;
1518
use PHPUnit\Framework\TestCase;
1619
use GuzzleHttp\Handler\MockHandler;
20+
use InvalidArgumentException as GlobalInvalidArgumentException;
21+
use OpenTok\Exception\AuthenticationException;
22+
use OpenTok\Exception\DomainException as ExceptionDomainException;
1723
use OpenTok\Exception\InvalidArgumentException;
24+
use RuntimeException;
25+
use OpenTok\Exception\UnexpectedValueException;
1826

1927
define('OPENTOK_DEBUG', true);
2028

@@ -1633,6 +1641,118 @@ public function testSipCallFrom()
16331641
$this->assertEquals($from, $body->sip->from);
16341642
}
16351643

1644+
public function testSipCallVideo()
1645+
{
1646+
// Arrange
1647+
$this->setupOTWithMocks([[
1648+
'code' => 200,
1649+
'headers' => [
1650+
'Content-Type' => 'application/json'
1651+
],
1652+
'path' => 'v2/project/APIKEY/dial'
1653+
]]);
1654+
1655+
$sessionId = '1_MX4xMjM0NTY3OH4-VGh1IEZlYiAyNyAwNDozODozMSBQU1QgMjAxNH4wLjI0NDgyMjI';
1656+
$bogusToken = 'T1==TEST';
1657+
$bogusSipUri = 'sip:[email protected]';
1658+
1659+
// Act
1660+
$sipCall = $this->opentok->dial($sessionId, $bogusToken, $bogusSipUri, ['video' => true]);
1661+
1662+
// Assert
1663+
$this->assertInstanceOf('OpenTok\SipCall', $sipCall);
1664+
$this->assertNotNull($sipCall->id);
1665+
$this->assertNotNull($sipCall->connectionId);
1666+
$this->assertNotNull($sipCall->streamId);
1667+
1668+
$this->assertCount(1, $this->historyContainer);
1669+
$request = $this->historyContainer[0]['request'];
1670+
1671+
$body = json_decode($request->getBody());
1672+
$this->assertEquals(true, $body->sip->video);
1673+
}
1674+
1675+
public function testPlayDTMF()
1676+
{
1677+
$this->setupOTWithMocks([[
1678+
'code' => 200,
1679+
'headers' => [
1680+
'Content-Type' => 'application/json'
1681+
],
1682+
'path' => 'v2/project/APIKEY/session/SESSIONID/play-dtmf'
1683+
]]);
1684+
1685+
$sessionId = '1_MX4xMjM0NTY3OH4-VGh1IEZlYiAyNyAwNDozODozMSBQU1QgMjAxNH4wLjI0NDgyMjI';
1686+
$digits = '1p713#';
1687+
1688+
$this->opentok->playDTMF($sessionId, $digits);
1689+
1690+
$this->assertCount(1, $this->historyContainer);
1691+
$request = $this->historyContainer[0]['request'];
1692+
1693+
$body = json_decode($request->getBody());
1694+
$this->assertEquals($digits, $body->digits);
1695+
}
1696+
1697+
public function testPlayDTMFIntoConnection()
1698+
{
1699+
$this->setupOTWithMocks([[
1700+
'code' => 200,
1701+
'headers' => [
1702+
'Content-Type' => 'application/json'
1703+
],
1704+
'path' => 'v2/project/APIKEY/session/SESSIONID/play-dtmf'
1705+
]]);
1706+
1707+
$sessionId = '1_MX4xMjM0NTY3OH4-VGh1IEZlYiAyNyAwNDozODozMSBQU1QgMjAxNH4wLjI0NDgyMjI';
1708+
$connectionId = 'da9cb410-e29b-4c2d-ab9e-fe65bf83fcaf';
1709+
$digits = '1p713#';
1710+
1711+
$this->opentok->playDTMF($sessionId, $digits, $connectionId);
1712+
1713+
$this->assertCount(1, $this->historyContainer);
1714+
$request = $this->historyContainer[0]['request'];
1715+
1716+
$body = json_decode($request->getBody());
1717+
$this->assertEquals($digits, $body->digits);
1718+
}
1719+
1720+
public function testDTMFFailsValidation()
1721+
{
1722+
$this->expectException(\InvalidArgumentException::class);
1723+
$this->expectExceptionMessage('DTMF digits can only support 0-9, p, #, and * characters');
1724+
1725+
$this->setupOT();
1726+
$sessionId = '1_MX4xMjM0NTY3OH4-VGh1IEZlYiAyNyAwNDozODozMSBQU1QgMjAxNH4wLjI0NDgyMjI';
1727+
$this->opentok->playDTMF($sessionId, 'bob');
1728+
}
1729+
1730+
/**
1731+
* Tests that we properly handle a 400 error from the API
1732+
* Ideally with the validator we fail before the API request is even made,
1733+
* but this will make sure that we still properly handle a 400 error. For
1734+
* this to work we do send a valid DTMF string however, to satisfy the
1735+
* validator.
1736+
*/
1737+
public function testPlayDTMFThrows400(): void
1738+
{
1739+
$this->expectException(DomainException::class);
1740+
$this->expectExceptionMessage('The OpenTok API request failed: Invalid DTMF Digits');
1741+
1742+
$this->setupOTWithMocks([[
1743+
'code' => 400,
1744+
'headers' => [
1745+
'Content-Type' => 'application/json'
1746+
],
1747+
'path' => 'v2/project/APIKEY/session/SESSIONID/play-dtmf-400'
1748+
]]);
1749+
1750+
$sessionId = '1_MX4xMjM0NTY3OH4-VGh1IEZlYiAyNyAwNDozODozMSBQU1QgMjAxNH4wLjI0NDgyMjI';
1751+
$digits = '1p713#';
1752+
1753+
$this->opentok->playDTMF($sessionId, $digits);
1754+
}
1755+
16361756
public function testSignalData()
16371757
{
16381758
// Arrange
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"code" : 200,
3+
"message" : "OK"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"code" : 400,
3+
"message" : "Invalid DTMF Digits"
4+
}

0 commit comments

Comments
 (0)