+++ /dev/null
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-
-<head>
- <meta charset="utf-8">
- <title>CANVAS VIDEO</title>
- <style>
- #Video {
- border: 1px solid red;
- }
- </style>
-</head>
-
-<body>
- <canvas id="Video" width="120" height="160"></canvas>
- <pre id="Stat"></pre>
- <pre id="Msg"></pre>
-
- <script>
- var ws;
- var wsURL = "ws://127.0.0.1/stream";
- var canvas = document.getElementById('Video');
- var ctx = canvas.getContext('2d');
-
- var frameCount = 0;
- var totalBytes = 0;
- window.setInterval(function() {
- fps = frameCount;
- bytes = totalBytes;
-
- frameCount = 0;
- totalBytes = 0;
-
- var Stat = document.getElementById('Stat');
- Stat.innerHTML = "当前帧率: " + fps + " fps, 带宽:" + (bytes*8.0/(1024.0*1024.0)).toFixed(1) + " Mbps";
- },1000)
-
- function Msg(...args) {
- msg = args.join('');
- console.log(msg);
-
- var Msg = document.getElementById('Msg');
- contents = Msg.innerHTML;
- contents += msg;
- slice = contents.split('\n').slice(-5);
- msg = slice.join('\n')+'\n';
- Msg.innerHTML = msg;
- }
-
- function initWebsocket() {
- ws = new WebSocket(wsURL);
- ws.SendCmd = function(req) {
- req = JSON.stringify(req);
- ws.send(req);
- }
-
- ws.onopen = function () {
- Msg("websocket opened");
- };
-
- ws.onerror = function (event) {
- Msg("websocket error: " + event);
- };
-
- ws.onclose = function (event) {
- Msg("websocket closed with code: " + event.code + " reason: " + event.reason);
- };
-
- ws.onmessage = function (event) {
- imageData = event.data;
- frameCount++;
- totalBytes += imageData.size;
- Msg("frame data len: ", imageData.size);
- var image = new Image();
- image.src = URL.createObjectURL(imageData);
- image.onload = () => {
- URL.revokeObjectURL(image.src);
- ctx.save();
- ctx.translate(60, 80);
- ctx.rotate(90*(Math.PI/180));
- ctx.translate(-80, -60);
- ctx.drawImage(image, 0, 0);
- ctx.restore();
- }
- };
- }
-
- initWebsocket();
- </script>
-</body>
-
-</html>
var frameChan chan []byte
func init() {
- frameChan = make(chan []byte, 8)
+ frameChan = make(chan []byte, 128)
}
-const (
- partBOUNDARY = "123456789000000000000987654321"
- streamContentType = "multipart/x-mixed-replace;boundary=" + partBOUNDARY
- streamBoundary = "\r\n--" + partBOUNDARY + "\r\n"
- streamPart = "Content-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n"
-)
-
-func watchHandler(w http.ResponseWriter, r *http.Request) {
- var err error
- w.Header().Set("Content-Type", streamContentType)
- w.Header().Set("Access-Control-Allow-Origin", "*")
-
- flusher, _ := w.(http.Flusher)
-
- for i := 0; ; i++ {
- var data []byte
- select {
- case data = <-frameChan:
- fmt.Fprintf(w, "%v", streamBoundary)
- fmt.Fprintf(w, streamPart, i)
- _, err = w.Write(data)
- flusher.Flush()
- if err != nil {
- break
- }
- default:
- continue
- }
-
- }
-}
func audioHandler(w http.ResponseWriter, r *http.Request) {
var err error
}
}
-func canvasHandler(w http.ResponseWriter, r *http.Request) {
- tmpl := template.Must(template.ParseFiles("./canvas.html"))
+func playerHandler(w http.ResponseWriter, r *http.Request) {
+ tmpl := template.Must(template.ParseFiles("./player.html"))
var data = map[string]interface{}{}
tmpl.Execute(w, data)
}
defer fmt.Println("Program Exited...")
m := http.NewServeMux()
- m.HandleFunc("/watch", watchHandler)
m.HandleFunc("/audio", audioHandler)
- m.HandleFunc("/canvas", canvasHandler)
+ m.HandleFunc("/player", playerHandler)
m.HandleFunc("/stream", streamHandler)
server := http.Server{
Addr: ":80",
--- /dev/null
+<!DOCTYPE html>
+<html lang="en" dir="ltr">
+
+<head>
+ <meta charset="utf-8">
+ <title>AUDIO PLAYER</title>
+ <style>
+
+ </style>
+</head>
+
+<body>
+ <button onclick="play();">PLAY</button>
+ <pre id="Stat"></pre>
+ <pre id="Msg"></pre>
+
+ <script>
+ var ws;
+ var wsURL = "ws://10.0.0.6/stream";
+
+ var frameCount = 0;
+ var totalBytes = 0;
+ window.setInterval(function() {
+ fps = frameCount;
+ bytes = totalBytes;
+
+ frameCount = 0;
+ totalBytes = 0;
+
+ var Stat = document.getElementById('Stat');
+ Stat.innerHTML = "当前帧率: " + fps + " fps, 带宽:" + (bytes*8.0/(1024.0*1024.0)).toFixed(1) + " Mbps";
+ },1000)
+
+ function Msg(...args) {
+ msg = args.join('');
+ console.log(msg);
+
+ var Msg = document.getElementById('Msg');
+ contents = Msg.innerHTML;
+ contents += msg;
+ slice = contents.split('\n').slice(-5);
+ msg = slice.join('\n')+'\n';
+ Msg.innerHTML = msg;
+ }
+
+ class PcmDataPlayer {
+ constructor() {
+ this.sampleRate = 8000;
+ this.flushTime = 1000;
+ this.audioSamples = new Float32Array();
+
+ this.audioCtx = new window.AudioContext();
+ this.gainNode = this.audioCtx.createGain();
+ this.gainNode.connect(this.audioCtx.destination);
+ this.startTime = this.audioCtx.currentTime;
+
+ setInterval(this.play.bind(this), this.flushTime);
+ }
+ play() {
+ const length = this.audioSamples.length;
+
+ if (0 == length) {
+ return
+ }
+
+ const audioBuffer = this.audioCtx.createBuffer(1, length, this.sampleRate);
+ const audioData = audioBuffer.getChannelData(0);
+ for (let i = 0; i < length; i++) {
+ audioData[i] = this.audioSamples[i];
+ }
+
+ if (this.startTime < this.audioCtx.currentTime) {
+ this.startTime = this.audioCtx.currentTime;
+ }
+ console.log('start vs current ' + this.startTime.toFixed(2) + ' vs ' + this.audioCtx.currentTime.toFixed(2) + ' duration: ' + audioBuffer.duration.toFixed(2));
+
+ var bufferSource = this.audioCtx.createBufferSource();
+ bufferSource.buffer = audioBuffer;
+ bufferSource.connect(this.gainNode);
+ bufferSource.start(this.startTime);
+ this.startTime += audioBuffer.duration;
+ this.audioSamples = new Float32Array();
+ }
+
+ putAudioData(data) {
+ let float32Data = new Float32Array(data.length);
+ for (let i = 0; i < data.length; i++) {
+ float32Data[i] = data[i] / (32768.0/5.0);
+ }
+
+ const tmp = new Float32Array(this.audioSamples.length + float32Data.length);
+ tmp.set(this.audioSamples, 0);
+ tmp.set(float32Data, this.audioSamples.length);
+ this.audioSamples = tmp;
+ }
+ }
+
+ // play函数会初始化音频设备
+ // 浏览器要求必需要用户手动触发,不能自动播放
+ // 因此该函数通过网页上的按钮click调用,而不是网页加载完成后直接调用
+ function play() {
+ var player = new PcmDataPlayer();
+
+ function initWebsocket() {
+ ws = new WebSocket(wsURL);
+ ws.binaryType = 'arraybuffer';
+ ws.SendCmd = function(req) {
+ req = JSON.stringify(req);
+ ws.send(req);
+ }
+
+ ws.onopen = function () {
+ Msg("websocket opened");
+ };
+
+ ws.onerror = function (event) {
+ Msg("websocket error: " + event);
+ };
+
+ ws.onclose = function (event) {
+ Msg("websocket closed with code: " + event.code + " reason: " + event.reason);
+ };
+
+ ws.onmessage = function (event) {
+ data = event.data;
+ frameCount++;
+ totalBytes += data.byteLength;
+
+ data = Array.prototype.slice.call(new Uint16Array(data));
+ player.putAudioData(data);
+ };
+ }
+
+ initWebsocket();
+ }
+
+ </script>
+</body>
+
+</html>