如何在HTML5使用WebRTC(内含可测试地址可用TRUN服务器)

简介: 如何在HTML5使用WebRTC(内含可测试地址可用TRUN服务器)
// 从地址栏获取参数
const url=location.href;
let name = getParamFromUrl(url, "name");
let role = getParamFromUrl(url, "role");
let remote = getParamFromUrl(url, "remote"); // answer none remote
var localOpened = false;

// 信令服务器
const signaling = new SignalingChannel("wss://www.zhaosonghan.com:9001", name, role, onmessage);
signaling.remote = remote;

// TURN 参数
const constraints = {
   audio: true, video: true};
const configuration = {
   iceServers: [{
   
                                      urls:'turn:43.138.235.180:9002',
                                      username: name,
                                      credential: 'mypwd'
                                    }]};

// 最重要的对象
const pc = new RTCPeerConnection(configuration);

// 没太大用
pc.getStats = (status) => {
   
  console.log("getStats ");
}

// 没太大用,状态改变会触发
pc.oniceconnectionstatechange = async (ev) => {
   
  console.log("oniceconnectionstatechange " + pc.iceConnectionState);

  // 如果是 answer 并且不是 local,打开自己本地的视频
  if (ROLE_ANSWER == role && !localOpened) {
   
    localOpened = true;
    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) => pc.addTrack(track, stream));

    // now, trigger onnegotiationneeded / onicecandidate
    document.getElementById('local').srcObject = stream;   
  }
}

// ICE 失败会有调用
pc.onicecandidateerror = (event) => {
   
  console.log("onicecandidateerror");
}

// 触发产生 candidate
// Send any ice candidates to the other peer.
pc.onicecandidate = ({
   candidate}) => {
   
  if (null == candidate)
    return;

  log("onicecandidate=" + JSON.stringify(candidate));

  signaling.sendToPeer(signaling.remote, {
   id:ID_WEBRTC_CANDI, candi:candidate});
}

// getUserMedia 调用后,会触发
// Let the "negotiationneeded" event trigger offer generation.
// offer trigger
pc.onnegotiationneeded = async () => {
   
  try {
   

    log("onnegotiationneeded");
    await pc.setLocalDescription(await pc.createOffer());

    // Send the offer to the other peer.
    signaling.sendToPeer(signaling.remote, {
   id:ID_WEBRTC_DESC, desc: pc.localDescription});
  } catch (err) {
   
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
   
  // Don't set srcObject again if it is already set.
  let remoteView = document.getElementById('remote');
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// 最开始的地方
// Call start() to initiate.
async function start() {
   
  try {
   
    // Get local stream, show it in 'local'
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
      stream.getTracks().forEach((track) => pc.addTrack(track, stream));

      // now, trigger onnegotiationneeded / onicecandidate
      document.getElementById('local').srcObject = stream;

  } catch (err) {
   
    log("start error=" + err);
  }
}

// 信令服务器交互
function onmessage(data) {
   
  //console.log("onmsg=" + data);

  let jsonRoot = eval('(' + data + ')');
  let cmd = parseInt(jsonRoot.head.cmd);
  //console.log("onmessage cmd=" + cmd);

  switch (cmd) {
   
    case CMD_REQ_SEND_PEER:
      handleCmdFromPeer(data);
      break;
    case CMD_RSP_SEND_PEER:
      handleSendPeerResp(data);
      break;
    case CMD_RSP_LOGIN:
      handleLogin(data);
      break;
    default:
      break;
  }
}

function handleLogin(data) {
   
  let jsonRoot = eval('(' + data + ')');

  log("login rst=" + jsonRoot.data.ret);
}

function handleSendPeerResp(data) {
   
  let jsonRoot = eval('(' + data + ')');
  log("handleSendPeerResp=" + jsonRoot.data.ret);
}

function handleCmdFromPeer(data) {
   
  let jsonRoot = eval('(' + data + ')');
  signaling.remote = jsonRoot.head.name;
  log("cmd from peer " + signaling.remote);

  let cmdid = parseInt(jsonRoot.data.msg.id);
  switch (cmdid) {
   
    case ID_WEBRTC_DESC:
      setRemoteDesc(jsonRoot.data.msg.desc);
      break;
    case ID_WEBRTC_CANDI:
      setCandidate(jsonRoot.data.msg.candi);
      break;
    default:
      break;
  }
}

// 添加 candidate
async function setCandidate(candi) {
   
  log("setCandidate " + JSON.stringify(candi));
  await pc.addIceCandidate(candi);
}

// 设置远端desc
async function setRemoteDesc(json) {
   
    if ('offer' == json.type) {
   

      await pc.setRemoteDescription(json);
      const stream = await navigator.mediaDevices.getUserMedia(constraints);
      stream.getTracks().forEach((track) => pc.addTrack(track, stream));
      await pc.setLocalDescription(await pc.createAnswer());
      log("offer setremotedesc local desc=" + pc.localDescription);

      signaling.sendToPeer(signaling.remote, {
   id:ID_WEBRTC_DESC, desc: pc.localDescription});  
    } else if ('answer' == json.type) {
   
      await pc.setRemoteDescription(json);
      log("answer setremotedesc local desc=" + pc.localDescription);

    } else {
   
      log('Unsupported SDP type.');
    }

}


function getParamFromUrl(url, param)
{
   
  let vars = url.split("&");
  for (let i = 0; i < vars.length; i++)
  {
   
    let pair = vars[i].split("=");
    if (param == pair[0])
      return pair[1];
  }

  return "";
}

以上是 html5 使用 webrtc 的核心代码,其实代码并不复杂,可以运行示例例观察调用流程;但是自己需要实现一个信令服务器。
如果没有信令服务器,可以使用如下链接直接看效果

pc端

offer https://www.zhaosonghan.com/h5/webrtc_pc.html?&name=123456&remote=abcdef&role=1
answer https://www.zhaosonghan.com/h5/webrtc_pc.html?&name=abcdef&role=2
移动端

offer https://www.zhaosonghan.com/h5/webrtc_mobile.html?&name=123456&remote=abcdef&role=1
answer https://www.zhaosonghan.com/h5/webrtc_mobile.html?&name=abcdef&role=2

以上示例来自 https://www.zhaosonghan.com/archives/1704808721108,感谢作者~

相关文章
|
2月前
|
网络协议 安全 测试技术
手撕测试tcp服务器效率工具——以epoll和io_uring对比为例
手撕测试tcp服务器效率工具——以epoll和io_uring对比为例
44 2
|
2月前
|
存储 弹性计算 运维
阿里云服务器ECS经济型e实例详细介绍_性能测试和租用价格
阿里云服务器ECS经济型e实例详细介绍_性能测试和租用价格,阿里云服务器ECS推出经济型e系列,经济型e实例是阿里云面向个人开发者、学生、小微企业,在中小型网站建设、开发测试、轻量级应用等场景推出的全新入门级云服务器,CPU采用Intel Xeon Platinum架构处理器,支持1:1、1:2、1:4多种处理器内存配比,e系列性价比优选
|
8天前
|
网络协议 安全 Linux
IDEA通过内网穿透实现固定公网地址远程SSH连接本地Linux服务器
IDEA通过内网穿透实现固定公网地址远程SSH连接本地Linux服务器
|
1月前
|
弹性计算 分布式计算 DataWorks
DataWorks报错问题之ecs自建数据库连通性测试报错如何解决
DataWorks是阿里云提供的一站式大数据开发与管理平台,支持数据集成、数据开发、数据治理等功能;在本汇总中,我们梳理了DataWorks产品在使用过程中经常遇到的问题及解答,以助用户在数据处理和分析工作中提高效率,降低难度。
|
1月前
|
弹性计算 缓存 测试技术
阿里云2核4g服务器(费用价格/性能测试/支持人数)
阿里云2核4g服务器能支持多少人访问?2核4G服务器并发数性能测试,阿小云账号下的2核4G服务器支持20人同时在线访问,然而应用不同、类型不同、程序效率不同实际并发数也不同,2核4G服务器的在线访问人数取决于多个变量因素
|
1月前
|
弹性计算 缓存 测试技术
2核4g服务器能支持多少人访问?阿里云2核4G服务器并发数测试
2核4g服务器能支持多少人访问?阿里云2核4G服务器并发数测试,2核4G服务器并发数性能测试,阿小云账号下的2核4G服务器支持20人同时在线访问,然而应用不同、类型不同、程序效率不同实际并发数也不同,2核4G服务器的在线访问人数取决于多个变量因素
|
2月前
|
弹性计算 监控 网络安全
ECS实例问题之公网IP地址无法访问如何解决
ECS实例指的是在阿里云ECS服务中创建的虚拟计算环境,用户可在此环境中运行应用程序和服务;本合集将介绍ECS实例的创建、管理、监控和维护流程,及常见问题处理方法,助力用户保障实例的稳定运行。
|
2月前
|
存储 负载均衡 监控
epoll服务器百万并发测试
epoll服务器百万并发测试
31 1
|
2月前
|
弹性计算 数据中心
阿里云香港服务器详细介绍_BGP多线精品测试_CN2高速网络
阿里云香港服务器中国香港数据中心网络线路类型BGP多线精品,中国电信CN2高速网络高质量、大规格BGP带宽,运营商精品公网直连中国内地,时延更低,优化海外回中国内地流量的公网线路,可以提高国际业务访问质量。阿里云百科来详细介绍阿里云香港云服务器
|
22天前
|
弹性计算
阿里云ECS使用体验
在申请高校学生免费体验阿里云ECS云服务器后的一些使用体验和感受。

热门文章

最新文章