使用到的一些技术与云服务功能:
调试工具:
点播/直播 协议介绍
HLS(M3U8) | 可用于直播 | http://xxx.liveplay.myqcloud.com/xxx.m3u8 |
支持 | 支持 |
---|---|---|---|---|
视频协议 | 用途 | URL 地址格式 | PC 浏览器 | 移动浏览器 |
HLS(M3U8) | 可用于点播 | http://xxx.vod.myqcloud.com/xxx.m3u8 |
支持 | 支持 |
FLV | 可用于直播 | http://xxx.liveplay.myqcloud.com/xxx.flv |
支持 | 不支持 |
FLV | 可用于点播 | http://xxx.vod.myqcloud.com/xxx.flv |
支持 | 不支持 |
RTMP | 只适用直播 | rtmp://xxx.liveplay.myqcloud.com/live/xxx |
支持 | 不支持 |
MP4 | 只适用点播 | http://xxx.vod.myqcloud.com/xxx.mp4 |
支持 | 支持 |
-
移动设备直播,建议使用RTMP 协议,性能较好,网络状态正常下,直播延迟大概 2 ~ 5 秒,移动设备可以正常使用
-
HLS 协议兼容性好,可以被使用与网页直播,但性能缺佳,测试有延迟5秒以上。
腾讯云小直播域名配置
需要配置:
- 推流域名
- 拉流域名
配置CNAME解析腾讯云给出的链接即可。
生成推流地址
推流地址通常是给与主播端使用,将视频流数据推向服务端。
使用到了腾讯云小直播服务,根据官方给的例子使用即可。
推流地址生成公式:
rtmp://domain/live/StreamName?txSecret=Md5(key+StreamName+hex(time))&txTime=hex(time)
需要四个参数生成:
- 云直播key,腾讯云给的
- streamName,区别不同推流地址的唯一流名称,必须唯一,后端处理这个比较方便(user_id+now().timestamp)貌似就可以生成。
- 推流域名,比如:69045.livepush.myqcloud.com
- 结束时间,比如最长直播持续一天,now().addDay().toDateTimeString();
PHP例子:
/**
* 获取推流地址
* 如果不传key和过期时间,将返回不含防盗链的url
* @param domain 您用来推流的域名
* streamName 您用来区别不同推流地址的唯一流名称
* key 安全密钥
* time 过期时间 sample 2016-11-12 12:00:00
* @return String url
*/
function getPushUrl($domain, $streamName, $key = null, $time = null){
if($key && $time){
$txTime = strtoupper(base_convert(strtotime($time),10,16));
//txSecret = MD5( KEY + streamName + txTime )
$txSecret = md5($key.$streamName.$txTime);
$ext_str = "?".http_build_query(array(
"txSecret"=> $txSecret,
"txTime"=> $txTime
));
}
return "rtmp://".$domain."/live/".$streamName . (isset($ext_str) ? $ext_str : "");
}
echo getPushUrl("123.test.com","123456","69e0daf7234b01f257a7adb9f807ae9f","2016-09-11 20:08:07");
Java 例子:
package com.test;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Test {
public static void main(String[] args) {
System.out.println(getSafeUrl("txrtmp", "11212122", 1469762325L));
}
private static final char[] DIGITS_LOWER =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/*
* KEY+ streamName + txTime
*/
private static String getSafeUrl(String key, String streamName, long txTime) {
String input = new StringBuilder().
append(key).
append(streamName).
append(Long.toHexString(txTime).toUpperCase()).toString();
String txSecret = null;
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
txSecret = byteArrayToHexString(
messageDigest.digest(input.getBytes("UTF-8")));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return txSecret == null ? "" :
new StringBuilder().
append("txSecret=").
append(txSecret).
append("&").
append("txTime=").
append(Long.toHexString(txTime).toUpperCase()).
toString();
}
private static String byteArrayToHexString(byte[] data) {
char[] out = new char[data.length << 1];
for (int i = 0, j = 0; i < data.length; i++) {
out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
out[j++] = DIGITS_LOWER[0x0F & data[i]];
}
return new String(out);
}
}
使用OBS调试推流功能
-
服务器填写腾讯上的推流地址。
-
串流密钥填写上面例子生成的地址中的
live/
后的字符串即可。
串流密钥例子:
test?txSecret=592172b126b77b71dbda74b1edf9b5de&txTime=5E65167F
测试推流是否成功
打开VLC,使用快捷键 Command+n
,输入推流域名+流名称即可。
例子:
https://xxx.com/live/test
如果成功,可以双击地址直接打开,可以看到你的推流画面
弹幕功能
服务端将弹幕相关数据,广播到当前直播间,前端使用 基于Laravel-echo
包去监听数据,再讲数据渲染到当前直播间即可。
PHP代码例子:
public function commentLiveRoomResolver($root, array $args, $context, $info)
{
$user = getUser();
$live_room_id = Arr::get($args, 'live_room_id', null);
$message = Arr::get($args, 'message', null);
event(new NewLiveRoomMessage($user->id, $live_room_id, $message));
return $message;
}
NewLiveRoomMessage代码:
<?php
namespace App\Events\LiveRoom;
use App\LiveRoom;
use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class NewLiveRoomMessage
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $message;
public $liveRoom;
/**
* Create a new event instance.
*
* @param $userId 观众id
* @param $liveRoomId 直播室id
* @param $message 弹幕内容
*/
public function __construct($userId,$liveRoomId,$message)
{
$this->user = User::find($userId);
$this->liveRoom = LiveRoom::find($liveRoomId);
$this->message = $message;
}
public function broadcastWith():array
{
return [
'user_id' => $this->user->id,
'user_name' => $this->user->name,
'user_avatar' => $this->user->avatar_url,
'live_room_id' => $this->liveRoom->id,
'message' => $this->message,
];
}
public function broadcastOn(): PresenceChannel
{
return new PresenceChannel('live_room.'.$this->liveRoom->id);
}
}
如果需要记录直播间弹幕数据到数据库中,再去添加NewLiveRoomMessage
的监听器中相关代码即可。