新增功能

This commit is contained in:
Your Name
2026-03-24 16:32:56 +08:00
parent 250d173c2f
commit 9160c36735
248 changed files with 3063 additions and 250 deletions
@@ -0,0 +1,167 @@
<?php
declare(strict_types=1);
namespace app\common\service;
use think\facade\Log;
/**
* 腾讯云 TRTC 云端录制(CreateCloudRecording / DeleteCloudRecording
* 依赖:composer require tencentcloud/trtc
*/
class TrtcCloudRecordingService
{
public static function sdkAvailable(): bool
{
return class_exists(\TencentCloud\Trtc\V20190722\TrtcClient::class);
}
/**
* @return array{ok:bool,task_id?:string,message?:string}
*/
public static function startMixRecording(
int $sdkAppId,
string $roomId,
string $botUserId,
string $botUserSig
): array {
if (!self::sdkAvailable()) {
return ['ok' => false, 'message' => '未安装 tencentcloud/trtc,请在 server 目录执行 composer update'];
}
$secretId = trim((string)config('trtc.api_secret_id', ''));
$secretKey = trim((string)config('trtc.api_secret_key', ''));
if ($secretId === '' || $secretKey === '') {
return ['ok' => false, 'message' => '未配置 trtc.api_secret_id / trtc.api_secret_keyCAM 密钥)'];
}
if ($sdkAppId <= 0) {
return ['ok' => false, 'message' => 'SdkAppId 无效'];
}
if (self::trtcUserSigSecretKey() === '') {
return ['ok' => false, 'message' => '未配置 TRTC UserSig 密钥(project.trtc.secretKey'];
}
$roomIdType = ctype_digit($roomId) ? 1 : 0;
$region = (string)config('trtc.recording_api_region', 'ap-guangzhou');
try {
$cred = new \TencentCloud\Common\Credential($secretId, $secretKey);
$httpProfile = new \TencentCloud\Common\Profile\HttpProfile();
$httpProfile->setEndpoint('trtc.tencentcloudapi.com');
$clientProfile = new \TencentCloud\Common\Profile\ClientProfile();
$clientProfile->setHttpProfile($httpProfile);
$client = new \TencentCloud\Trtc\V20190722\TrtcClient($cred, $region, $clientProfile);
$req = new \TencentCloud\Trtc\V20190722\Models\CreateCloudRecordingRequest();
$req->SdkAppId = $sdkAppId;
$req->RoomId = (string)$roomId;
$req->RoomIdType = $roomIdType;
$req->UserId = $botUserId;
$req->UserSig = $botUserSig;
$recordParams = new \TencentCloud\Trtc\V20190722\Models\RecordParams();
$recordParams->RecordMode = 2;
$recordParams->StreamType = 0;
$recordParams->MaxIdleTime = 300;
$req->RecordParams = $recordParams;
$tencentVod = new \TencentCloud\Trtc\V20190722\Models\TencentVod();
$tencentVod->ExpireTime = 0;
$cloudVod = new \TencentCloud\Trtc\V20190722\Models\CloudVod();
$cloudVod->TencentVod = $tencentVod;
$storage = new \TencentCloud\Trtc\V20190722\Models\StorageParams();
$storage->CloudVod = $cloudVod;
$req->StorageParams = $storage;
$videoParams = new \TencentCloud\Trtc\V20190722\Models\VideoParams();
$videoParams->Width = 720;
$videoParams->Height = 1280;
$videoParams->Fps = 15;
$videoParams->BitRate = 1000000;
$videoParams->Gop = 2;
$mixTc = new \TencentCloud\Trtc\V20190722\Models\MixTranscodeParams();
$mixTc->VideoParams = $videoParams;
$req->MixTranscodeParams = $mixTc;
$mixLayout = new \TencentCloud\Trtc\V20190722\Models\MixLayoutParams();
$mixLayout->MixLayoutMode = 3;
$req->MixLayoutParams = $mixLayout;
$resp = $client->CreateCloudRecording($req);
$taskId = $resp->TaskId ?? '';
if ($taskId === '') {
return ['ok' => false, 'message' => 'CreateCloudRecording 未返回 TaskId'];
}
return ['ok' => true, 'task_id' => $taskId];
} catch (\Throwable $e) {
Log::error('CreateCloudRecording failed: ' . $e->getMessage());
return ['ok' => false, 'message' => $e->getMessage()];
}
}
/**
* @return array{ok:bool,message?:string}
*/
public static function stopRecording(int $sdkAppId, string $taskId): array
{
if ($taskId === '') {
return ['ok' => true];
}
if (!self::sdkAvailable()) {
return ['ok' => false, 'message' => '未安装 tencentcloud/trtc'];
}
$secretId = trim((string)config('trtc.api_secret_id', ''));
$secretKey = trim((string)config('trtc.api_secret_key', ''));
if ($secretId === '' || $secretKey === '') {
return ['ok' => false, 'message' => '未配置云 API 密钥'];
}
$region = (string)config('trtc.recording_api_region', 'ap-guangzhou');
try {
$cred = new \TencentCloud\Common\Credential($secretId, $secretKey);
$httpProfile = new \TencentCloud\Common\Profile\HttpProfile();
$httpProfile->setEndpoint('trtc.tencentcloudapi.com');
$clientProfile = new \TencentCloud\Common\Profile\ClientProfile();
$clientProfile->setHttpProfile($httpProfile);
$client = new \TencentCloud\Trtc\V20190722\TrtcClient($cred, $region, $clientProfile);
$req = new \TencentCloud\Trtc\V20190722\Models\DeleteCloudRecordingRequest();
$req->SdkAppId = $sdkAppId;
$req->TaskId = $taskId;
$client->DeleteCloudRecording($req);
return ['ok' => true];
} catch (\Throwable $e) {
Log::warning('DeleteCloudRecording: ' . $e->getMessage());
return ['ok' => false, 'message' => $e->getMessage()];
}
}
public static function trtcSdkAppId(): int
{
$p = config('project.trtc');
return (int)(is_array($p) ? ($p['sdkAppId'] ?? 0) : 0) ?: (int)config('trtc.sdkAppId', 0);
}
public static function trtcUserSigSecretKey(): string
{
$p = config('project.trtc');
$fromProject = is_array($p) ? (string)($p['secretKey'] ?? '') : '';
return $fromProject !== '' ? $fromProject : (string)config('trtc.secretKey', '');
}
public static function makeBotUserSig(string $botUserId): string
{
$sdkAppId = self::trtcSdkAppId();
$key = self::trtcUserSigSecretKey();
$api = new TLSSigAPIv2($sdkAppId, $key);
$expire = (int)(config('project.trtc.expireTime') ?? config('trtc.expireTime', 86400));
return $api->genUserSig($botUserId, $expire > 0 ? $expire : 86400);
}
}