中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

招聘網(wǎng)站可以同時做兩份簡歷嗎seo職業(yè)技能培訓(xùn)班

招聘網(wǎng)站可以同時做兩份簡歷嗎,seo職業(yè)技能培訓(xùn)班,公司做網(wǎng)站推廣需要多少錢,網(wǎng)站建設(shè)推廣技術(shù)1.什么是webrtc? WebRTC 是 Web 實時通信(Real-Time Communication)的縮寫,它既是 API 也是協(xié)議。WebRTC 協(xié)議是兩個 WebRTC Agent 協(xié)商雙向安全實時通信的一組規(guī)則。開發(fā)人員可以通過 WebRTC API 使用 WebRTC 協(xié)議。目前 WebRTC…

1.什么是webrtc?

WebRTC 是 Web 實時通信(Real-Time Communication)的縮寫,它既是 API 也是協(xié)議。WebRTC 協(xié)議是兩個 WebRTC Agent 協(xié)商雙向安全實時通信的一組規(guī)則。開發(fā)人員可以通過 WebRTC API 使用 WebRTC 協(xié)議。目前 WebRTC API 僅有 JavaScript 版本。 可以用 HTTP 和 Fetch API 之間的關(guān)系作為類比。WebRTC 協(xié)議就是 HTTP,而 WebRTC API 就是 Fetch API。 除了 JavaScript 語言,WebRTC 協(xié)議也可以在其他 API 和語言中使用。你還可以找到 WebRTC 的服務(wù)器和特定領(lǐng)域的工具。所有這些實現(xiàn)都使用 WebRTC 協(xié)議,以便它們可以彼此交互。 WebRTC 協(xié)議由 IETF 工作組在rtcweb中維護(hù)。WebRTC API 的 W3C 文檔在webrtc。

WebSocket

WebSocket是一種在單個TCP連接上進(jìn)行全雙工通信的協(xié)議。WebSocket通信協(xié)議于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455,并由RFC7936補充規(guī)范。WebSocket API也被W3C定為標(biāo)準(zhǔn)。WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸

webrtc架構(gòu)

architecture

2.代碼工程

實驗?zāi)繕?biāo)

實現(xiàn)視頻通話功能

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>WebRTC</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies>
</project>

controller

package com.et.webrtc.controller;import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;import java.util.HashMap;
import java.util.Map;@RestController
public class HelloWorldController {@RequestMapping("/hello")public Map<String, Object> showHelloWorld(){Map<String, Object> map = new HashMap<>();map.put("msg", "HelloWorld");return map;}/*** WebRTC + WebSocket*/@RequestMapping("webrtc/{username}.html")public ModelAndView socketChartPage(@PathVariable String username) {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("webrtc.html");modelAndView.addObject("username",username);return modelAndView;}
}

config

package com.et.webrtc.config;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** WebRTC + WebSocket*/
@Slf4j
@Component
@ServerEndpoint(value = "/webrtc/{username}")
public class WebRtcWSServer {/*** 連接集合*/private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();/*** 連接建立成功調(diào)用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("username") String username, @PathParam("publicKey") String publicKey) {sessionMap.put(username, session);}/*** 連接關(guān)閉調(diào)用的方法*/@OnClosepublic void onClose(Session session) {for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {if (entry.getValue() == session) {sessionMap.remove(entry.getKey());break;}}}/*** 發(fā)生錯誤時調(diào)用*/@OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();}/*** 服務(wù)器接收到客戶端消息時調(diào)用的方法*/@OnMessagepublic void onMessage(String message, Session session) {try{//jacksonObjectMapper mapper = new ObjectMapper();mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);//JSON字符串轉(zhuǎn) HashMapHashMap hashMap = mapper.readValue(message, HashMap.class);//消息類型String type = (String) hashMap.get("type");//to userString toUser = (String) hashMap.get("toUser");Session toUserSession = sessionMap.get(toUser);String fromUser = (String) hashMap.get("fromUser");//msgString msg = (String) hashMap.get("msg");//sdpString sdp = (String) hashMap.get("sdp");//iceMap iceCandidate  = (Map) hashMap.get("iceCandidate");HashMap<String, Object> map = new HashMap<>();map.put("type",type);//呼叫的用戶不在線if(toUserSession == null){toUserSession = session;map.put("type","call_back");map.put("fromUser","系統(tǒng)消息");map.put("msg","Sorry,呼叫的用戶不在線!");send(toUserSession,mapper.writeValueAsString(map));return;}//對方掛斷if ("hangup".equals(type)) {map.put("fromUser",fromUser);map.put("msg","對方掛斷!");}//視頻通話請求if ("call_start".equals(type)) {map.put("fromUser",fromUser);map.put("msg","1");}//視頻通話請求回應(yīng)if ("call_back".equals(type)) {map.put("fromUser",toUser);map.put("msg",msg);}//offerif ("offer".equals(type)) {map.put("fromUser",toUser);map.put("sdp",sdp);}//answerif ("answer".equals(type)) {map.put("fromUser",toUser);map.put("sdp",sdp);}//iceif ("_ice".equals(type)) {map.put("fromUser",toUser);map.put("iceCandidate",iceCandidate);}send(toUserSession,mapper.writeValueAsString(map));}catch(Exception e){e.printStackTrace();}}/*** 封裝一個send方法,發(fā)送消息到前端*/private void send(Session session, String message) {try {System.out.println(message);session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}
}
package com.et.webrtc.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
@EnableWebSocket
public class WebSocketConfiguration {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

前端頁面

<!DOCTYPE>
<!--解決idea thymeleaf 表達(dá)式模板報紅波浪線-->
<!--suppress ALL -->
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>WebRTC + WebSocket</title><meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"><style>html,body{margin: 0;padding: 0;}#main{position: absolute;width: 370px;height: 550px;}#localVideo{position: absolute;background: #757474;top: 10px;right: 10px;width: 100px;height: 150px;z-index: 2;}#remoteVideo{position: absolute;top: 0px;left: 0px;width: 100%;height: 100%;background: #222;}#buttons{z-index: 3;bottom: 20px;left: 90px;position: absolute;}#toUser{border: 1px solid #ccc;padding: 7px 0px;border-radius: 5px;padding-left: 5px;margin-bottom: 5px;}#toUser:focus{border-color: #66afe9;outline: 0;-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}#call{width: 70px;height: 35px;background-color: #00BB00;border: none;margin-right: 25px;color: white;border-radius: 5px;}#hangup{width:70px;height:35px;background-color:#FF5151;border:none;color:white;border-radius: 5px;}</style>
</head>
<body>
<div id="main"><video id="remoteVideo" playsinline autoplay></video><video id="localVideo" playsinline autoplay muted></video><div id="buttons"><input id="toUser" placeholder="輸入在線好友賬號"/><br/><button id="call">視頻通話</button><button id="hangup">掛斷</button></div>
</div>
</body>
<!-- 可引可不引 -->
<!--<script th:src="@{/js/adapter-2021.js}"></script>-->
<script type="text/javascript" th:inline="javascript">let username = /*[[${username}]]*/'';let localVideo = document.getElementById('localVideo');let remoteVideo = document.getElementById('remoteVideo');let websocket = null;let peer = null;WebSocketInit();ButtonFunInit();/* WebSocket */function WebSocketInit(){//判斷當(dāng)前瀏覽器是否支持WebSocketif ('WebSocket' in window) {websocket = new WebSocket("wss://192.168.0.104/webrtc/"+username);} else {alert("當(dāng)前瀏覽器不支持WebSocket!");}//連接發(fā)生錯誤的回調(diào)方法websocket.onerror = function (e) {alert("WebSocket連接發(fā)生錯誤!");};//連接關(guān)閉的回調(diào)方法websocket.onclose = function () {console.error("WebSocket連接關(guān)閉");};//連接成功建立的回調(diào)方法websocket.onopen = function () {console.log("WebSocket連接成功");};//接收到消息的回調(diào)方法websocket.onmessage = async function (event) {let { type, fromUser, msg, sdp, iceCandidate } = JSON.parse(event.data.replace(/\n/g,"\\n").replace(/\r/g,"\\r"));console.log(type);if (type === 'hangup') {console.log(msg);document.getElementById('hangup').click();return;}if (type === 'call_start') {let msg = "0"if(confirm(fromUser + "發(fā)起視頻通話,確定接聽嗎")==true){document.getElementById('toUser').value = fromUser;WebRTCInit();msg = "1"}websocket.send(JSON.stringify({type:"call_back",toUser:fromUser,fromUser:username,msg:msg}));return;}if (type === 'call_back') {if(msg === "1"){console.log(document.getElementById('toUser').value + "同意視頻通話");//創(chuàng)建本地視頻并發(fā)送offerlet stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })localVideo.srcObject = stream;stream.getTracks().forEach(track => {peer.addTrack(track, stream);});let offer = await peer.createOffer();await peer.setLocalDescription(offer);let newOffer = offer.toJSON();newOffer["fromUser"] = username;newOffer["toUser"] = document.getElementById('toUser').value;websocket.send(JSON.stringify(newOffer));}else if(msg === "0"){alert(document.getElementById('toUser').value + "拒絕視頻通話");document.getElementById('hangup').click();}else{alert(msg);document.getElementById('hangup').click();}return;}if (type === 'offer') {let stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });localVideo.srcObject = stream;stream.getTracks().forEach(track => {peer.addTrack(track, stream);});await peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));let answer = await peer.createAnswer();let newAnswer = answer.toJSON();newAnswer["fromUser"] = username;newAnswer["toUser"] = document.getElementById('toUser').value;websocket.send(JSON.stringify(newAnswer));await peer.setLocalDescription(answer);return;}if (type === 'answer') {peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));return;}if (type === '_ice') {peer.addIceCandidate(iceCandidate);return;}}}/* WebRTC */function WebRTCInit(){peer = new RTCPeerConnection();//icepeer.onicecandidate = function (e) {if (e.candidate) {websocket.send(JSON.stringify({type: '_ice',toUser:document.getElementById('toUser').value,fromUser:username,iceCandidate: e.candidate}));}};//trackpeer.ontrack = function (e) {if (e && e.streams) {remoteVideo.srcObject = e.streams[0];}};}/* 按鈕事件 */function ButtonFunInit(){//視頻通話document.getElementById('call').onclick = function (e){document.getElementById('toUser').style.visibility = 'hidden';let toUser = document.getElementById('toUser').value;if(!toUser){alert("請先指定好友賬號,再發(fā)起視頻通話!");return;}if(peer == null){WebRTCInit();}websocket.send(JSON.stringify({type:"call_start",fromUser:username,toUser:toUser,}));}//掛斷document.getElementById('hangup').onclick = function (e){document.getElementById('toUser').style.visibility = 'unset';if(localVideo.srcObject){const videoTracks = localVideo.srcObject.getVideoTracks();videoTracks.forEach(videoTrack => {videoTrack.stop();localVideo.srcObject.removeTrack(videoTrack);});}if(remoteVideo.srcObject){const videoTracks = remoteVideo.srcObject.getVideoTracks();videoTracks.forEach(videoTrack => {videoTrack.stop();remoteVideo.srcObject.removeTrack(videoTrack);});//掛斷同時,通知對方websocket.send(JSON.stringify({type:"hangup",fromUser:username,toUser:document.getElementById('toUser').value,}));}if(peer){peer.ontrack = null;peer.onremovetrack = null;peer.onremovestream = null;peer.onicecandidate = null;peer.oniceconnectionstatechange = null;peer.onsignalingstatechange = null;peer.onicegatheringstatechange = null;peer.onnegotiationneeded = null;peer.close();peer = null;}localVideo.srcObject = null;remoteVideo.srcObject = null;}}
</script>
</html>

DemoAppliciation.java

package com.et.webrtc;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}

以上只是一些關(guān)鍵代碼,所有代碼請參見下面代碼倉庫

代碼倉庫

  • GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.

3.測試

啟動Spring Boot應(yīng)用

測試視頻通話

前置條件:必須是https協(xié)議,不然無法打開視頻和語音權(quán)限

  • 筆記本:https://192.168.0.104/webrtc/2.html
  • 手機:https://192.168.0.104/webrtc/1.html

輸入對方id,進(jìn)行視屏通話

4.引用

  • 是什么,為什么,如何使用 | 給好奇者的WebRTC
  • https://www.cnblogs.com/huanzi-qch/p/15716286.html
  • Spring Boot集成websocket實現(xiàn)webrtc功能 | Harries Blog?
http://www.risenshineclean.com/news/42888.html

相關(guān)文章:

  • 叫別人建個網(wǎng)站多少錢廣州 競價托管
  • 建設(shè)公司網(wǎng)站有什么好處關(guān)鍵詞優(yōu)化外包服務(wù)
  • 公司自有網(wǎng)站工信備案原版百度
  • 模板網(wǎng)站robots怎么做如何建網(wǎng)站要什么條件
  • 商務(wù)部網(wǎng)站市場體系建設(shè)司子站微信如何引流推廣精準(zhǔn)加人
  • 深圳網(wǎng)站建設(shè)策劃企業(yè)宣傳方式
  • 可視方便建站微網(wǎng)站哪個好怎么用論壇seo網(wǎng)站
  • asp.net網(wǎng)站開發(fā)教程 pdf網(wǎng)站關(guān)鍵詞排名外包
  • 做logo找靈感的網(wǎng)站微信朋友圈營銷文案
  • 企業(yè)云網(wǎng)站建設(shè)互聯(lián)網(wǎng)廣告行業(yè)
  • 網(wǎng)站開發(fā) 報價單 表格百度權(quán)重1是什么意思
  • 手機和網(wǎng)站頁面模板手機制作網(wǎng)頁
  • 在家做網(wǎng)站目前最火的推廣平臺
  • 呼市網(wǎng)站開發(fā)域名購買哪個網(wǎng)站好
  • 可以找酒店案例的網(wǎng)站網(wǎng)站流量排名
  • 茶的網(wǎng)站制作網(wǎng)站權(quán)重什么意思
  • 修改wordpress ftp端口廣州aso優(yōu)化
  • 培訓(xùn)學(xué)校 網(wǎng)站費用免費網(wǎng)站的軟件
  • WordPress快速發(fā)布文章濱州seo排名
  • 網(wǎng)站建設(shè)流行技術(shù)精準(zhǔn)客戶截流軟件
  • 專業(yè)做公司宣傳網(wǎng)站網(wǎng)站seo優(yōu)化步驟
  • 西安網(wǎng)站制作頂尖網(wǎng)站優(yōu)化要做哪些
  • 成都專業(yè)網(wǎng)站推廣公司百度推廣有哪些形式
  • 成都網(wǎng)站制作創(chuàng)新互聯(lián)微軟優(yōu)化大師
  • 天遠(yuǎn)軟件網(wǎng)站建設(shè)百家號關(guān)鍵詞排名優(yōu)化
  • 建網(wǎng)站公司成都百度服務(wù)中心投訴
  • 網(wǎng)站怎么做友情鏈接深圳關(guān)鍵詞排名推廣
  • 做網(wǎng)站簡單嗎百度后臺管理
  • 安徽省建設(shè)廳網(wǎng)站證書查詢跨境網(wǎng)站建站
  • 做商城網(wǎng)站要什么手續(xù)百度公司簡介