-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
181 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
use smol::io::{AsyncWriteExt, AsyncReadExt}; | ||
use smol::net::{TcpListener, TcpStream}; | ||
use smol::stream::StreamExt; | ||
|
||
use crate::util::spawn_and_log_error; | ||
|
||
pub async fn run_server(addr: String, player_html: String) -> anyhow::Result<()> { | ||
// Open up a TCP connection and create a URL. | ||
let listener = TcpListener::bind(addr).await?; | ||
let addr = format!("http://{}", listener.local_addr()?); | ||
log::info!("HTTP-Player Server is listening to {}", addr); | ||
|
||
// For each incoming TCP connection, spawn a task and call `accept`. | ||
let mut incoming = listener.incoming(); | ||
while let Some(stream) = incoming.next().await { | ||
let stream = stream?; | ||
spawn_and_log_error(accept(stream, player_html.clone())); | ||
} | ||
Ok(()) | ||
} | ||
|
||
async fn accept(mut stream: TcpStream, player_html: String) -> anyhow::Result<()> { | ||
log::info!("[HTTP] new connection from {}", stream.peer_addr()?); | ||
|
||
let mut buffer = [0; 1024]; | ||
stream.read(&mut buffer).await?; | ||
|
||
let header = format!("HTTP/1.1 200 OK\r\n\ | ||
Content-Type: text/html;charset=UTF-8\r\n\ | ||
Connection: close\r\n\ | ||
Content-Length: {}\r\n\ | ||
Cache-Control: no-cache\r\n\ | ||
Access-Control-Allow-Origin: *\r\n\ | ||
\r\n\ | ||
{}", player_html.len(), player_html); | ||
stream.write_all(header.as_bytes()).await?; | ||
stream.flush().await?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<!doctype html> | ||
<html lang="zh"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" | ||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"> | ||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/jmuxer@2.0.2/dist/jmuxer.min.js"></script> | ||
<title>River Player</title> | ||
</head> | ||
<body> | ||
<div id="container" style="margin: 10px auto 0; width: 1024px;"> | ||
<video style="border: 1px solid #333; width: 1024px;" autoplay id="player"></video> | ||
<br> | ||
<div> | ||
<button class="ui labeled icon button" onclick="open_ws(url, jmuxer);"> | ||
<i class="play icon"></i> | ||
Play | ||
</button> | ||
|
||
<button class="ui labeled icon button" onclick="close_ws()"> | ||
<i class="stop icon"></i> | ||
Stop | ||
</button> | ||
|
||
<button class="ui labeled icon disabled button" onclick=""> | ||
<i class="expand icon"></i> | ||
Expand | ||
</button> | ||
</div> | ||
</div> | ||
</body> | ||
<script> | ||
const ctx = {/*$INJECTED_CONTEXT*/}; | ||
|
||
const url = `ws://${document.domain}:${ctx.port}/websocket${window.location.pathname}`; | ||
let jmuxer = null; | ||
let timer_id = null; | ||
|
||
let close_ws = () => { | ||
}; | ||
|
||
$(function main() { | ||
jmuxer = new JMuxer({ | ||
flushingTime: 100, | ||
fps: 30, | ||
node: 'player', | ||
mode: 'both', /* available values are: both, audio and video */ | ||
debug: false | ||
}); | ||
|
||
let player = video_element = document.getElementById('player'); | ||
|
||
document.addEventListener("visibilitychange", function () { | ||
forward_latest_frame(player); | ||
}); | ||
|
||
timer_id = setInterval(() => { | ||
forward_latest_frame(player); | ||
}, 2000); | ||
}); | ||
|
||
function open_ws(url, jmuxer) { | ||
close_ws(); | ||
|
||
const socket = new WebSocket(url); | ||
socket.binaryType = 'arraybuffer'; | ||
|
||
socket.addEventListener('open', function () { | ||
console.log(`[event open] url=${url}`); | ||
}); | ||
|
||
socket.addEventListener('message', function (event) { | ||
feed_data(jmuxer, new Uint8Array(event.data)); | ||
}); | ||
|
||
socket.addEventListener('close', function () { | ||
console.log(`[event close]`); | ||
}); | ||
|
||
close_ws = () => { | ||
clearInterval(timer_id); | ||
socket.close(1000); | ||
console.info("[close_ws] closed"); | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @param jmuxer | ||
* @param event_data | ||
*/ | ||
function feed_data(jmuxer, event_data) { | ||
const type_flag = event_data[0]; | ||
const media_data = event_data.subarray(1); | ||
// console.log(`[feed_data] type=${type_flag}, len=${media_data.length}`); | ||
jmuxer.feed(type_flag ? {audio: media_data} : {video: media_data}); | ||
} | ||
|
||
function forward_latest_frame(video) { | ||
if (video && video.buffered && video.buffered.end(0)) { | ||
let latest = video.buffered.end(0); | ||
if (latest - video.currentTime > 0.3) { | ||
video.currentTime = latest; | ||
console.log(`[forward_latest_frame] latest=${latest}`); | ||
} | ||
} | ||
} | ||
|
||
|
||
</script> | ||
</html> |