

模块 | 技术建议 |
|---|---|
流媒体服务器 | SRS、ZLMediaKit、nginx-rtmp(测试用) |
推流协议 | RTMP(主播)、WebRTC(低延迟)、SRT(远程赛事) |
播放协议 | HLS(兼容)、HTTP-FLV(低延迟)、WebRTC(实时) |
后端 | PHP(Laravel/Hyperf)、Node.js(可选)、Java(可选) |
实时通信 | Swoole WebSocket、Socket.IO、IM SDK(腾讯云/环信) |
数据库 | MySQL(核心业务)、Redis(在线状态/缓存/计数) |
对象存储 | OSS/S3/MinIO(回放、录制) |
CDN | 阿里/腾讯/Cloudflare 分发 HLS/FLV |
异步任务 | RabbitMQ/Kafka(转码、统计、消息队列) |
监控 | Prometheus + Grafana |
日志 | ELK / Loki |
Clients
├─ 主播/裁判推流 (OBS/APP/SRT) --> RTMP/SRT --> 流媒体集群 (SRS/ZL)
├─ 观众 Web / Mobile --> HLS/HTTP-FLV/WebRTC --> CDN
└─ Chat / 弹幕客户端 --> WebSocket / IM 服务
Backend Services
├─ API 服务 (PHP/Node) --> MySQL + Redis
├─ 流媒体回调处理 (on_publish/on_close)
├─ 异步任务 (转码/录制/统计)
├─ 礼物/打赏服务
├─ 赛事管理/排期/房间管理
└─ 监控/运维/报警
Storage & Infra
├─ MySQL/Redis
├─ OSS/S3/MinIO (录制回放)
├─ CDN 分发
├─ Prometheus/Grafana 监控
└─ 日志 ELK / LokiCREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(64),
password_hash VARCHAR(255),
role TINYINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE events (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
start_time DATETIME,
end_time DATETIME,
status TINYINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE rooms (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
event_id BIGINT,
owner_id BIGINT,
stream_key VARCHAR(128),
is_live TINYINT DEFAULT 0,
viewers_count INT DEFAULT 0,
hls_url VARCHAR(512),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE streams (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
room_id BIGINT,
start_at DATETIME,
stop_at DATETIME,
record_url VARCHAR(512)
);
CREATE TABLE messages (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
room_id BIGINT,
user_id BIGINT,
type VARCHAR(32),
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);阶段 | 核心目标 |
|---|---|
MVP(1-2 月) | 房间管理、推流鉴权、HLS/FLV 播放、基础弹幕 |
V1(2-3 月) | 录制/回放、赛事管理、礼物/打赏、WebSocket 弹幕 |
V2(2 月) | 多机房部署、CDN 集成、低延迟 WebRTC、统计分析 |
V3(2 月) | 风控、版权保护、私有化部署、监控告警、可扩展架构 |
┌─────────────┐
│ 主播/裁判端 │
│ OBS / APP │
└─────┬───────┘
│ RTMP/SRT/WebRTC
▼
┌───────────────┐
│ 流媒体服务器 │
│ SRS/ZLMediaKit│
└─────┬─────────┘
│ HLS/FLV/WebRTC
▼
CDN分发
│
┌────────────┴─────────────┐
│ 观众端 │
│ Web/APP/TV │
│ 播放 HLS/FLV/WebRTC │
│ 弹幕 WebSocket/IM │
└────────────┬─────────────┘
│
▼
┌───────────────┐
│ 业务后端 API │
│ PHP Laravel │
│ MySQL/Redis │
│ WebSocket/Swoole
└─────┬─────────┘
│
┌───────────┴────────────┐
│ 异步任务/转码/录制 Worker│
│ RabbitMQ/Kafka + FFmpeg │
└───────────┬────────────┘
│
┌───────┴────────┐
│ 对象存储/OSS/S3 │
│ 录制回放文件 │
└────────────────┘推流流程
stream_key → OBS / APP 推 RTMP/SRT
on_publish 回调 → PHP API 验证 stream_key
rooms.is_live=1,触发 WebSocket 通知观众
play_token → 拉 HLS/FLV/WebRTC 流
断流/回放流程
on_close 回调
streams.stop_at
弹幕/互动
token
// app/Models/User.php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable {
protected $fillable = ['username','password','role'];
}
// app/Models/Event.php
class Event extends Model {
protected $fillable = ['name','start_time','end_time','status'];
}
// app/Models/Room.php
class Room extends Model {
protected $fillable = ['event_id','owner_id','stream_key','is_live','viewers_count','hls_url'];
}
// app/Models/Stream.php
class Stream extends Model {
protected $fillable = ['room_id','start_at','stop_at','record_url'];
}// app/Http/Controllers/StreamHookController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Room;
use App\Models\Stream;
class StreamHookController extends Controller {
// 推流开始
public function onPublish(Request $request){
$streamKey = $request->input('name');
$room = Room::where('stream_key', $streamKey)->first();
if(!$room) return response('Unauthorized', 401);
$room->is_live = 1;
$room->save();
// 新增 stream 记录
Stream::create([
'room_id' => $room->id,
'start_at' => now()
]);
return response('OK', 200);
}
// 推流结束
public function onClose(Request $request){
$streamKey = $request->input('name');
$room = Room::where('stream_key', $streamKey)->first();
if(!$room) return response('Unauthorized', 401);
$room->is_live = 0;
$room->save();
$stream = Stream::where('room_id',$room->id)->latest()->first();
$stream->stop_at = now();
$stream->save();
// 触发异步任务: 转码/上传 OSS
dispatch(new \App\Jobs\ProcessStream($stream));
return response('OK', 200);
}
}// app/Http/Controllers/PlayTokenController.php
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cache;
class PlayTokenController extends Controller {
public function getToken(Request $request, $roomId){
$room = Room::findOrFail($roomId);
$token = hash_hmac('sha256', $room->stream_key.'|'.time(), env('APP_KEY'));
// 缓存 token 5分钟
Cache::put('play_token_'.$token, $room->id, 300);
return response()->json(['token'=>$token, 'hls_url'=>$room->hls_url]);
}
}// routes/api.php
use App\Http\Controllers\StreamHookController;
use App\Http\Controllers\PlayTokenController;
Route::post('/hook/on_publish', [StreamHookController::class,'onPublish']);
Route::post('/hook/on_close', [StreamHookController::class,'onClose']);
Route::get('/rooms/{id}/play-token', [PlayTokenController::class,'getToken']);// app/Jobs/ProcessStream.php
namespace App\Jobs;
use App\Models\Stream;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
class ProcessStream implements ShouldQueue {
use Queueable;
protected $stream;
public function __construct(Stream $stream){ $this->stream = $stream; }
public function handle(){
$file = "/recordings/{$this->stream->id}.ts";
$output = "/recordings/{$this->stream->id}.mp4";
exec("ffmpeg -i $file -c:v copy -c:a copy $output");
// 上传 OSS/S3 (示例)
// Storage::disk('oss')->putFileAs('streams',$output,"{$this->stream->id}.mp4");
$this->stream->record_url = "/oss/streams/{$this->stream->id}.mp4";
$this->stream->save();
}
}✅ 这样一套架构 + 数据流 + 核心 PHP 代码骨架,已经可以直接作为赛事直播系统开发模板,包括推流/断流、play token、防盗链、录制回放、异步转码。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。