Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2013-12-23 01:22:10 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
6875b6f5f20e2baab1e816b1085d964d62093894
6875b6f5
1 parent
e9a88e6b
support chat room, meeting.
隐藏空白字符变更
内嵌
并排对比
正在显示
4 个修改的文件
包含
692 行增加
和
338 行删除
trunk/research/api-server/server.py
trunk/research/players/js/srs.js
trunk/research/players/srs_chat.html
trunk/research/players/srs_publisher.html
trunk/research/api-server/server.py
查看文件 @
6875b6f
...
...
@@ -36,7 +36,7 @@ reload(sys)
exec
(
"sys.setdefaultencoding('utf-8')"
)
assert
sys
.
getdefaultencoding
()
.
lower
()
==
"utf-8"
import
json
,
datetime
,
cherrypy
import
os
,
json
,
time
,
datetime
,
cherrypy
,
threading
# simple log functions.
def
trace
(
msg
):
...
...
@@ -320,6 +320,123 @@ class RESTSessions(object):
return
code
global_chat_id
=
os
.
getpid
();
'''
the chat streams, public chat room.
'''
class
RESTChats
(
object
):
exposed
=
True
global_id
=
100
def
__init__
(
self
):
# object fields:
# id: an int value indicates the id of user.
# username: a str indicates the user name.
# url: a str indicates the url of user stream.
# agent: a str indicates the agent of user.
# join_date: a number indicates the join timestamp in seconds.
# join_date_str: a str specifies the formated friendly time.
# heatbeat: a number indicates the heartbeat timestamp in seconds.
# vcodec: a dict indicates the video codec info.
# acodec: a dict indicates the audio codec info.
self
.
__chats
=
[];
self
.
__chat_lock
=
threading
.
Lock
();
# dead time in seconds, if exceed, remove the chat.
self
.
__dead_time
=
30
;
def
GET
(
self
):
enable_crossdomain
()
try
:
self
.
__chat_lock
.
acquire
();
chats
=
[];
copy
=
self
.
__chats
[:];
for
chat
in
copy
:
if
time
.
time
()
-
chat
[
"heartbeat"
]
>
self
.
__dead_time
:
self
.
__chats
.
remove
(
chat
);
continue
;
chats
.
append
({
"id"
:
chat
[
"id"
],
"username"
:
chat
[
"username"
],
"url"
:
chat
[
"url"
],
"join_date_str"
:
chat
[
"join_date_str"
],
"heartbeat"
:
chat
[
"heartbeat"
],
});
finally
:
self
.
__chat_lock
.
release
();
return
json
.
dumps
({
"code"
:
0
,
"data"
:
{
"now"
:
time
.
time
(),
"chats"
:
chats
}})
def
POST
(
self
):
enable_crossdomain
()
req
=
cherrypy
.
request
.
body
.
read
()
chat
=
json
.
loads
(
req
)
global
global_chat_id
;
chat
[
"id"
]
=
global_chat_id
global_chat_id
+=
1
chat
[
"join_date"
]
=
time
.
time
();
chat
[
"heartbeat"
]
=
time
.
time
();
chat
[
"join_date_str"
]
=
time
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
);
try
:
self
.
__chat_lock
.
acquire
();
self
.
__chats
.
append
(
chat
)
finally
:
self
.
__chat_lock
.
release
();
trace
(
"create chat success, id=
%
s"
%
(
chat
[
"id"
]))
return
json
.
dumps
({
"code"
:
0
,
"data"
:
chat
[
"id"
]})
def
DELETE
(
self
,
id
):
enable_crossdomain
()
try
:
self
.
__chat_lock
.
acquire
();
for
chat
in
self
.
__chats
:
if
str
(
id
)
!=
str
(
chat
[
"id"
]):
continue
self
.
__chats
.
remove
(
chat
)
trace
(
"delete chat success, id=
%
s"
%
(
id
))
return
json
.
dumps
({
"code"
:
0
,
"data"
:
None
})
finally
:
self
.
__chat_lock
.
release
();
raise
cherrypy
.
HTTPError
(
405
,
"Not allowed."
)
def
PUT
(
self
,
id
):
enable_crossdomain
()
try
:
self
.
__chat_lock
.
acquire
();
for
chat
in
self
.
__chats
:
if
str
(
id
)
!=
str
(
chat
[
"id"
]):
continue
chat
[
"heartbeat"
]
=
time
.
time
();
trace
(
"heartbeat chat success, id=
%
s"
%
(
id
))
return
json
.
dumps
({
"code"
:
0
,
"data"
:
None
})
finally
:
self
.
__chat_lock
.
release
();
raise
cherrypy
.
HTTPError
(
405
,
"Not allowed."
)
def
OPTIONS
(
self
,
id
=
None
):
enable_crossdomain
()
# HTTP RESTful path.
class
Root
(
object
):
def
__init__
(
self
):
...
...
@@ -335,6 +452,7 @@ class V1(object):
self
.
clients
=
RESTClients
()
self
.
streams
=
RESTStreams
()
self
.
sessions
=
RESTSessions
()
self
.
chats
=
RESTChats
()
'''
main code start.
...
...
trunk/research/players/js/srs.js
查看文件 @
6875b6f
...
...
@@ -28,6 +28,31 @@ function update_nav() {
}
/**
* log specified, there must be a log element as:
<!-- for the log -->
<div class="alert alert-info fade in" id="txt_log">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong><span id="txt_log_title">Usage:</span></strong>
<span id="txt_log_msg">创建会议室,或者加入会议室</span>
</div>
*/
function
info
(
desc
)
{
$
(
"#txt_log"
).
addClass
(
"alert-info"
).
removeClass
(
"alert-error"
).
removeClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Info:"
);
$
(
"#txt_log_msg"
).
text
(
desc
);
}
function
warn
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
removeClass
(
"alert-error"
).
addClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Warn:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
}
function
error
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
addClass
(
"alert-error"
).
removeClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Error:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
}
/**
* parse the query string to object.
*/
function
parse_query_string
(){
...
...
@@ -83,6 +108,23 @@ function build_default_rtmp_url() {
return
"rtmp://"
+
server
+
":"
+
port
+
"/"
+
app
+
"...vhost..."
+
vhost
+
"/"
+
stream
;
}
}
// for the chat to init the publish url.
function
build_default_publish_rtmp_url
()
{
var
query
=
parse_query_string
();
var
server
=
(
query
.
server
==
undefined
)?
window
.
location
.
hostname
:
query
.
server
;
var
port
=
(
query
.
port
==
undefined
)?
1935
:
query
.
port
;
var
vhost
=
(
query
.
vhost
==
undefined
)?
window
.
location
.
hostname
:
query
.
vhost
;
var
app
=
(
query
.
app
==
undefined
)?
"live"
:
query
.
app
;
var
stream
=
(
query
.
stream
==
undefined
)?
"livestream"
:
query
.
stream
;
if
(
server
==
vhost
||
vhost
==
""
)
{
return
"rtmp://"
+
server
+
":"
+
port
+
"/"
+
app
+
"/"
+
stream
;
}
else
{
vhost
=
srs_get_player_publish_vhost
(
vhost
);
return
"rtmp://"
+
server
+
":"
+
port
+
"/"
+
app
+
"...vhost..."
+
vhost
+
"/"
+
stream
;
}
}
/**
@param server the ip of server. default to window.location.hostname
...
...
@@ -162,6 +204,8 @@ function srs_get_player_height() { return srs_get_player_width() * 9 / 19; }
function
srs_get_version_code
()
{
return
"1.5"
;
}
// get the default vhost for players.
function
srs_get_player_vhost
()
{
return
"players"
;
}
// the api server port, for chat room.
function
srs_get_api_server_port
()
{
return
8085
;
}
// get the stream published to vhost,
// generally we need to transcode the stream to support HLS and filters.
// for example, src_vhost is "players", we transcode stream to vhost "players_pub".
...
...
@@ -188,6 +232,112 @@ function srs_init(rtmp_url, hls_url, modal_player) {
$
(
modal_player
).
css
(
"margin-left"
,
"-"
+
srs_get_player_modal
()
/
2
+
"px"
);
}
}
// for the chat to init the publish url.
function
srs_init_publish
(
rtmp_url
)
{
update_nav
();
if
(
rtmp_url
)
{
$
(
rtmp_url
).
val
(
build_default_publish_rtmp_url
());
}
}
/**
* when publisher ready, init the page elements.
*/
function
srs_publisher_initialize_page
(
cameras
,
microphones
,
sl_cameras
,
sl_microphones
,
sl_vcodec
,
sl_profile
,
sl_level
,
sl_gop
,
sl_size
,
sl_fps
,
sl_bitrate
)
{
$
(
sl_cameras
).
empty
();
for
(
var
i
=
0
;
i
<
cameras
.
length
;
i
++
)
{
$
(
sl_cameras
).
append
(
"<option value='"
+
i
+
"'>"
+
cameras
[
i
]
+
"</option"
);
}
// optional: select the first no "virtual" signed.
for
(
var
i
=
0
;
i
<
cameras
.
length
;
i
++
)
{
if
(
cameras
[
i
].
toLowerCase
().
indexOf
(
"virtual"
)
==
-
1
)
{
$
(
sl_cameras
+
" option[value='"
+
i
+
"']"
).
attr
(
"selected"
,
true
);
break
;
}
}
$
(
sl_microphones
).
empty
();
for
(
var
i
=
0
;
i
<
microphones
.
length
;
i
++
)
{
$
(
sl_microphones
).
append
(
"<option value='"
+
i
+
"'>"
+
microphones
[
i
]
+
"</option"
);
}
$
(
sl_vcodec
).
empty
();
var
vcodecs
=
[
"h264"
,
"vp6"
];
for
(
var
i
=
0
;
i
<
vcodecs
.
length
;
i
++
)
{
$
(
sl_vcodec
).
append
(
"<option value='"
+
vcodecs
[
i
]
+
"'>"
+
vcodecs
[
i
]
+
"</option"
);
}
$
(
sl_profile
).
empty
();
var
profiles
=
[
"baseline"
,
"main"
];
for
(
var
i
=
0
;
i
<
profiles
.
length
;
i
++
)
{
$
(
sl_profile
).
append
(
"<option value='"
+
profiles
[
i
]
+
"'>"
+
profiles
[
i
]
+
"</option"
);
}
$
(
sl_level
).
empty
();
var
levels
=
[
"1"
,
"1b"
,
"1.1"
,
"1.2"
,
"1.3"
,
"2"
,
"2.1"
,
"2.2"
,
"3"
,
"3.1"
,
"3.2"
,
"4"
,
"4.1"
,
"4.2"
,
"5"
,
"5.1"
];
for
(
var
i
=
0
;
i
<
levels
.
length
;
i
++
)
{
$
(
sl_level
).
append
(
"<option value='"
+
levels
[
i
]
+
"'>"
+
levels
[
i
]
+
"</option"
);
}
$
(
sl_level
+
" option[value='4.1']"
).
attr
(
"selected"
,
true
);
$
(
sl_gop
).
empty
();
var
gops
=
[
"0.3"
,
"0.5"
,
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
,
"9"
,
"10"
,
"15"
,
"20"
];
for
(
var
i
=
0
;
i
<
gops
.
length
;
i
++
)
{
$
(
sl_gop
).
append
(
"<option value='"
+
gops
[
i
]
+
"'>"
+
gops
[
i
]
+
"秒</option"
);
}
$
(
sl_gop
+
" option[value='5']"
).
attr
(
"selected"
,
true
);
$
(
sl_size
).
empty
();
var
sizes
=
[
"176x144"
,
"320x240"
,
"352x240"
,
"352x288"
,
"460x240"
,
"640x480"
,
"720x480"
,
"720x576"
,
"800x600"
,
"1024x768"
,
"1280x720"
,
"1360x768"
,
"1920x1080"
];
for
(
i
=
0
;
i
<
sizes
.
length
;
i
++
)
{
$
(
sl_size
).
append
(
"<option value='"
+
sizes
[
i
]
+
"'>"
+
sizes
[
i
]
+
"</option"
);
}
$
(
sl_size
+
" option[value='460x240']"
).
attr
(
"selected"
,
true
);
$
(
sl_fps
).
empty
();
var
fpses
=
[
"5"
,
"10"
,
"15"
,
"20"
,
"24"
,
"25"
,
"29.97"
,
"30"
];
for
(
i
=
0
;
i
<
fpses
.
length
;
i
++
)
{
$
(
sl_fps
).
append
(
"<option value='"
+
fpses
[
i
]
+
"'>"
+
Number
(
fpses
[
i
]).
toFixed
(
2
)
+
" 帧/秒</option"
);
}
$
(
sl_fps
+
" option[value='15']"
).
attr
(
"selected"
,
true
);
$
(
sl_bitrate
).
empty
();
var
bitrates
=
[
"50"
,
"200"
,
"350"
,
"500"
,
"650"
,
"800"
,
"950"
,
"1000"
,
"1200"
,
"1500"
,
"1800"
,
"2000"
,
"3000"
,
"5000"
];
for
(
i
=
0
;
i
<
bitrates
.
length
;
i
++
)
{
$
(
sl_bitrate
).
append
(
"<option value='"
+
bitrates
[
i
]
+
"'>"
+
bitrates
[
i
]
+
" kbps</option"
);
}
$
(
sl_bitrate
+
" option[value='350']"
).
attr
(
"selected"
,
true
);
}
/**
* get the vcodec and acodec.
*/
function
srs_publiser_get_codec
(
vcodec
,
acodec
,
sl_cameras
,
sl_microphones
,
sl_vcodec
,
sl_profile
,
sl_level
,
sl_gop
,
sl_size
,
sl_fps
,
sl_bitrate
)
{
acodec
.
device_code
=
$
(
sl_microphones
).
val
();
acodec
.
device_name
=
$
(
sl_microphones
).
text
();
vcodec
.
device_code
=
$
(
sl_cameras
).
find
(
"option:selected"
).
val
();
vcodec
.
device_name
=
$
(
sl_cameras
).
find
(
"option:selected"
).
text
();
vcodec
.
codec
=
$
(
sl_vcodec
).
find
(
"option:selected"
).
val
();
vcodec
.
profile
=
$
(
sl_profile
).
find
(
"option:selected"
).
val
();
vcodec
.
level
=
$
(
sl_level
).
find
(
"option:selected"
).
val
();
vcodec
.
fps
=
$
(
sl_fps
).
find
(
"option:selected"
).
val
();
vcodec
.
gop
=
$
(
sl_gop
).
find
(
"option:selected"
).
val
();
vcodec
.
size
=
$
(
sl_size
).
find
(
"option:selected"
).
val
();
vcodec
.
bitrate
=
$
(
sl_bitrate
).
find
(
"option:selected"
).
val
();
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
...
...
@@ -223,11 +373,16 @@ function SrsPlayer(container, width, height) {
}
/**
* user can set some callback, then start the player.
* @param url the default url.
* callbacks:
* on_player_ready():int, when srs player ready, user can play.
* on_player_metadata(metadata:Object):int, when srs player get metadata.
*/
SrsPlayer
.
prototype
.
start
=
function
()
{
SrsPlayer
.
prototype
.
start
=
function
(
url
)
{
if
(
url
)
{
this
.
stream_url
=
url
;
}
// embed the flash.
var
flashvars
=
{};
flashvars
.
id
=
this
.
id
;
...
...
@@ -262,7 +417,9 @@ SrsPlayer.prototype.start = function() {
* @param stream_url the url of stream, rtmp or http.
*/
SrsPlayer
.
prototype
.
play
=
function
(
url
)
{
this
.
stream_url
=
url
;
if
(
url
)
{
this
.
stream_url
=
url
;
}
this
.
callbackObj
.
ref
.
__play
(
this
.
stream_url
,
this
.
width
,
this
.
height
,
this
.
buffer_time
);
}
SrsPlayer
.
prototype
.
stop
=
function
()
{
...
...
trunk/research/players/srs_chat.html
查看文件 @
6875b6f
...
...
@@ -15,99 +15,45 @@
</style>
<script
type=
"text/javascript"
>
var
srs_publisher
=
null
;
var
remote_player
=
null
;
var
realtime_player
=
null
;
var
wizard
=
null
;
var
api_server
=
null
;
var
self_chat
=
null
;
var
global_chat_user_id
=
200
;
var
previous_chats
=
[];
var
no_play
=
false
;
$
(
function
(){
// get the vhost and port to set the default url.
// for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
// url set to: rtmp://demo:1935/live/livestream
srs_init
(
"#txt_url"
,
null
,
null
);
srs_init
_publish
(
"#txt_url"
);
$
(
"#btn_create_chat"
).
click
(
function
(){
// if no play specified, donot show the player, for debug the publisher.
var
query
=
parse_query_string
();
if
(
query
.
no_play
==
"true"
)
{
no_play
=
true
;
}
$
(
"#btn_video_settings"
).
click
(
function
(){
$
(
"#video_modal"
).
modal
({
show
:
true
});
});
$
(
"#btn_
join_chat
"
).
click
(
function
(){
$
(
"#btn_
audio_settings
"
).
click
(
function
(){
$
(
"#audio_modal"
).
modal
({
show
:
true
});
});
$
(
"#btn_publish"
).
click
(
on_user_publish
);
$
(
"#btn_join"
).
click
(
on_user_publish
);
// for publish, we use randome stream name.
$
(
"#txt_url"
).
val
(
$
(
"#txt_url"
).
val
()
+
"."
+
new
Date
().
getTime
());
// start the publisher.
srs_publisher
=
new
SrsPublisher
(
"local_publisher"
,
430
,
185
);
srs_publisher
.
on_publisher_ready
=
function
(
cameras
,
microphones
)
{
$
(
"#sl_cameras"
).
empty
();
for
(
var
i
=
0
;
i
<
cameras
.
length
;
i
++
)
{
$
(
"#sl_cameras"
).
append
(
"<option value='"
+
i
+
"'>"
+
cameras
[
i
]
+
"</option"
);
}
// optional: select the first no "virtual" signed.
for
(
var
i
=
0
;
i
<
cameras
.
length
;
i
++
)
{
if
(
cameras
[
i
].
toLowerCase
().
indexOf
(
"virtual"
)
==
-
1
)
{
$
(
"#sl_cameras option[value='"
+
i
+
"']"
).
attr
(
"selected"
,
true
);
break
;
}
}
$
(
"#sl_microphones"
).
empty
();
for
(
var
i
=
0
;
i
<
microphones
.
length
;
i
++
)
{
$
(
"#sl_microphones"
).
append
(
"<option value='"
+
i
+
"'>"
+
microphones
[
i
]
+
"</option"
);
}
$
(
"#sl_vcodec"
).
empty
();
var
vcodecs
=
[
"h264"
,
"vp6"
];
for
(
var
i
=
0
;
i
<
vcodecs
.
length
;
i
++
)
{
$
(
"#sl_vcodec"
).
append
(
"<option value='"
+
vcodecs
[
i
]
+
"'>"
+
vcodecs
[
i
]
+
"</option"
);
}
$
(
"#sl_profile"
).
empty
();
var
profiles
=
[
"baseline"
,
"main"
];
for
(
var
i
=
0
;
i
<
profiles
.
length
;
i
++
)
{
$
(
"#sl_profile"
).
append
(
"<option value='"
+
profiles
[
i
]
+
"'>"
+
profiles
[
i
]
+
"</option"
);
}
$
(
"#sl_level"
).
empty
();
var
levels
=
[
"1"
,
"1b"
,
"1.1"
,
"1.2"
,
"1.3"
,
"2"
,
"2.1"
,
"2.2"
,
"3"
,
"3.1"
,
"3.2"
,
"4"
,
"4.1"
,
"4.2"
,
"5"
,
"5.1"
];
for
(
var
i
=
0
;
i
<
levels
.
length
;
i
++
)
{
$
(
"#sl_level"
).
append
(
"<option value='"
+
levels
[
i
]
+
"'>"
+
levels
[
i
]
+
"</option"
);
}
$
(
"#sl_level option[value='4.1']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_gop"
).
empty
();
var
gops
=
[
"0.3"
,
"0.5"
,
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
,
"9"
,
"10"
,
"15"
,
"20"
];
for
(
var
i
=
0
;
i
<
gops
.
length
;
i
++
)
{
$
(
"#sl_gop"
).
append
(
"<option value='"
+
gops
[
i
]
+
"'>"
+
gops
[
i
]
+
"秒</option"
);
}
$
(
"#sl_gop option[value='5']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_size"
).
empty
();
var
sizes
=
[
"176x144"
,
"320x240"
,
"352x240"
,
"352x288"
,
"460x240"
,
"640x480"
,
"720x480"
,
"720x576"
,
"800x600"
,
"1024x768"
,
"1280x720"
,
"1360x768"
,
"1920x1080"
];
for
(
i
=
0
;
i
<
sizes
.
length
;
i
++
)
{
$
(
"#sl_size"
).
append
(
"<option value='"
+
sizes
[
i
]
+
"'>"
+
sizes
[
i
]
+
"</option"
);
}
$
(
"#sl_size option[value='460x240']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_fps"
).
empty
();
var
fpses
=
[
"5"
,
"10"
,
"15"
,
"20"
,
"24"
,
"25"
,
"29.97"
,
"30"
];
for
(
i
=
0
;
i
<
fpses
.
length
;
i
++
)
{
$
(
"#sl_fps"
).
append
(
"<option value='"
+
fpses
[
i
]
+
"'>"
+
Number
(
fpses
[
i
]).
toFixed
(
2
)
+
" 帧/秒</option"
);
}
$
(
"#sl_fps option[value='15']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_bitrate"
).
empty
();
var
bitrates
=
[
"50"
,
"200"
,
"350"
,
"500"
,
"650"
,
"800"
,
"950"
,
"1000"
,
"1200"
,
"1500"
,
"1800"
,
"2000"
,
"3000"
,
"5000"
];
for
(
i
=
0
;
i
<
bitrates
.
length
;
i
++
)
{
$
(
"#sl_bitrate"
).
append
(
"<option value='"
+
bitrates
[
i
]
+
"'>"
+
bitrates
[
i
]
+
" kbps</option"
);
}
$
(
"#sl_bitrate option[value='350']"
).
attr
(
"selected"
,
true
);
srs_publisher_initialize_page
(
cameras
,
microphones
,
"#sl_cameras"
,
"#sl_microphones"
,
"#sl_vcodec"
,
"#sl_profile"
,
"#sl_level"
,
"#sl_gop"
,
"#sl_size"
,
"#sl_fps"
,
"#sl_bitrate"
);
};
srs_publisher
.
on_publisher_error
=
function
(
code
,
desc
)
{
error
(
code
,
desc
);
...
...
@@ -117,20 +63,7 @@
};
srs_publisher
.
start
();
//wizard = $("#some-wizard").wizard({});
//wizard.show();
// if no play specified, donot show the player, for debug the publisher.
var
query
=
parse_query_string
();
if
(
query
.
no_play
!=
"true"
)
{
// start the normal player with HLS supported.
remote_player
=
new
SrsPlayer
(
"remote_player"
,
430
,
185
);
remote_player
.
on_player_ready
=
function
()
{
remote_player
.
set_bt
(
0.8
);
remote_player
.
set_fs
(
"screen"
,
100
);
};
remote_player
.
start
();
if
(
!
no_play
)
{
// start the realtime player.
realtime_player
=
new
SrsPlayer
(
"realtime_player"
,
430
,
185
);
realtime_player
.
on_player_ready
=
function
()
{
...
...
@@ -139,101 +72,340 @@
};
realtime_player
.
start
();
}
api_server
=
"http://"
+
query
.
hostname
+
":"
+
srs_get_api_server_port
()
+
"/api/v1/chats"
;
refresh
();
});
function
update_play_url
()
{
var
url
=
$
(
"#txt_url"
).
val
();
var
ret
=
srs_parse_rtmp_url
(
url
);
var
query
=
parse_query_string
();
var
srs_player_url
=
"http://"
+
query
.
host
+
query
.
dir
+
"/srs_player.html?"
;
srs_player_url
+=
"vhost="
+
srs_get_player_publish_vhost
(
ret
.
vhost
)
+
"&port="
+
ret
.
port
+
"&app="
+
ret
.
app
+
"&stream="
+
ret
.
stream
;
srs_player_url
+=
"&autostart=true"
;
var
srs_player_rt_url
=
"http://"
+
query
.
host
+
query
.
dir
+
"/srs_player.html?"
;
srs_player_rt_url
+=
"vhost="
+
ret
.
vhost
+
"&port="
+
ret
.
port
+
"&app="
+
ret
.
app
+
"&stream="
+
ret
.
stream
;
srs_player_rt_url
+=
"&autostart=true"
;
var
jwplayer_url
=
"http://"
+
query
.
host
+
query
.
dir
+
"/jwplayer6.html?"
;
jwplayer_url
+=
"vhost="
+
srs_get_player_publish_vhost
(
ret
.
vhost
)
+
"&port="
+
ret
.
port
+
"&app="
+
ret
.
app
+
"&stream="
+
ret
.
stream
;
jwplayer_url
+=
"&hls_autostart=true"
;
var
hls_url
=
"http://"
+
ret
.
server
+
":"
+
query
.
http_port
+
"/"
+
ret
.
app
+
"/"
+
ret
.
stream
+
".m3u8"
;
function
refresh
()
{
if
(
!
self_chat
)
{
setTimeout
(
refresh
,
1000
);
return
;
}
$
(
"#txt_play_realtime"
).
text
(
"RTMP低延时(点击打开)"
).
attr
(
"href"
,
srs_player_rt_url
).
attr
(
"target"
,
"_blank"
);
$
(
"#txt_play_url"
).
text
(
"RTMP已转码(点击打开)"
).
attr
(
"href"
,
srs_player_url
).
attr
(
"target"
,
"_blank"
);
$
(
"#txt_play_hls"
).
text
(
"HLS-m3u8(点击打开或右键复制)"
).
attr
(
"href"
,
hls_url
).
attr
(
"target"
,
"_blank"
);
$
(
"#txt_play_jwplayer"
).
text
(
"HLS-JWPlayer(点击打开)"
).
attr
(
"href"
,
jwplayer_url
).
attr
(
"target"
,
"_blank"
);
$
.
ajax
({
type
:
"GET"
,
async
:
true
,
url
:
api_server
,
contentType
:
"text/html"
,
data
:
""
,
dataType
:
"json"
,
complete
:
function
()
{
},
error
:
function
(
ret
)
{
setTimeout
(
refresh
,
5000
);
warn
(
101
,
"查询会议室失败:"
+
JSON
.
stringify
(
ret
));
},
success
:
function
(
ret
)
{
if
(
0
!=
ret
[
"code"
])
{
warn
(
102
,
"查询会议室失败: "
+
JSON
.
stringify
(
ret
));
setTimeout
(
refresh
,
5000
);
return
;
}
var
chats
=
ret
[
"data"
][
"chats"
];
var
server_time
=
ret
[
"now"
];
on_get_chats
(
chats
);
setTimeout
(
refresh
,
5000
);
}
});
}
function
on_user_publish
()
{
if
(
$
(
"#btn_publish"
).
text
()
==
"停止发布"
)
{
srs_publisher
.
stop
();
$
(
"#btn_publish"
).
text
(
"发布视频"
);
$
(
"#txt_play_realtime"
).
text
(
"RTMP低延时(请发布视频)"
).
attr
(
"href"
,
"#"
).
attr
(
"target"
,
"_self"
);
$
(
"#txt_play_url"
).
text
(
"RTMP已转码(请发布视频)"
).
attr
(
"href"
,
"#"
).
attr
(
"target"
,
"_self"
);
$
(
"#txt_play_hls"
).
text
(
"HLS-m3u8(请发布视频)"
).
attr
(
"href"
,
"#"
).
attr
(
"target"
,
"_self"
);
$
(
"#txt_play_jwplayer"
).
text
(
"HLS-JWPlayer(请发布视频)"
).
attr
(
"href"
,
"#"
).
attr
(
"target"
,
"_self"
);
function
on_get_chats
(
chats
)
{
if
(
!
self_chat
)
{
return
;
}
// get self, check self is valid?
var
_self_chat
=
null
;
for
(
var
i
=
0
;
i
<
chats
.
length
;
i
++
)
{
var
chat
=
chats
[
i
];
if
(
self_chat
&&
self_chat
.
id
==
chat
.
id
)
{
_self_chat
=
chat
;
break
;
}
}
// rejoin if invalid.
if
(
!
_self_chat
)
{
on_user_exit_chat
(
function
(){
on_user_join_chat
(
function
(){
info
(
"重新加入会议室成功"
);
});
});
return
;
}
$
(
"#btn_publish"
).
text
(
"停止发布"
);
render_chat_room
(
chats
);
update_play_url
();
if
(
!
self_chat
)
{
return
;
}
var
url
=
$
(
"#txt_url"
).
val
();
var
vcodec
=
{};
var
acodec
=
{};
// update self heartbeat.
var
url
=
api_server
+
"/"
+
self_chat
.
id
;
acodec
.
device_code
=
$
(
"#sl_microphones"
).
val
();
acodec
.
device_name
=
$
(
"#sl_microphones"
).
text
();
var
chat
=
{};
chat
.
localtime
=
new
Date
().
getTime
();
vcodec
.
device_code
=
$
(
"#sl_cameras"
).
find
(
"option:selected"
).
val
();
vcodec
.
device_name
=
$
(
"#sl_cameras"
).
find
(
"option:selected"
).
text
();
// publish to api server to requires an id.
$
.
ajax
({
type
:
"PUT"
,
async
:
true
,
url
:
url
,
contentType
:
"text/html"
,
data
:
JSON
.
stringify
(
chat
),
dataType
:
"json"
,
complete
:
function
()
{
},
error
:
function
(
ret
)
{
warn
(
105
,
"更新会议室信息失败:"
+
JSON
.
stringify
(
ret
));
},
success
:
function
(
ret
)
{
if
(
0
!=
ret
[
"code"
])
{
warn
(
106
,
"更新会议室信息失败:: "
+
JSON
.
stringify
(
ret
));
return
;
}
}
});
}
function
render_chat_room
(
chats
)
{
if
(
!
self_chat
)
{
return
;
}
vcodec
.
codec
=
$
(
"#sl_vcodec"
).
find
(
"option:selected"
).
val
();
vcodec
.
profile
=
$
(
"#sl_profile"
).
find
(
"option:selected"
).
val
();
vcodec
.
level
=
$
(
"#sl_level"
).
find
(
"option:selected"
).
val
();
vcodec
.
fps
=
$
(
"#sl_fps"
).
find
(
"option:selected"
).
val
();
vcodec
.
gop
=
$
(
"#sl_gop"
).
find
(
"option:selected"
).
val
();
vcodec
.
size
=
$
(
"#sl_size"
).
find
(
"option:selected"
).
val
();
vcodec
.
bitrate
=
$
(
"#sl_bitrate"
).
find
(
"option:selected"
).
val
();
// new added chat
for
(
var
i
=
0
;
i
<
chats
.
length
;
i
++
)
{
var
chat
=
chats
[
i
];
// ignore the self.
if
(
self_chat
&&
self_chat
.
id
==
chat
.
id
)
{
continue
;
}
// if previous exists, ignore, only add new here.
var
previous_chat
=
get_previous_chat_user
(
previous_chats
,
chat
.
id
);
if
(
previous_chat
)
{
chat
.
player
=
previous_chat
.
player
;
continue
;
}
global_chat_user_id
++
;
// username: a str indicates the user name.
// url: a str indicates the url of user stream.
// join_date: a str indicates the join timestamp in seconds.
// join_date_str: friendly formated time.
var
obj
=
$
(
"<div/>"
).
html
(
$
(
"#template"
).
html
());
$
(
obj
).
attr
(
"chat_id"
,
chat
.
id
);
$
(
obj
).
attr
(
"id"
,
"div_"
+
chat
.
id
);
// for specifed chat: $("#div_" + chat_id)
$
(
obj
).
attr
(
"class"
,
"div_chat"
);
// for all chats: $(".div_chat")
$
(
obj
).
find
(
"#realtime_player"
).
attr
(
"id"
,
"rp_"
+
chat
.
id
);
// for specifed player: $("#rp_" + chat_id)
$
(
obj
).
find
(
"#realtime_player_raw"
).
attr
(
"id"
,
"rp_raw_"
+
chat
.
id
);
// for specifed player: $("#rp_raw_" + chat_id)
$
(
obj
).
find
(
"#user_name"
).
text
(
chat
.
username
);
$
(
obj
).
find
(
"#join_date"
).
text
(
chat
.
join_date_str
);
$
(
obj
).
find
(
"#collapseM"
).
attr
(
"id"
,
"collapse_"
+
global_chat_user_id
);
$
(
obj
).
find
(
"#headerN"
).
attr
(
"href"
,
"#collapse_"
+
global_chat_user_id
);
$
(
"#lst_chats"
).
append
(
obj
);
info
(
"开始推流到服务器"
);
srs_publisher
.
publish
(
url
,
vcodec
,
acodec
);
if
(
!
no_play
)
{
// start the realtime player.
var
_player
=
new
SrsPlayer
(
"rp_raw_"
+
chat
.
id
,
600
,
300
);
_player
.
on_player_ready
=
function
()
{
this
.
set_bt
(
0.8
);
this
.
set_fs
(
"screen"
,
100
);
};
_player
.
start
(
chat
.
url
);
chat
.
player
=
_player
;
}
else
{
chat
.
player
=
null
;
}
$
(
obj
).
find
(
"#collapse_main"
).
on
(
'hidden'
,
function
(){
var
id
=
$
(
this
).
parent
().
attr
(
"chat_id"
);
var
chat
=
get_previous_chat_user
(
previous_chats
,
id
);
if
(
!
chat
||
!
chat
.
player
)
{
return
;
}
chat
.
player
.
stop
();
});
$
(
obj
).
find
(
"#collapse_main"
).
on
(
'shown'
,
function
(){
var
id
=
$
(
this
).
parent
().
attr
(
"chat_id"
);
var
chat
=
get_previous_chat_user
(
previous_chats
,
id
);
if
(
!
chat
||
!
chat
.
player
)
{
return
;
}
chat
.
player
.
play
();
});
}
if
(
realtime_player
)
{
// directly play the url for the realtime player.
realtime_player
.
stop
();
realtime_player
.
play
(
url
);
// removed chat
for
(
var
i
=
0
;
i
<
previous_chats
.
length
;
i
++
)
{
var
chat
=
previous_chats
[
i
];
// ignore the self.
if
(
self_chat
&&
self_chat
.
id
==
chat
.
id
)
{
continue
;
}
var
new_chat
=
get_previous_chat_user
(
chats
,
chat
.
id
);
if
(
new_chat
)
{
continue
;
}
if
(
chat
.
player
)
{
chat
.
player
.
stop
();
}
$
(
"#div_"
+
chat
.
id
).
remove
();
}
if
(
remote_player
)
{
// the normal player should play the transcoded stream in another vhost.
// for example, publish stream to vhost players,
// the realtime player play the vhost players, which may donot support HLS,
// the normal player play the vhost players_pub, which transcoded to h264/aac with HLS.
var
ret
=
srs_parse_rtmp_url
(
url
);
var
pub_url
=
"rtmp://"
+
ret
.
server
+
":"
+
ret
.
port
+
"/"
+
ret
.
app
;
pub_url
+=
"?vhost="
+
srs_get_player_publish_vhost
(
ret
.
vhost
)
+
"/"
+
ret
.
stream
;
remote_player
.
stop
();
remote_player
.
play
(
pub_url
);
previous_chats
=
chats
;
}
function
get_previous_chat_user
(
arr
,
id
)
{
for
(
var
i
=
0
;
i
<
arr
.
length
;
i
++
)
{
var
chat
=
arr
[
i
];
if
(
id
==
chat
.
id
)
{
return
chat
;
}
}
return
null
;
}
function
info
(
desc
)
{
$
(
"#txt_log"
).
addClass
(
"alert-info"
).
removeClass
(
"alert-error"
).
removeClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Info:"
);
$
(
"#txt_log_msg"
).
text
(
desc
);
function
on_user_publish
()
{
if
(
$
(
"#txt_name"
).
val
().
trim
()
==
""
)
{
$
(
"#txt_name"
).
focus
().
parent
().
parent
().
addClass
(
"error"
);
warn
(
100
,
"请输入您的名字"
);
return
;
}
$
(
"#txt_name"
).
parent
().
parent
().
removeClass
(
"error"
);
// join chat.
if
(
!
self_chat
)
{
on_user_join_chat
();
}
else
{
on_user_exit_chat
();
}
}
function
warn
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
removeClass
(
"alert-error"
).
addClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Warn:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
function
on_user_exit_chat
(
complete_pfn
)
{
srs_publisher
.
stop
();
$
(
"#btn_join"
).
text
(
"加入会议"
);
if
(
!
self_chat
)
{
return
;
}
// removed chat
for
(
var
i
=
0
;
i
<
previous_chats
.
length
;
i
++
)
{
var
chat
=
previous_chats
[
i
];
// ignore the self.
if
(
self_chat
&&
self_chat
.
id
==
chat
.
id
)
{
continue
;
}
if
(
chat
.
player
)
{
chat
.
player
.
stop
();
}
$
(
"#div_"
+
chat
.
id
).
remove
();
}
previous_chats
=
[];
var
url
=
api_server
+
"/"
+
self_chat
.
id
;
// whatever, cleanup local chat.
self_chat
=
null
;
$
(
"#btn_join"
).
attr
(
"disabled"
,
true
);
// publish to api server to requires an id.
$
.
ajax
({
type
:
"DELETE"
,
async
:
true
,
url
:
url
,
contentType
:
"text/html"
,
data
:
""
,
dataType
:
"json"
,
complete
:
function
()
{
$
(
"#btn_join"
).
attr
(
"disabled"
,
false
);
if
(
complete_pfn
)
{
complete_pfn
();
}
},
error
:
function
(
ret
)
{
warn
(
103
,
"退出会议室失败"
);
},
success
:
function
(
ret
)
{
if
(
0
!=
ret
[
"code"
])
{
warn
(
104
,
"退出会议室失败"
);
return
;
}
info
(
"退出会议室成功"
);
}
});
}
function
error
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
addClass
(
"alert-error"
).
removeClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Error:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
function
on_user_join_chat
(
complete_pfn
)
{
if
(
self_chat
)
{
return
;
}
var
url
=
$
(
"#txt_url"
).
val
();
var
vcodec
=
{};
var
acodec
=
{};
srs_publiser_get_codec
(
vcodec
,
acodec
,
"#sl_cameras"
,
"#sl_microphones"
,
"#sl_vcodec"
,
"#sl_profile"
,
"#sl_level"
,
"#sl_gop"
,
"#sl_size"
,
"#sl_fps"
,
"#sl_bitrate"
);
var
chat
=
{};
chat
.
id
=
-
1
;
chat
.
username
=
$
(
"#txt_name"
).
val
().
trim
();
chat
.
agent
=
navigator
.
userAgent
;
chat
.
url
=
url
;
chat
.
vcodec
=
vcodec
;
chat
.
acodec
=
acodec
;
$
(
"#btn_join"
).
attr
(
"disabled"
,
true
);
// publish to api server to requires an id.
$
.
ajax
({
type
:
"POST"
,
async
:
true
,
url
:
api_server
,
contentType
:
"text/html"
,
data
:
JSON
.
stringify
(
chat
),
dataType
:
"json"
,
complete
:
function
()
{
$
(
"#btn_join"
).
attr
(
"disabled"
,
false
);
if
(
complete_pfn
)
{
complete_pfn
();
}
},
error
:
function
(
ret
)
{
warn
(
105
,
"创建会议室失败:"
+
JSON
.
stringify
(
ret
));
},
success
:
function
(
ret
)
{
if
(
0
!=
ret
[
"code"
])
{
warn
(
106
,
"创建会议室失败: "
+
JSON
.
stringify
(
ret
));
return
;
}
chat
.
id
=
ret
[
"data"
];
// success, start publish.
self_chat
=
chat
;
$
(
"#btn_join"
).
text
(
"退出会议"
);
info
(
"开始推流到服务器"
);
srs_publisher
.
publish
(
url
,
vcodec
,
acodec
);
if
(
realtime_player
)
{
// directly play the url for the realtime player.
realtime_player
.
stop
();
realtime_player
.
play
(
url
);
}
}
});
}
</script>
</head>
...
...
@@ -257,33 +429,83 @@
</div>
</div>
<div
class=
"container"
>
<!-- for the log -->
<div
class=
"alert alert-info fade in"
id=
"txt_log"
>
<button
type=
"button"
class=
"close"
data-dismiss=
"alert"
>
×
</button>
<strong><span
id=
"txt_log_title"
>
Usage:
</span></strong>
<span
id=
"txt_log_msg"
>
创建会议室,或者
加入会议室
</span>
<span
id=
"txt_log_msg"
>
输入名字,设置编码参数后,
加入会议室
</span>
</div>
<div
class=
"control-group"
>
<div
class=
"form-inline"
>
<button
class=
"btn"
id=
"btn_create_chat"
>
创建会议室
</button>
<button
class=
"btn"
id=
"btn_join_chat"
>
加入会议室
</button>
<input
type=
"text"
id=
"txt_name"
class=
"input-small"
placeholder=
"您的名字..."
value=
""
></input>
<button
class=
"btn input-medium"
id=
"btn_video_settings"
>
视频编码配置
</button>
<button
class=
"btn input-medium"
id=
"btn_audio_settings"
>
音频编码配置
</button>
<button
class=
"btn input-medium btn-primary"
id=
"btn_join"
>
加入会议
</button>
<input
type=
"text"
id=
"txt_url"
class=
"input-mini hide"
value=
""
></input>
</div>
</div>
<div
class=
"control-group"
>
<div
class=
"form-inline"
>
发布地址:
<input
type=
"text"
id=
"txt_url"
class=
"input-xxlarge"
value=
""
></input>
<button
class=
"btn btn-primary"
id=
"btn_publish"
>
发布视频
</button>
<div
class=
"container"
>
<div
class=
"row-fluid"
>
<div
class=
"span6"
>
<div
class=
"accordion-group"
>
<div
class=
"accordion-heading"
>
<span
class=
"accordion-toggle"
data-toggle=
"collapse"
href=
"#collapseN"
>
<strong>
[我的] 本地摄像头
</strong>
</span>
</div>
<div
id=
"collapseM"
class=
"accordion-body collapse in"
>
<div
class=
"accordion-inner"
>
<div
id=
"local_publisher"
></div>
</div>
</div>
</div>
</div>
<div
class=
"span6"
>
<div
class=
"accordion-group"
>
<div
class=
"accordion-heading"
>
<span
class=
"accordion-toggle"
data-toggle=
"collapse"
href=
"#collapseN"
>
<strong>
[我的] 远程服务器流
</strong>
</span>
</div>
<div
id=
"collapseM"
class=
"accordion-body collapse in"
>
<div
class=
"accordion-inner"
>
<div
id=
"realtime_player"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"control-group"
>
<div
class=
"form-inline"
>
播放地址
1.
<a
id=
"txt_play_realtime"
class=
"input-xxlarge"
href=
"#"
>
RTMP低延时(请发布视频)
</a>
2.
<a
id=
"txt_play_url"
class=
"input-xxlarge"
href=
"#"
>
RTMP已转码(请发布视频)
</a>
3.
<a
id=
"txt_play_hls"
class=
"input-xxlarge"
href=
"#"
>
HLS-m3u8(请发布视频)
</a>
4.
<a
id=
"txt_play_jwplayer"
class=
"input-xxlarge"
href=
"#"
>
HLS-JWPlayer(请发布视频)
</a>
<div
class=
"container hide"
id=
"template"
>
<div
class=
"accordion-group"
id=
"collapse_main"
>
<div
class=
"accordion-heading"
title=
"点击展开或收起,收起后停止播放流,展开时从服务器请求流"
>
<span
id=
"headerN"
class=
"accordion-toggle"
data-toggle=
"collapse"
href=
"#collapseN"
>
<strong>
[
<a
href=
"#"
><span
id=
"user_name"
>
XX
</span></a>
]
</strong>
<strong>
加入时间
</strong>
[
<span
id=
"join_date"
></span>
]
<img
src=
"img/tooltip.png"
/>
</span>
</div>
<div
id=
"collapseM"
class=
"accordion-body collapse"
>
<div
class=
"accordion-inner"
>
<div
class=
"row-fluid"
>
<div
class=
"span2"
>
</div>
<div
class=
"span8"
>
<div
id=
"realtime_player"
>
<div
id=
"realtime_player_raw"
>
</div>
</div>
</div>
<div
class=
"span2"
>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"container"
id=
"lst_chats"
>
</div>
<div
id=
"video_modal"
class=
"modal hide fade"
>
<div
class=
"modal-header"
>
<button
type=
"button"
class=
"close"
data-dismiss=
"modal"
aria-hidden=
"true"
>
×
</button>
...
...
@@ -409,64 +631,7 @@
<button
class=
"btn btn-primary"
data-dismiss=
"modal"
aria-hidden=
"true"
>
设置
</button>
</div>
</div>
<div
class=
"container"
>
<div
class=
"row-fluid"
>
<div
class=
"span6"
>
<div
class=
"accordion-group"
>
<div
class=
"accordion-heading"
>
<span
class=
"accordion-toggle"
data-toggle=
"collapse"
href=
"#collapse1"
>
<strong>
本地摄像头
</strong>
</span>
</div>
<div
id=
"collapse1"
class=
"accordion-body collapse in"
>
<div
class=
"accordion-inner"
>
<div
id=
"local_publisher"
></div>
</div>
</div>
</div>
</div>
<div
class=
"span6"
>
<div
class=
"accordion-group"
>
<div
class=
"accordion-heading"
>
<span
class=
"accordion-toggle"
data-toggle=
"collapse"
href=
"#collapse2"
>
<strong>
远程服务器
</strong>
<a
id=
"remote_tips"
href=
"#"
data-toggle=
"tooltip"
data-placement=
"top"
title=
""
>
黑屏
<img
src=
"img/tooltip.png"
/>
</a>
</span>
</div>
<div
id=
"collapse2"
class=
"accordion-body collapse in"
>
<div
class=
"accordion-inner"
>
<div
id=
"remote_player"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"container"
>
<div
class=
"row-fluid"
>
<div
class=
"span6"
>
<div
class=
"accordion-group"
>
<div
class=
"accordion-heading"
>
<span
class=
"accordion-toggle"
data-toggle=
"collapse"
href=
"#collapse3"
>
<strong>
远程服务器
</strong>
<a
id=
"low_latecy_tips"
href=
"#"
data-toggle=
"tooltip"
data-placement=
"top"
title=
""
>
低延时
<img
src=
"img/tooltip.png"
/>
</a>
</span>
</div>
<div
id=
"collapse3"
class=
"accordion-body collapse in"
>
<div
class=
"accordion-inner"
>
<div
id=
"realtime_player"
></div>
</div>
</div>
</div>
</div>
<div
class=
"span6"
>
</div>
</div>
</div>
<hr/>
<footer>
<p><a
href=
"https://github.com/winlinvip/simple-rtmp-server"
>
SRS Team
©
2013
</a></p>
</footer>
...
...
trunk/research/players/srs_publisher.html
查看文件 @
6875b6f
...
...
@@ -46,74 +46,12 @@
// start the publisher.
srs_publisher
=
new
SrsPublisher
(
"local_publisher"
,
430
,
185
);
srs_publisher
.
on_publisher_ready
=
function
(
cameras
,
microphones
)
{
$
(
"#sl_cameras"
).
empty
();
for
(
var
i
=
0
;
i
<
cameras
.
length
;
i
++
)
{
$
(
"#sl_cameras"
).
append
(
"<option value='"
+
i
+
"'>"
+
cameras
[
i
]
+
"</option"
);
}
// optional: select the first no "virtual" signed.
for
(
var
i
=
0
;
i
<
cameras
.
length
;
i
++
)
{
if
(
cameras
[
i
].
toLowerCase
().
indexOf
(
"virtual"
)
==
-
1
)
{
$
(
"#sl_cameras option[value='"
+
i
+
"']"
).
attr
(
"selected"
,
true
);
break
;
}
}
$
(
"#sl_microphones"
).
empty
();
for
(
var
i
=
0
;
i
<
microphones
.
length
;
i
++
)
{
$
(
"#sl_microphones"
).
append
(
"<option value='"
+
i
+
"'>"
+
microphones
[
i
]
+
"</option"
);
}
$
(
"#sl_vcodec"
).
empty
();
var
vcodecs
=
[
"h264"
,
"vp6"
];
for
(
var
i
=
0
;
i
<
vcodecs
.
length
;
i
++
)
{
$
(
"#sl_vcodec"
).
append
(
"<option value='"
+
vcodecs
[
i
]
+
"'>"
+
vcodecs
[
i
]
+
"</option"
);
}
$
(
"#sl_profile"
).
empty
();
var
profiles
=
[
"baseline"
,
"main"
];
for
(
var
i
=
0
;
i
<
profiles
.
length
;
i
++
)
{
$
(
"#sl_profile"
).
append
(
"<option value='"
+
profiles
[
i
]
+
"'>"
+
profiles
[
i
]
+
"</option"
);
}
$
(
"#sl_level"
).
empty
();
var
levels
=
[
"1"
,
"1b"
,
"1.1"
,
"1.2"
,
"1.3"
,
"2"
,
"2.1"
,
"2.2"
,
"3"
,
"3.1"
,
"3.2"
,
"4"
,
"4.1"
,
"4.2"
,
"5"
,
"5.1"
];
for
(
var
i
=
0
;
i
<
levels
.
length
;
i
++
)
{
$
(
"#sl_level"
).
append
(
"<option value='"
+
levels
[
i
]
+
"'>"
+
levels
[
i
]
+
"</option"
);
}
$
(
"#sl_level option[value='4.1']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_gop"
).
empty
();
var
gops
=
[
"0.3"
,
"0.5"
,
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
,
"9"
,
"10"
,
"15"
,
"20"
];
for
(
var
i
=
0
;
i
<
gops
.
length
;
i
++
)
{
$
(
"#sl_gop"
).
append
(
"<option value='"
+
gops
[
i
]
+
"'>"
+
gops
[
i
]
+
"秒</option"
);
}
$
(
"#sl_gop option[value='5']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_size"
).
empty
();
var
sizes
=
[
"176x144"
,
"320x240"
,
"352x240"
,
"352x288"
,
"460x240"
,
"640x480"
,
"720x480"
,
"720x576"
,
"800x600"
,
"1024x768"
,
"1280x720"
,
"1360x768"
,
"1920x1080"
];
for
(
i
=
0
;
i
<
sizes
.
length
;
i
++
)
{
$
(
"#sl_size"
).
append
(
"<option value='"
+
sizes
[
i
]
+
"'>"
+
sizes
[
i
]
+
"</option"
);
}
$
(
"#sl_size option[value='460x240']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_fps"
).
empty
();
var
fpses
=
[
"5"
,
"10"
,
"15"
,
"20"
,
"24"
,
"25"
,
"29.97"
,
"30"
];
for
(
i
=
0
;
i
<
fpses
.
length
;
i
++
)
{
$
(
"#sl_fps"
).
append
(
"<option value='"
+
fpses
[
i
]
+
"'>"
+
Number
(
fpses
[
i
]).
toFixed
(
2
)
+
" 帧/秒</option"
);
}
$
(
"#sl_fps option[value='15']"
).
attr
(
"selected"
,
true
);
$
(
"#sl_bitrate"
).
empty
();
var
bitrates
=
[
"50"
,
"200"
,
"350"
,
"500"
,
"650"
,
"800"
,
"950"
,
"1000"
,
"1200"
,
"1500"
,
"1800"
,
"2000"
,
"3000"
,
"5000"
];
for
(
i
=
0
;
i
<
bitrates
.
length
;
i
++
)
{
$
(
"#sl_bitrate"
).
append
(
"<option value='"
+
bitrates
[
i
]
+
"'>"
+
bitrates
[
i
]
+
" kbps</option"
);
}
$
(
"#sl_bitrate option[value='350']"
).
attr
(
"selected"
,
true
);
srs_publisher_initialize_page
(
cameras
,
microphones
,
"#sl_cameras"
,
"#sl_microphones"
,
"#sl_vcodec"
,
"#sl_profile"
,
"#sl_level"
,
"#sl_gop"
,
"#sl_size"
,
"#sl_fps"
,
"#sl_bitrate"
);
};
srs_publisher
.
on_publisher_error
=
function
(
code
,
desc
)
{
error
(
code
,
desc
);
...
...
@@ -194,20 +132,12 @@
var
url
=
$
(
"#txt_url"
).
val
();
var
vcodec
=
{};
var
acodec
=
{};
acodec
.
device_code
=
$
(
"#sl_microphones"
).
val
();
acodec
.
device_name
=
$
(
"#sl_microphones"
).
text
();
vcodec
.
device_code
=
$
(
"#sl_cameras"
).
find
(
"option:selected"
).
val
();
vcodec
.
device_name
=
$
(
"#sl_cameras"
).
find
(
"option:selected"
).
text
();
vcodec
.
codec
=
$
(
"#sl_vcodec"
).
find
(
"option:selected"
).
val
();
vcodec
.
profile
=
$
(
"#sl_profile"
).
find
(
"option:selected"
).
val
();
vcodec
.
level
=
$
(
"#sl_level"
).
find
(
"option:selected"
).
val
();
vcodec
.
fps
=
$
(
"#sl_fps"
).
find
(
"option:selected"
).
val
();
vcodec
.
gop
=
$
(
"#sl_gop"
).
find
(
"option:selected"
).
val
();
vcodec
.
size
=
$
(
"#sl_size"
).
find
(
"option:selected"
).
val
();
vcodec
.
bitrate
=
$
(
"#sl_bitrate"
).
find
(
"option:selected"
).
val
();
srs_publiser_get_codec
(
vcodec
,
acodec
,
"#sl_cameras"
,
"#sl_microphones"
,
"#sl_vcodec"
,
"#sl_profile"
,
"#sl_level"
,
"#sl_gop"
,
"#sl_size"
,
"#sl_fps"
,
"#sl_bitrate"
);
info
(
"开始推流到服务器"
);
srs_publisher
.
publish
(
url
,
vcodec
,
acodec
);
...
...
@@ -230,22 +160,6 @@
remote_player
.
play
(
pub_url
);
}
}
function
info
(
desc
)
{
$
(
"#txt_log"
).
addClass
(
"alert-info"
).
removeClass
(
"alert-error"
).
removeClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Info:"
);
$
(
"#txt_log_msg"
).
text
(
desc
);
}
function
warn
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
removeClass
(
"alert-error"
).
addClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Warn:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
}
function
error
(
code
,
desc
)
{
$
(
"#txt_log"
).
removeClass
(
"alert-info"
).
addClass
(
"alert-error"
).
removeClass
(
"alert-warn"
);
$
(
"#txt_log_title"
).
text
(
"Error:"
);
$
(
"#txt_log_msg"
).
text
(
"code: "
+
code
+
", "
+
desc
);
}
</script>
</head>
<body>
...
...
请
注册
或
登录
后发表评论