下面是一个使用ThinkPHP 5实现后端逻辑的示例。我们将创建一个简单的ThinkPHP 5项目来处理生成推流和播流地址的请求。
后端部分(ThinkPHP 5)
1. 初始化ThinkPHP 5项目
首先,确保你已经安装了Composer。然后使用Composer创建一个新的ThinkPHP 5项目。
composer create-project topthink/think tp5-rtc-demo
cd tp5-rtc-demo
2. 安装依赖
ThinkPHP 5自带了一些必要的依赖,我们还需要安装guzzlehttp/guzzle
来处理HTTP请求。
composer require guzzlehttp/guzzle
3. 创建控制器
在application/index/controller
目录下创建一个新的控制器文件Rtc.php
。
<?php
namespace app\index\controller;
use think\Controller;
use GuzzleHttp\Client;
class Rtc extends Controller
{
// 阿里云RTC的AppID和AppKey
private $appId = 'your_app_id';
private $appKey = 'your_app_key';
// 生成Token的函数
private function generateToken($userId, $channelName)
{
$timestamp = time() + 3600; // 1小时有效期
$nonce = bin2hex(random_bytes(15));
$signature = hash_hmac('sha1', $this->appId . $channelName . $userId . $timestamp . $nonce, $this->appKey);
return '0001' . $this->appId . $channelName . $userId . $timestamp . $nonce . $signature;
}
// 处理获取推流和播流地址的请求
public function getRtcToken()
{
$userId = input('post.userId');
$otherUserId = input('post.otherUserId');
$channelName = 'room1'; // 可以根据需要动态生成房间名
$token = $this->generateToken($userId, $channelName);
$pushUrl = "wss://your-rtc-push-url/{$channelName}?token={$token}";
$playUrl = "wss://your-rtc-play-url/{$channelName}?token={$token}";
return json(['pushUrl' => $pushUrl, 'playUrl' => $playUrl]);
}
}
4. 配置路由
在route/route.php
中添加路由规则。
use think\Route;
Route::post('get-rtc-token', 'index/Rtc/getRtcToken');
5. 启动ThinkPHP 5服务器
在项目根目录下启动ThinkPHP 5内置服务器。
php think run
默认情况下,服务器会在http://localhost:8000
上运行。
前端部分
前端部分与之前的示例保持一致,只需将后端URL改为ThinkPHP 5的地址。
1. 编写前端代码
在pages/index/index.vue
中编写以下代码:
<template>
<view>
<!-- 本地视频预览 -->
<live-pusher :url="pushUrl" mode="RTC" autopush @statechange="onPushStateChange"></live-pusher>
<!-- 远程视频播放 -->
<live-player :src="playUrl" mode="RTC" autoplay @statechange="onPlayStateChange"></live-player>
</view>
</template>
<script>
export default {
data() {
return {
pushUrl: '',
playUrl: '',
};
},
methods: {
onPushStateChange(e) {
console.log('推流状态变化', e);
},
onPlayStateChange(e) {
console.log('播放状态变化', e);
},
// 获取推流和播流地址的逻辑
async getRTCToken() {
const response = await uni.request({
url: 'http://localhost:8000/get-rtc-token',
method: 'POST',
data: {
userId: 'user1',
otherUserId: 'user2',
},
});
this.pushUrl = response.data.pushUrl;
this.playUrl = response.data.playUrl;
},
},
onLoad() {
this.getRTCToken();
},
};
</script>
<style>
/* 添加一些样式 */
live-pusher, live-player {
width: 100%;
height: 300px;
}
</style>
运行项目
- 启动后端服务器
php think run
- 启动UniApp项目
在HBuilderX中打开你的UniApp项目,然后点击运行按钮,选择合适的模拟器或真机进行测试。
注意事项
-
阿里云RTC的URL格式:
- 上述示例中的
pushUrl
和playUrl
是示例格式,你需要根据阿里云RTC的实际文档来调整URL格式。 - 确保你已经正确配置了阿里云RTC的推流和播流地址。
- 上述示例中的
-
安全性:
- 在生产环境中,确保你的后端服务和Token生成逻辑是安全的,防止未授权访问。
-
网络环境:
- 测试时,请确保网络环境稳定,以获得更好的音视频通话体验。
通过以上步骤,你应该能够实现一个基本的UniApp音视频通话功能,并使用ThinkPHP 5作为后端来处理音视频流。如果有任何问题或需要进一步的帮助,请随时提问。
同样我们可以更完善一下前端的代码例如增加上开始通话和结束通话的功能
<template>
<view class="container">
<view class="video-container">
<!-- 本地视频预览 -->
<live-pusher
ref="livePusher"
:url="pushUrl"
mode="RTC"
autopush
@statechange="onPushStateChange"
class="live-pusher"
></live-pusher>
<!-- 远程视频播放 -->
<live-player
ref="livePlayer"
:src="playUrl"
mode="RTC"
autoplay
@statechange="onPlayStateChange"
class="live-player"
></live-player>
</view>
<view class="controls">
<button @click="startCall" :disabled="isCalling" class="control-button">开始通话</button>
<button @click="endCall" :disabled="!isCalling" class="control-button">结束通话</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
pushUrl: '',
playUrl: '',
isCalling: false,
};
},
methods: {
onPushStateChange(e) {
console.log('推流状态变化', e);
},
onPlayStateChange(e) {
console.log('播放状态变化', e);
},
// 获取推流和播流地址的逻辑
async getRTCToken() {
const response = await uni.request({
url: 'http://localhost:8000/get-rtc-token',
method: 'POST',
data: {
userId: 'user1',
otherUserId: 'user2',
},
});
this.pushUrl = response.data.pushUrl;
this.playUrl = response.data.playUrl;
},
startCall() {
this.$refs.livePusher.start();
this.$refs.livePlayer.play();
this.isCalling = true;
},
endCall() {
this.$refs.livePusher.stop();
this.$refs.livePlayer.stop();
this.isCalling = false;
},
},
onLoad() {
this.getRTCToken();
},
};
</script>
<style>
/* 添加一些样式 */
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f0f0f0;
}
.video-container {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 100%;
max-width: 800px;
margin-bottom: 20px;
}
.live-pusher, .live-player {
width: 45%;
height: 300px;
border: 1px solid #ccc;
border-radius: 10px;
overflow: hidden;
}
.controls {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 100%;
max-width: 400px;
}
.control-button {
padding: 10px 20px;
font-size: 16px;
color: #fff;
background-color: #007aff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.control-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
</style>
总而言之是需要大家去一步步的实践的。如果有更好的实现方式请分享反馈给我们