Hôm nay mình sẽ hướng dẫn các bạn generate token agora phục vụ cho video call
Tạo file app/Libs/Agora/AccessToken.php
<?php
namespace App\Libs\Agora;
use App\Libs\Agora\Message;
class AccessToken
{
public static $Privileges = array(
"kJoinChannel" => 1,
"kPublishAudioStream" => 2,
"kPublishVideoStream" => 3,
"kPublishDataStream" => 4,
"kPublishAudioCdn" => 5,
"kPublishVideoCdn" => 6,
"kRequestPublishAudioStream" => 7,
"kRequestPublishVideoStream" => 8,
"kRequestPublishDataStream" => 9,
"kInvitePublishAudioStream" => 10,
"kInvitePublishVideoStream" => 11,
"kInvitePublishDataStream" => 12,
"kAdministrateChannel" => 101,
"kRtmLogin" => 1000,
);
public $appID;
public $appCertificate;
public $channelName;
public $uid;
public $message;
public function __construct()
{
$this->message = new Message();
}
public function setUid($uid)
{
if ($uid === 0) {
$this->uid = "";
} else {
$this->uid = $uid . '';
}
}
public function isNonemptyString($name, $str)
{
if (is_string($str) && $str !== "") {
return true;
}
echo $name . " check failed, should be a non-empty string";
return false;
}
public static function init($appID, $appCertificate, $channelName, $uid)
{
$accessToken = new AccessToken();
if (!$accessToken->isNonemptyString("appID", $appID) ||
!$accessToken->isNonemptyString("appCertificate", $appCertificate) ||
!$accessToken->isNonemptyString("channelName", $channelName)) {
return null;
}
$accessToken->appID = $appID;
$accessToken->appCertificate = $appCertificate;
$accessToken->channelName = $channelName;
$accessToken->setUid($uid);
$accessToken->message = new Message();
return $accessToken;
}
public static function initWithToken($token, $appCertificate, $channel, $uid)
{
$accessToken = new AccessToken();
if (!$accessToken->extract($token, $appCertificate, $channel, $uid)) {
return null;
}
return $accessToken;
}
public function addPrivilege($key, $expireTimestamp)
{
$this->message->privileges[$key] = $expireTimestamp;
return $this;
}
public function extract($token, $appCertificate, $channelName, $uid)
{
$ver_len = 3;
$appid_len = 32;
$version = substr($token, 0, $ver_len);
if ($version !== "006") {
echo 'invalid version ' . $version;
return false;
}
if (!$this->isNonemptyString("token", $token) ||
!$this->isNonemptyString("appCertificate", $appCertificate) ||
!$this->isNonemptyString("channelName", $channelName)) {
return false;
}
$appid = substr($token, $ver_len, $appid_len);
$content = (base64_decode(substr($token, $ver_len + $appid_len, strlen($token) - ($ver_len + $appid_len))));
$pos = 0;
$strPost = "0";
$len = unpack("v", $content . substr($strPost, 2))[1];
$pos += 2;
$sig = substr($content, $pos, $len);
$pos += $len;
$crc_channel = unpack("V", substr($content, $pos, 4))[1];
$pos += 4;
$crc_uid = unpack("V", substr($content, $pos, 4))[1];
$pos += 4;
$msgLen = unpack("v", substr($content, $pos, 2))[1];
$pos += 2;
$msg = substr($content, $pos, $msgLen);
$this->appID = $appid;
$message = new Message();
$message->unpackContent($msg);
$this->message = $message;
//non reversable values
$this->appCertificate = $appCertificate;
$this->channelName = $channelName;
$this->setUid($uid);
return true;
}
public function build()
{
$msg = $this->message->packContent();
$val = array_merge(
unpack("C*", $this->appID),
unpack("C*", $this->channelName),
unpack("C*", $this->uid),
$msg
);
$sig = hash_hmac('sha256', implode(array_map("chr", $val)), $this->appCertificate, true);
$crc_channel_name = crc32($this->channelName) & 0xffffffff;
$crc_uid = crc32($this->uid) & 0xffffffff;
$content = array_merge(
unpack("C*", $this->packString($sig)),
unpack("C*", pack("V", $crc_channel_name)),
unpack("C*", pack("V", $crc_uid)),
unpack("C*", pack("v", count($msg))),
$msg
);
$version = "006";
$ret = $version . $this->appID . base64_encode(implode(array_map("chr", $content)));
return $ret;
}
public function packString($value)
{
return pack("v", strlen($value)) . $value;
}
}
Tạo file app/Libs/Agora/Message.php
<?php
namespace App\Libs\Agora;
class Message
{
public $salt;
public $ts;
public $privileges;
public function __construct()
{
$this->salt = rand(0, 100000);
$date = new \DateTime("now", new \DateTimeZone('UTC'));
$this->ts = $date->getTimestamp() + 24 * 3600;
$this->privileges = array();
}
public function packContent()
{
$buffer = unpack("C*", pack("V", $this->salt));
$buffer = array_merge($buffer, unpack("C*", pack("V", $this->ts)));
$buffer = array_merge($buffer, unpack("C*", pack("v", count($this->privileges))));
foreach ($this->privileges as $key => $value) {
$buffer = array_merge($buffer, unpack("C*", pack("v", $key)));
$buffer = array_merge($buffer, unpack("C*", pack("V", $value)));
}
return $buffer;
}
public function unpackContent($msg)
{
$pos = 0;
$salt = unpack("V", substr($msg, $pos, 4))[1];
$pos += 4;
$ts = unpack("V", substr($msg, $pos, 4))[1];
$pos += 4;
$size = unpack("v", substr($msg, $pos, 2))[1];
$pos += 2;
$privileges = array();
for ($i = 0; $i < $size; $i++) {
$key = unpack("v", substr($msg, $pos, 2));
$pos += 2;
$value = unpack("V", substr($msg, $pos, 4));
$pos += 4;
$privileges[$key[1]] = $value[1];
}
$this->salt = $salt;
$this->ts = $ts;
$this->privileges = $privileges;
}
}
Tạo file app/Libs/Agora/RtmTokenBuilder.php
<?php
namespace App\Libs\Agora;
use App\Libs\Agora\AccessToken;
class RtmTokenBuilder
{
const ROLE_RTM_USER = 1;
# appID: The App ID issued to you by Agora. Apply for a new App ID from
# Agora Dashboard if it is missing from your kit. See Get an App ID.
# appCertificate: Certificate of the application that you registered in
# the Agora Dashboard. See Get an App Certificate.
# channelName:Unique channel name for the AgoraRTC session in the string format
# userAccount: The user account.
# role: Role_Rtm_User = 1
# privilegeExpireTs: represented by the number of seconds elapsed since
# 1/1/1970. If, for example, you want to access the
# Agora Service within 10 minutes after the token is
# generated, set expireTimestamp as the current
# timestamp + 600 (seconds)./
public static function buildToken($appID, $appCertificate, $userAccount, $role, $privilegeExpireTs)
{
$token = AccessToken::init($appID, $appCertificate, $userAccount, '');
$Privileges = AccessToken::$Privileges;
$token->addPrivilege($Privileges["kRtmLogin"], $privilegeExpireTs);
return $token->build();
}
}
Tạo file app/Services/AgoraService.php
<?php
namespace App\Services;
use App\Libs\Agora\AccessToken;
use App\Libs\Agora\RtmTokenBuilder;
use Log;
class AgoraService
{
private $appID;
private $appCertificate;
public function __construct()
{
$this->appID = config('agora.app_id');
$this->appCertificate = config('agora.app_certificate');
}
public function getRtcToken(string $channelName, int $uid = 0, int $expireTimestamp = 0)
{
try {
$builder = AccessToken::init($this->appID, $this->appCertificate, $channelName, $uid);
$builder->addPrivilege(AccessToken::$Privileges["kJoinChannel"], $expireTimestamp);
return $builder->build();
} catch (\Exception $e) {
Log::error('[AGORA_GENERATE_RTC_TOKEN_ERROR] '. $e->getMessage());
return false;
}
}
public function getRtmToken(string $channelName, int $expireTimestamp = 0)
{
try {
$token = RtmTokenBuilder::buildToken(
$this->appID,
$this->appCertificate,
$channelName,
RtmTokenBuilder::ROLE_RTM_USER,
$expireTimestamp
);
return $token;
} catch (\Exception $e) {
Log::error('[AGORA_GENERATE_RTM_TOKEN_ERROR] '. $e->getMessage());
return false;
}
}
}
Tạo file app/config/agora.php
<?php
return [
'app_id' => env('AGORA_APP_ID', null),
'app_certificate' => env('AGORA_APP_CERTIFICATE', null),
];
Tạo controller app/Http/Controller/AgoraController.php
generate token
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Services\AgoraService;
use Webpatser\Uuid\Uuid;
use Exception;
class AgoraController extends Controller
{
/**
* @var AgoraService
*/
protected $agoraService;
public function __construct()
{
$this->agoraService = app(AgoraService::class);
}
public function generateToken()
{
try {
$channelName = (string) Uuid::generate(4);
// Rtc token dùng để video call
$token = $this->agoraService->getRtcToken($channelName);
// Rtm token dùng để chat
$rtmToken = $this->agoraService->getRtmToken($channelName);
if (!$token || !$rtmToken) {
$this->error('Generate token error');
}
$data = [
'channel_name' => $channelName,
'token' => $token,
'rtm_token' => $rtmToken,
];
return $this->success($data);
} catch (Exception $e) {
return $this->error($e->getMessage());
}
}
}
Tài liệu tham khảo agora generate token