diff --git a/test-wsplay/ws.html b/test-wsplay/ws.html
new file mode 100644
index 0000000..b81ae00
--- /dev/null
+++ b/test-wsplay/ws.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+IntroQ/http
+
+
+
+
+
+PUSH PUSH PUSH
+
+
+Team(1から6):
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-wsplay/ws.js b/test-wsplay/ws.js
new file mode 100644
index 0000000..fd495b0
--- /dev/null
+++ b/test-wsplay/ws.js
@@ -0,0 +1,132 @@
+// 例
+// https://www.codespeedy.com/change-html5-audio-player-src-file-in-javascript/
+function intro() {
+ var team = document.getElementById("tm"),
+ button = document.getElementById("push"),
+ info = document.getElementById("info"),
+ music = document.getElementById("music"),
+ play = document.getElementById("play"),
+ msrc = document.getElementById("msrc");
+ var conn, PORT=8804, server = location.hostname;
+ server = "wss://www.iekei.org/hayaoshi/"
+ function sendmsg(str) {
+ conn.send(JSON.stringify({team: team.value, state: str}));
+ }
+ function initConn() {
+ alert(music.volume);
+ try {
+ conn = new WebSocket(server);
+ conn.onopen = function() {}; // Nothing special
+ conn.onerror = function(err) {
+ alert('WebSocket failure: ' + err)
+ };
+ conn.onmessage = function(ev) {
+ info.textContent = ev.data;
+ console.log("data: "+ev.data);
+ if (ev.data.match(/\.(mp3|ogg)/)) {
+ music.setAttribute("src", ev.data);
+ info.textContent = "Loading...";
+ //info.textContent = "Playing "+music.getAttribute("src");
+ music.volume = 0.1;
+ music.load();
+ if (team.value == "admin")
+ info.textContent += ev.data;
+ else
+ info.textContent += "Done.";
+ sendmsg("loading done");
+ button.disabled = false;
+ } else if (ev.data.match(/PING/)) {
+ sendmsg("PONG");
+ } else if (ev.data.match(/LOAD: (\d+)\/(\d+)/)) {
+ if (team.value == "admin") {
+ var a=parseInt(RegExp.$1), b=parseInt(RegExp.$2);
+ // alert(a+"..."+b);
+ if (a>=b) {
+ play.textContent = " PLAYxxx ";
+ info.textContent = music.getAttribute("src");
+ play.disabled = false;
+ } else {
+ play.textContent = (" PLAY "+a+"/"+b);
+ play.disabled = true;
+ }
+ }
+ } else if (ev.data.match(/(PLAY|STOP): ([0-9.]+) ([0-9.]+)/)) {
+ var delay = RegExp.$2*2000,
+ ct = parseFloat(RegExp.$3),
+ start = (RegExp.$1.match(/PLAY/))
+ delay = Math.round(delay*100)/100;
+ info.textContent = "PUSH!!!"+delay;
+ if (ct>0) {
+ console.log("StartPos="+ct);
+ music.currentTime = ct;
+ }
+ setTimeout(function() {
+ (start) ? music.play() : music.pause();
+ }, delay);
+ // music.resume().play();
+ // music.play();
+ } else if (ev.data.match(/RESET/)) {
+ console.log("Got RESET!!!!!");
+ music.currentTime = 0;
+ info.textContent = "Ready...";
+ button.disabled = false;
+ } else if (ev.data.match(new RegExp(team.value))) {
+ // alert(new RegExp(team.value));
+ music.pause();
+ button.disabled = true;
+ } else {
+ music.pause();
+ }
+ };
+ conn.onclose = function(ev) {
+ info.textContent = "接続断: 頃合を見てPUSHを押してください。";
+ button.disabled = false;
+ conn = null;
+ };
+ info.textContent = "Ready...";
+ } catch (err) {
+ alert("Socket Creation Error\n\
+Firefoxですか? URLウィンドウに about:config と入れて\n\
+Search: 窓に websocket と入れて、\n\
+network..websocket.allowInsecureFromHTTP\n\
+の行をダブルクリックして true に変えてください。\n" + err);
+ }
+ }
+ function push(ev) {
+ music.pause();
+ if (!conn) {
+ initConn();
+ } else if (team.value == "") {
+ alert("Teamに1から6のどれかを入れてね!");
+ } else {
+ var info = {team: team.value, state: "PUSH: "+music.currentTime},
+ str = JSON.stringify(info);
+ conn.send(str);
+ }
+ }
+ document.getElementById("prev").addEventListener("click", function() {
+ sendmsg("prev");
+ }, false);
+ document.getElementById("next").addEventListener("click", function() {
+ sendmsg("next");
+ }, false);
+ document.getElementById("play").addEventListener("click", function() {
+ sendmsg("PLAY");
+ }, false);
+ document.getElementById("stop").addEventListener("click", function() {
+ sendmsg("STOP: "+music.currentTime);
+ }, false);
+ document.getElementById("reset").addEventListener("click", function() {
+ sendmsg("RESET");
+ }, false);
+ function catchClick() {
+ info.setAttribute("pre-caution", "");
+ info.textContent = "Ready...";
+ music.play(); music.pause();
+ document.removeEventListener("click", catchClick);
+ }
+ document.addEventListener("click", catchClick, false);
+ button.addEventListener("mousedown", push, false);
+ initConn();
+}
+document.addEventListener("DOMContentLoaded", intro, false);
diff --git a/test-wsplay/ws.rb b/test-wsplay/ws.rb
new file mode 100755
index 0000000..e84543d
--- /dev/null
+++ b/test-wsplay/ws.rb
@@ -0,0 +1,120 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+# EM Intro. - http://keijinsonyaban.blogspot.jp/2010/12/eventmachine.html
+
+require 'em-websocket'
+require 'json'
+PORT = 8804
+
+clients = {}
+ans = {}
+readiness = {}
+
+@musiclist = ["aiai.ogg", "u-mebius.mp3", "u-tarou.ogg", "u-tiga-b.ogg",
+ "music-video.mp3"]
+@musicpos = 0
+@rediness = {}
+@admin = nil
+@stoptime = nil
+
+print("No clients yet...")
+EM::WebSocket.start({:host => "0.0.0.0", :port => PORT}) do |ws_conn|
+ ws_conn.onopen do
+ # p "hello"+ws_conn.inspect
+ clients[ws_conn] = a = {} # Start from NO NAME
+ printf("%d guest(s)\n", clients.keys.length)
+ a["ping"] = Time.now.to_f
+ ws_conn.send("PING")
+ end
+ ws_conn.onmessage do |message|
+ jv = JSON.parse(message)
+ team, st = jv['team'], jv['state']
+ if team > ''
+ clients[ws_conn]["name"] = team
+ if /PUSH: ([0-9.]+)/ =~ st
+ ans[team] = true
+ @stoptime = $1.to_f
+ STDERR.printf("Stopped at client %.3fs\n", @stoptime)
+ end
+ end
+ # clients.each{|conn| conn.send(resp) }
+ if team=="admin"
+ @admin = ws_conn
+ case st
+ when "prev"
+ @musicpos = [0, @musicpos-1].max
+ ans = {}; @rediness = {}; msg = @musiclist[@musicpos]
+ @stoptime = nil
+ when "next"
+ @musicpos = [@musiclist.length-1, @musicpos+1].min
+ ans = {}; @rediness = {}; msg = @musiclist[@musicpos]
+ @stoptime = nil
+ when "RESET"
+ ans = {}; msg="RESET"
+ @stoptime = nil
+ when "PLAY", /STOP: ([0-9.]+)/
+ cmd = (/PLAY/=~st ? "PLAY" : "STOP")
+ @stoptime = $1
+ maxdelay = clients.keys.collect{|x|clients[x]["delay"]}.max
+ clients.keys.each{|c|
+ d = maxdelay-clients[c]["delay"]
+ c.send("#{cmd}: #{d} #{@stoptime||0}")
+ }
+ msg=""
+ else
+ msg = ans.keys.select{|x|x!="admin"}.join(", ")
+ end
+ #if false && /prev|next/ =~ st
+ # STDERR.printf("Set pos @ %d -> %s\n", @musicpos, @musiclist[@musicpos])
+ # @rediness = {}
+ # clients.keys.each{|conn|
+ # conn.send(msg) # if conn!=ws_conn;
+ # }
+ if msg>""
+ clients.keys.each{|conn| conn.send(msg)}
+ end
+ end
+ resp = ans.keys.select{|x|x!="admin"}.join(", ")
+ case st
+ when /PONG/i
+ a = clients[ws_conn]
+ a["pong"] = Time.now.to_f
+ a["delay"] = a["pong"]-a["ping"]
+ p clients.values.collect{|v| v['delay']}.join(", ")
+ when /loading done/i
+ @rediness[ws_conn] = true
+ msg = "RESET"
+ STDERR.printf("%d/%d\n", @rediness.keys.length, clients.keys.length)
+ # clients.keys.each{|conn| conn.send("RESET")}
+ @admin.send(sprintf("LOAD: %d/%d\n", @rediness.keys.length, clients.keys.length))
+ if @rediness.keys.length == clients.keys.length then
+ clients.keys.each {|conn|
+ if conn != @admin
+ STDERR.puts("Sending RESET to #{conn}")
+ conn.send("RESET")
+ end
+ }
+ end
+ end
+ if /PLAY|STOP|RESET|loading/ !~ st
+ clients.keys.each{|conn| conn.send(resp);}
+ # clients.each{|conn| conn.send(@musiclist[@musicpos])}
+ end
+ end
+ ws_conn.onclose do
+ clients.delete(ws_conn)
+ @rediness
+ # p "bye"+ws_conn.inspect
+ printf("%d GUEST(s)\n", clients.keys.length)
+ end
+ EM::defer do
+ puts "..captured!"
+ loop do
+ print("Hit Return to Reset client messages...")
+ line = gets
+ puts("Resetting")
+ clients.keys.each{|conn| conn.send("Ready..") }
+ ans = {};
+ end
+ end
+end