winlin

fix the bitrate bug(in Bps), use enhanced microphone.

... ... @@ -276,6 +276,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
* nginx v1.5.0: 139524 lines <br/>
### History
* v0.9, 2013-12-25, fix the bitrate bug(in Bps), use enhanced microphone.
* v0.9, 2013-12-22, demo video meeting or chat(srs+cherrypy+jquery+bootstrap).
* v0.9, 2013-12-22, merge from wenjie, support banwidth test.
* v0.9, 2013-12-22, merge from wenjie: support set chunk size at vhost level
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...
... ... @@ -53,31 +53,6 @@ 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(){
... ... @@ -247,10 +222,8 @@ function srs_init_publish(rtmp_url) {
}
}
/**
* when publisher ready, init the page elements.
*/
function srs_publisher_initialize_page(
// without default values set.
function srs_initialize_codec_page(
cameras, microphones,
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate
) {
... ... @@ -265,14 +238,36 @@ function srs_publisher_initialize_page(
break;
}
}
// optional: select the first "integrated" signed.
for (var i = 0; i < cameras.length; i++) {
if (cameras[i].toLowerCase().indexOf("integrated") >= 0) {
$(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");
}
// optional: select the first no "default" signed.
for (var i = 0; i < microphones.length; i++) {
if (microphones[i].toLowerCase().indexOf("default") == -1) {
$(sl_microphones + " option[value='" + i + "']").attr("selected", true);
break;
}
}
// optional: select the first "realtek" signed.
for (var i = 0; i < microphones.length; i++) {
if (microphones[i].toLowerCase().indexOf("realtek") >= 0) {
$(sl_microphones + " option[value='" + i + "']").attr("selected", true);
break;
}
}
$(sl_vcodec).empty();
var vcodecs = ["h264", "vp6"];
vcodecs = ["h264"]; // h264 only.
for (var i = 0; i < vcodecs.length; i++) {
$(sl_vcodec).append("<option value='" + vcodecs[i] + "'>" + vcodecs[i] + "</option");
}
... ... @@ -282,7 +277,6 @@ function srs_publisher_initialize_page(
for (var i = 0; i < profiles.length; i++) {
$(sl_profile).append("<option value='" + profiles[i] + "'>" + profiles[i] + "</option");
}
$(sl_profile + " option[value='main']").attr("selected", true);
$(sl_level).empty();
var levels = ["1", "1b", "1.1", "1.2", "1.3",
... ... @@ -290,7 +284,6 @@ function srs_publisher_initialize_page(
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",
... ... @@ -298,7 +291,6 @@ function srs_publisher_initialize_page(
for (var i = 0; i < gops.length; i++) {
$(sl_gop).append("<option value='" + gops[i] + "'>" + gops[i] + "秒</option");
}
$(sl_gop + " option[value='10']").attr("selected", true);
$(sl_size).empty();
var sizes = ["176x144", "320x240", "352x240",
... ... @@ -307,14 +299,12 @@ function srs_publisher_initialize_page(
for (i = 0; i < sizes.length; i++) {
$(sl_size).append("<option value='" + sizes[i] + "'>" + sizes[i] + "</option");
}
$(sl_size + " option[value='640x480']").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='20']").attr("selected", true);
$(sl_bitrate).empty();
var bitrates = ["50", "200", "350", "500", "650", "800",
... ... @@ -322,6 +312,40 @@ function srs_publisher_initialize_page(
for (i = 0; i < bitrates.length; i++) {
$(sl_bitrate).append("<option value='" + bitrates[i] + "'>" + bitrates[i] + " kbps</option");
}
}
/**
* 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
) {
srs_initialize_codec_page(
cameras, microphones,
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate
);
//var profiles = ["baseline", "main"];
$(sl_profile + " option[value='main']").attr("selected", true);
//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"];
$(sl_level + " option[value='4.1']").attr("selected", true);
//var gops = ["0.3", "0.5", "1", "2", "3", "4",
// "5", "6", "7", "8", "9", "10", "15", "20"];
$(sl_gop + " option[value='10']").attr("selected", true);
//var sizes = ["176x144", "320x240", "352x240",
// "352x288", "460x240", "640x480", "720x480", "720x576", "800x600",
// "1024x768", "1280x720", "1360x768", "1920x1080"];
$(sl_size + " option[value='640x480']").attr("selected", true);
//var fpses = ["5", "10", "15", "20", "24", "25", "29.97", "30"];
$(sl_fps + " option[value='20']").attr("selected", true);
//var bitrates = ["50", "200", "350", "500", "650", "800",
// "950", "1000", "1200", "1500", "1800", "2000", "3000", "5000"];
$(sl_bitrate + " option[value='500']").attr("selected", true);
}
/**
... ... @@ -331,75 +355,33 @@ function srs_chat_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");
}
srs_initialize_codec_page(
cameras, microphones,
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate
);
$(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");
}
//var profiles = ["baseline", "main"];
$(sl_profile + " option[value='baseline']").attr("selected", true);
$(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='3.1']").attr("selected", true);
//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"];
$(sl_level + " option[value='2.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");
}
//var gops = ["0.3", "0.5", "1", "2", "3", "4",
// "5", "6", "7", "8", "9", "10", "15", "20"];
$(sl_gop + " option[value='0.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);
//var sizes = ["176x144", "320x240", "352x240",
// "352x288", "460x240", "640x480", "720x480", "720x576", "800x600",
// "1024x768", "1280x720", "1360x768", "1920x1080"];
$(sl_size + " option[value='320x240']").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);
//var fpses = ["5", "10", "15", "20", "24", "25", "29.97", "30"];
$(sl_fps + " option[value='10']").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);
//var bitrates = ["50", "200", "350", "500", "650", "800",
// "950", "1000", "1200", "1500", "1800", "2000", "3000", "5000"];
$(sl_bitrate + " option[value='200']").attr("selected", true);
}
/**
* get the vcodec and acodec.
... ... @@ -451,6 +433,7 @@ function SrsPlayer(container, width, height, private_object) {
this.id = SrsPlayer.__id++;
this.stream_url = null;
this.buffer_time = 0.8; // default to 0.8
this.volume = 1.0; // default to 100%
this.callbackObj = null;
// callback set the following values.
... ... @@ -502,12 +485,19 @@ SrsPlayer.prototype.start = function(url) {
/**
* play the stream.
* @param stream_url the url of stream, rtmp or http.
* @param volume the volume, 0 is mute, 1 is 100%, 2 is 200%.
*/
SrsPlayer.prototype.play = function(url) {
SrsPlayer.prototype.play = function(url, volume) {
if (url) {
this.stream_url = url;
}
this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time);
// volume maybe 0, so never use if(volume) to check its value.
if (volume != null && volume != undefined) {
this.volume = volume;
}
this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time, this.volume);
}
SrsPlayer.prototype.stop = function() {
for (var i = 0; i < SrsPlayer.__players.length; i++) {
... ... @@ -652,7 +642,7 @@ function SrsPublisher(container, width, height, private_object) {
this.errors = {
"100": "无法获取指定的摄像头", //error_camera_get
"101": "无法获取指定的麦克风", //error_microphone_get
"102": "摄像头为禁用状态,推流时请允许flash访问摄像头", //error_camera_muted
"102": "摄像头为禁用状态,推流时请允许flash访问摄像头" //error_camera_muted
};
}
/**
... ...
/**
* 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">标题:</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);
}
... ...
... ... @@ -7,6 +7,7 @@
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ... @@ -420,7 +421,7 @@
if (realtime_player) {
// directly play the url for the realtime player.
realtime_player.stop();
realtime_player.play(url);
realtime_player.play(url, 0);
}
}
});
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...
... ... @@ -10,6 +10,7 @@ package
import flash.events.NetStatusEvent;
import flash.events.TimerEvent;
import flash.external.ExternalInterface;
import flash.media.SoundTransform;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
... ... @@ -19,6 +20,8 @@ package
import flash.utils.Timer;
import flash.utils.setTimeout;
import flashx.textLayout.formats.Float;
public class srs_player extends Sprite
{
// user set id.
... ... @@ -280,8 +283,9 @@ package
* @param _width, the player width.
* @param _height, the player height.
* @param buffer_time, the buffer time in seconds. recommend to >=0.5
* @param volume, the volume, 0 is mute, 1 is 100%, 2 is 200%.
*/
private function js_call_play(url:String, _width:int, _height:int, buffer_time:Number):void {
private function js_call_play(url:String, _width:int, _height:int, buffer_time:Number, volume:Number):void {
this.user_url = url;
this.user_w = _width;
this.user_h = _height;
... ... @@ -313,6 +317,7 @@ package
}
media_stream = new NetStream(media_conn);
media_stream.soundTransform = new SoundTransform(volume);
media_stream.bufferTime = buffer_time;
media_stream.client = {};
media_stream.client.onMetaData = system_on_metadata;
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...
... ... @@ -10,6 +10,9 @@ package
import flash.media.H264Profile;
import flash.media.H264VideoStreamSettings;
import flash.media.Microphone;
import flash.media.MicrophoneEnhancedMode;
import flash.media.MicrophoneEnhancedOptions;
import flash.media.SoundCodec;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
... ... @@ -135,27 +138,31 @@ package
this.js_call_stop();
// microphone and camera
var m:Microphone = Microphone.getMicrophone(acodec.device_code);
if(m == null){
var microphone:Microphone = null;
//microphone = Microphone.getEnhancedMicrophone(acodec.device_code);
if (!microphone) {
microphone = Microphone.getMicrophone(acodec.device_code);
}
if(microphone == null){
this.system_error(this.error_microphone_get, "failed to open microphone " + acodec.device_code + "(" + acodec.device_name + ")");
return;
}
// ignore muted, for flash will require user to access it.
// Remark: the name is the index!
var c:Camera = Camera.getCamera(vcodec.device_code);
if(c == null){
var camera:Camera = Camera.getCamera(vcodec.device_code);
if(camera == null){
this.system_error(this.error_camera_get, "failed to open camera " + vcodec.device_code + "(" + vcodec.device_name + ")");
return;
}
// ignore muted, for flash will require user to access it.
// but we still warn user.
if(c && c.muted){
if(camera && camera.muted){
this.system_warn(this.error_camera_muted, "Access Denied, camera " + vcodec.device_code + "(" + vcodec.device_name + ") is muted");
}
this.media_camera = c;
this.media_microphone = m;
this.media_camera = camera;
this.media_microphone = microphone;
this.media_conn = new NetConnection();
this.media_conn.client = {};
... ... @@ -188,14 +195,14 @@ package
// TODO: FIXME: failed event.
});
__build_video_codec(media_stream, c, vcodec);
__build_audio_codec(media_stream, m, acodec);
__build_video_codec(media_stream, camera, vcodec);
__build_audio_codec(media_stream, microphone, acodec);
if (media_microphone) {
media_stream.attachAudio(m);
media_stream.attachAudio(microphone);
}
if (media_camera) {
media_stream.attachCamera(c);
media_stream.attachCamera(camera);
}
var streamName:String = url.substr(url.lastIndexOf("/"));
... ... @@ -264,6 +271,10 @@ package
// if your sound capture device supports this value. Otherwise, the default value is the next available capture level above 8 kHz that
// your sound capture device supports, usually 11 kHz.
m.rate = microRate;
// see: http://www.adobe.com/cn/devnet/flashplayer/articles/acoustic-echo-cancellation.html
m.codec = SoundCodec.SPEEX;
m.framesPerPacket = 1;
}
private function __build_video_codec(stream:NetStream, c:Camera, vcodec:Object):void {
if (!c) {
... ... @@ -332,9 +343,9 @@ package
// (highest quality, no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth,
// pass 0 for quality.
// winlin:
// bandwidth is in bps not kbps. 500*1000 = 500kbps.
// bandwidth is in Bps not kbps.
// quality=1 is lowest quality, 100 is highest quality.
c.setQuality(cameraBitrate * 1000, cameraQuality);
c.setQuality(cameraBitrate / 8.0 * 1000, cameraQuality);
}
}
}
\ No newline at end of file
... ...
... ... @@ -8,6 +8,7 @@
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/srs.js"></script>
<script type="text/javascript" src="js/srs.log.js"></script>
<style>
body{
padding-top: 55px;
... ...