winlin

merge from 2.0release

1 #Simple-RTMP-Server 1 #Simple-RTMP-Server
2 2
3 -SRS/3.0,开发代号:[OuXuli](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#release30) 3 +SRS/3.0, [OuXuli](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#release30)
4 4
5 SRS定位是运营级的互联网直播服务器集群,追求更好的概念完整性和最简单实现的代码。<br/> 5 SRS定位是运营级的互联网直播服务器集群,追求更好的概念完整性和最简单实现的代码。<br/>
6 SRS is industrial-strength live streaming cluster, for the best conceptual integrity and the simplest implementation. 6 SRS is industrial-strength live streaming cluster, for the best conceptual integrity and the simplest implementation.
7 7
8 Download from github.io: [Centos6-x86_64][centos0], [more...][more0]<br/> 8 Download from github.io: [Centos6-x86_64][centos0], [more...][more0]<br/>
9 Download from ossrs.net: [Centos6-x86_64][centos1], [more...][more1]<br/> 9 Download from ossrs.net: [Centos6-x86_64][centos1], [more...][more1]<br/>
10 -Contact by QQ or Skype, read [Contact][contact] 10 +Website for SRS/2.0, read SRS 2.0 [Chinese][srs2_CN] or [English][srs2_EN].
11 11
12 ## Why SRS? 12 ## Why SRS?
13 13
@@ -1025,5 +1025,6 @@ Winlin @@ -1025,5 +1025,6 @@ Winlin
1025 [centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip 1025 [centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip
1026 [centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip 1026 [centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip
1027 1027
1028 - 1028 +[srs2_CN]: https://github.com/simple-rtmp-server/srs/wiki/v2_CN_Home
  1029 +[srs2_EN]: https://github.com/simple-rtmp-server/srs/wiki/v2_EN_Home
1029 1030
@@ -38,6 +38,7 @@ int proxy(srs_flv_t flv, srs_rtmp_t ortmp); @@ -38,6 +38,7 @@ int proxy(srs_flv_t flv, srs_rtmp_t ortmp);
38 int connect_oc(srs_rtmp_t ortmp); 38 int connect_oc(srs_rtmp_t ortmp);
39 39
40 #define RE_PULSE_MS 300 40 #define RE_PULSE_MS 300
  41 +#define RE_PULSE_JITTER_MS 3000
41 int64_t re_create(); 42 int64_t re_create();
42 void re_update(int64_t re, int32_t starttime, u_int32_t time); 43 void re_update(int64_t re, int32_t starttime, u_int32_t time);
43 void re_cleanup(int64_t re, int32_t starttime, u_int32_t time); 44 void re_cleanup(int64_t re, int32_t starttime, u_int32_t time);
@@ -256,7 +257,7 @@ void re_update(int64_t re, int32_t starttime, u_int32_t time) @@ -256,7 +257,7 @@ void re_update(int64_t re, int32_t starttime, u_int32_t time)
256 // send by pulse algorithm. 257 // send by pulse algorithm.
257 int64_t now = srs_utils_time_ms(); 258 int64_t now = srs_utils_time_ms();
258 int64_t diff = time - starttime - (now -re); 259 int64_t diff = time - starttime - (now -re);
259 - if (diff > RE_PULSE_MS) { 260 + if (diff > RE_PULSE_MS && diff < RE_PULSE_JITTER_MS) {
260 usleep((useconds_t)(diff * 1000)); 261 usleep((useconds_t)(diff * 1000));
261 } 262 }
262 } 263 }
@@ -853,6 +853,7 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) @@ -853,6 +853,7 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
853 } 853 }
854 } 854 }
855 855
  856 + // TODO: reload new http_remux in on_vhost_add
856 // http_remux, only one per vhost. 857 // http_remux, only one per vhost.
857 if (get_vhost_http_remux_enabled(vhost)) { 858 if (get_vhost_http_remux_enabled(vhost)) {
858 for (it = subscribes.begin(); it != subscribes.end(); ++it) { 859 for (it = subscribes.begin(); it != subscribes.end(); ++it) {
@@ -4417,3 +4418,18 @@ bool srs_config_dvr_is_plan_append(string plan) @@ -4417,3 +4418,18 @@ bool srs_config_dvr_is_plan_append(string plan)
4417 { 4418 {
4418 return plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND; 4419 return plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND;
4419 } 4420 }
  4421 +
  4422 +bool srs_stream_caster_is_udp(string caster)
  4423 +{
  4424 + return caster == SRS_CONF_DEFAULT_STREAM_CASTER_MPEGTS_OVER_UDP;
  4425 +}
  4426 +
  4427 +bool srs_stream_caster_is_rtsp(string caster)
  4428 +{
  4429 + return caster == SRS_CONF_DEFAULT_STREAM_CASTER_RTSP;
  4430 +}
  4431 +
  4432 +bool srs_stream_caster_is_flv(string caster)
  4433 +{
  4434 + return caster == SRS_CONF_DEFAULT_STREAM_CASTER_FLV;
  4435 +}
@@ -1143,6 +1143,9 @@ extern bool srs_config_ingest_is_stream(std::string type); @@ -1143,6 +1143,9 @@ extern bool srs_config_ingest_is_stream(std::string type);
1143 extern bool srs_config_dvr_is_plan_segment(std::string plan); 1143 extern bool srs_config_dvr_is_plan_segment(std::string plan);
1144 extern bool srs_config_dvr_is_plan_session(std::string plan); 1144 extern bool srs_config_dvr_is_plan_session(std::string plan);
1145 extern bool srs_config_dvr_is_plan_append(std::string plan); 1145 extern bool srs_config_dvr_is_plan_append(std::string plan);
  1146 +extern bool srs_stream_caster_is_udp(std::string caster);
  1147 +extern bool srs_stream_caster_is_rtsp(std::string caster);
  1148 +extern bool srs_stream_caster_is_flv(std::string caster);
1146 1149
1147 // global config 1150 // global config
1148 extern SrsConfig* _srs_config; 1151 extern SrsConfig* _srs_config;
@@ -164,7 +164,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* shared_metadata) @@ -164,7 +164,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* shared_metadata)
164 SrsSharedPtrMessage* metadata = shared_metadata->copy(); 164 SrsSharedPtrMessage* metadata = shared_metadata->copy();
165 165
166 // TODO: FIXME: config the jitter of Forwarder. 166 // TODO: FIXME: config the jitter of Forwarder.
167 - if ((ret = jitter->correct(metadata, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) { 167 + if ((ret = jitter->correct(metadata, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
168 srs_freep(metadata); 168 srs_freep(metadata);
169 return ret; 169 return ret;
170 } 170 }
@@ -183,7 +183,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* shared_audio) @@ -183,7 +183,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* shared_audio)
183 SrsSharedPtrMessage* msg = shared_audio->copy(); 183 SrsSharedPtrMessage* msg = shared_audio->copy();
184 184
185 // TODO: FIXME: config the jitter of Forwarder. 185 // TODO: FIXME: config the jitter of Forwarder.
186 - if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) { 186 + if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
187 srs_freep(msg); 187 srs_freep(msg);
188 return ret; 188 return ret;
189 } 189 }
@@ -207,7 +207,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* shared_video) @@ -207,7 +207,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* shared_video)
207 SrsSharedPtrMessage* msg = shared_video->copy(); 207 SrsSharedPtrMessage* msg = shared_video->copy();
208 208
209 // TODO: FIXME: config the jitter of Forwarder. 209 // TODO: FIXME: config the jitter of Forwarder.
210 - if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) { 210 + if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
211 srs_freep(msg); 211 srs_freep(msg);
212 return ret; 212 return ret;
213 } 213 }
@@ -53,6 +53,8 @@ using namespace std; @@ -53,6 +53,8 @@ using namespace std;
53 53
54 // drop the segment when duration of ts too small. 54 // drop the segment when duration of ts too small.
55 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 55 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
  56 +// when hls timestamp jump, reset it.
  57 +#define SRS_AUTO_HLS_SEGMENT_TIMESTAMP_JUMP_MS 300
56 58
57 // fragment plus the deviation percent. 59 // fragment plus the deviation percent.
58 #define SRS_HLS_FLOOR_REAP_PERCENT 0.3 60 #define SRS_HLS_FLOOR_REAP_PERCENT 0.3
@@ -161,6 +163,11 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts) @@ -161,6 +163,11 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts)
161 // update the segment duration, which is nagetive, 163 // update the segment duration, which is nagetive,
162 // just ignore it. 164 // just ignore it.
163 if (current_frame_dts < segment_start_dts) { 165 if (current_frame_dts < segment_start_dts) {
  166 + // for atc and timestamp jump, reset the start dts.
  167 + if (current_frame_dts < segment_start_dts - SRS_AUTO_HLS_SEGMENT_TIMESTAMP_JUMP_MS * 90) {
  168 + srs_warn("hls timestamp jump %"PRId64"=>%"PRId64, segment_start_dts, current_frame_dts);
  169 + segment_start_dts = current_frame_dts;
  170 + }
164 return; 171 return;
165 } 172 }
166 173
@@ -280,7 +287,7 @@ SrsHlsMuxer::SrsHlsMuxer() @@ -280,7 +287,7 @@ SrsHlsMuxer::SrsHlsMuxer()
280 previous_floor_ts = 0; 287 previous_floor_ts = 0;
281 accept_floor_ts = 0; 288 accept_floor_ts = 0;
282 hls_ts_floor = false; 289 hls_ts_floor = false;
283 - target_duration = 0; 290 + max_td = 0;
284 _sequence_no = 0; 291 _sequence_no = 0;
285 current = NULL; 292 current = NULL;
286 acodec = SrsCodecAudioReserved1; 293 acodec = SrsCodecAudioReserved1;
@@ -400,10 +407,8 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, @@ -400,10 +407,8 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
400 m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream); 407 m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
401 m3u8 = path + "/" + m3u8_url; 408 m3u8 = path + "/" + m3u8_url;
402 409
403 - // we always keep the target duration increasing.  
404 - int max_td = srs_max(target_duration, (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost)));  
405 - srs_info("hls update target duration %d=>%d, aof=%.2f", target_duration, max_td, aof_ratio);  
406 - target_duration = max_td; 410 + // when update config, reset the history target duration.
  411 + max_td = (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost));
407 412
408 std::string storage = _srs_config->get_hls_storage(r->vhost); 413 std::string storage = _srs_config->get_hls_storage(r->vhost);
409 if (storage == "ram") { 414 if (storage == "ram") {
@@ -699,7 +704,9 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -699,7 +704,9 @@ int SrsHlsMuxer::segment_close(string log_desc)
699 srs_assert(it == segments.end()); 704 srs_assert(it == segments.end());
700 705
701 // valid, add to segments if segment duration is ok 706 // valid, add to segments if segment duration is ok
702 - if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { 707 + // when too small, it maybe not enough data to play.
  708 + // when too large, it maybe timestamp corrupt.
  709 + if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS && (int)current->duration <= max_td) {
703 segments.push_back(current); 710 segments.push_back(current);
704 711
705 // use async to call the http hooks, for it will cause thread switch. 712 // use async to call the http hooks, for it will cause thread switch.
@@ -750,7 +757,6 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -750,7 +757,6 @@ int SrsHlsMuxer::segment_close(string log_desc)
750 // rename from tmp to real path 757 // rename from tmp to real path
751 std::string tmp_file = current->full_path + ".tmp"; 758 std::string tmp_file = current->full_path + ".tmp";
752 if (should_write_file) { 759 if (should_write_file) {
753 - unlink(tmp_file.c_str());  
754 if (unlink(tmp_file.c_str()) < 0) { 760 if (unlink(tmp_file.c_str()) < 0) {
755 srs_warn("ignore unlink path failed, file=%s.", tmp_file.c_str()); 761 srs_warn("ignore unlink path failed, file=%s.", tmp_file.c_str());
756 } 762 }
@@ -817,6 +823,11 @@ int SrsHlsMuxer::refresh_m3u8() @@ -817,6 +823,11 @@ int SrsHlsMuxer::refresh_m3u8()
817 { 823 {
818 int ret = ERROR_SUCCESS; 824 int ret = ERROR_SUCCESS;
819 825
  826 + // no segments, also no m3u8, return.
  827 + if (segments.size() == 0) {
  828 + return ret;
  829 + }
  830 +
820 std::string temp_m3u8 = m3u8 + ".temp"; 831 std::string temp_m3u8 = m3u8 + ".temp";
821 if ((ret = _refresh_m3u8(temp_m3u8)) == ERROR_SUCCESS) { 832 if ((ret = _refresh_m3u8(temp_m3u8)) == ERROR_SUCCESS) {
822 if (should_write_file && rename(temp_m3u8.c_str(), m3u8.c_str()) < 0) { 833 if (should_write_file && rename(temp_m3u8.c_str(), m3u8.c_str()) < 0) {
@@ -826,7 +837,11 @@ int SrsHlsMuxer::refresh_m3u8() @@ -826,7 +837,11 @@ int SrsHlsMuxer::refresh_m3u8()
826 } 837 }
827 838
828 // remove the temp file. 839 // remove the temp file.
829 - unlink(temp_m3u8.c_str()); 840 + if (srs_path_exists(temp_m3u8)) {
  841 + if (unlink(temp_m3u8.c_str()) < 0) {
  842 + srs_warn("ignore remove m3u8 failed, %s", temp_m3u8.c_str());
  843 + }
  844 + }
830 845
831 return ret; 846 return ret;
832 } 847 }
@@ -861,6 +876,9 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) @@ -861,6 +876,9 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
861 ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF; 876 ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF;
862 srs_verbose("write m3u8 sequence success."); 877 srs_verbose("write m3u8 sequence success.");
863 878
  879 + // iterator shared for td generation and segemnts wrote.
  880 + std::vector<SrsHlsSegment*>::iterator it;
  881 +
864 // #EXT-X-TARGETDURATION:4294967295\n 882 // #EXT-X-TARGETDURATION:4294967295\n
865 /** 883 /**
866 * @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 25 884 * @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 25
@@ -871,11 +889,13 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) @@ -871,11 +889,13 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
871 * typical target duration is 10 seconds. 889 * typical target duration is 10 seconds.
872 */ 890 */
873 // @see https://github.com/simple-rtmp-server/srs/issues/304#issuecomment-74000081 891 // @see https://github.com/simple-rtmp-server/srs/issues/304#issuecomment-74000081
874 - std::vector<SrsHlsSegment*>::iterator it; 892 + int target_duration = 0;
875 for (it = segments.begin(); it != segments.end(); ++it) { 893 for (it = segments.begin(); it != segments.end(); ++it) {
876 SrsHlsSegment* segment = *it; 894 SrsHlsSegment* segment = *it;
877 target_duration = srs_max(target_duration, (int)ceil(segment->duration)); 895 target_duration = srs_max(target_duration, (int)ceil(segment->duration));
878 } 896 }
  897 + target_duration = srs_max(target_duration, max_td);
  898 +
879 ss << "#EXT-X-TARGETDURATION:" << target_duration << SRS_CONSTS_LF; 899 ss << "#EXT-X-TARGETDURATION:" << target_duration << SRS_CONSTS_LF;
880 srs_verbose("write m3u8 duration success."); 900 srs_verbose("write m3u8 duration success.");
881 901
@@ -1335,7 +1355,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) @@ -1335,7 +1355,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
1335 } 1355 }
1336 1356
1337 // TODO: FIXME: config the jitter of HLS. 1357 // TODO: FIXME: config the jitter of HLS.
1338 - if ((ret = jitter->correct(audio, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) { 1358 + if ((ret = jitter->correct(audio, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
1339 srs_error("rtmp jitter correct audio failed. ret=%d", ret); 1359 srs_error("rtmp jitter correct audio failed. ret=%d", ret);
1340 return ret; 1360 return ret;
1341 } 1361 }
@@ -1393,7 +1413,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video) @@ -1393,7 +1413,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video)
1393 } 1413 }
1394 1414
1395 // TODO: FIXME: config the jitter of HLS. 1415 // TODO: FIXME: config the jitter of HLS.
1396 - if ((ret = jitter->correct(video, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) { 1416 + if ((ret = jitter->correct(video, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
1397 srs_error("rtmp jitter correct video failed. ret=%d", ret); 1417 srs_error("rtmp jitter correct video failed. ret=%d", ret);
1398 return ret; 1418 return ret;
1399 } 1419 }
@@ -233,7 +233,7 @@ private: @@ -233,7 +233,7 @@ private:
233 int64_t previous_floor_ts; 233 int64_t previous_floor_ts;
234 private: 234 private:
235 int _sequence_no; 235 int _sequence_no;
236 - int target_duration; 236 + int max_td;
237 std::string m3u8; 237 std::string m3u8;
238 std::string m3u8_url; 238 std::string m3u8_url;
239 private: 239 private:
@@ -805,7 +805,14 @@ int SrsHttpStreamServer::http_mount(SrsSource* s, SrsRequest* r) @@ -805,7 +805,14 @@ int SrsHttpStreamServer::http_mount(SrsSource* s, SrsRequest* r)
805 entry->cache = new SrsStreamCache(s, r); 805 entry->cache = new SrsStreamCache(s, r);
806 entry->stream = new SrsLiveStream(s, r, entry->cache); 806 entry->stream = new SrsLiveStream(s, r, entry->cache);
807 807
808 - srs_assert(!tmpl->req); 808 + // TODO: FIXME: maybe refine the logic of http remux service.
  809 + // if user push streams followed:
  810 + // rtmp://test.com/live/stream1
  811 + // rtmp://test.com/live/stream2
  812 + // and they will using the same template, such as: [vhost]/[app]/[stream].flv
  813 + // so, need to free last request object, otherwise, it will cause memory leak.
  814 + srs_freep(tmpl->req);
  815 +
809 tmpl->source = s; 816 tmpl->source = s;
810 tmpl->req = r->copy(); 817 tmpl->req = r->copy();
811 818
@@ -1170,8 +1177,8 @@ int SrsHttpStreamServer::hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph) @@ -1170,8 +1177,8 @@ int SrsHttpStreamServer::hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph)
1170 std::string sid = r->get_stream_url(); 1177 std::string sid = r->get_stream_url();
1171 // check if the stream is enabled. 1178 // check if the stream is enabled.
1172 if (sflvs.find(sid) != sflvs.end()) { 1179 if (sflvs.find(sid) != sflvs.end()) {
1173 - SrsLiveEntry* entry = sflvs[sid];  
1174 - if (!entry->stream->entry->enabled) { 1180 + SrsLiveEntry* s_entry = sflvs[sid];
  1181 + if (!s_entry->stream->entry->enabled) {
1175 srs_error("stream is disabled, hijack failed. ret=%d", ret); 1182 srs_error("stream is disabled, hijack failed. ret=%d", ret);
1176 return ret; 1183 return ret;
1177 } 1184 }
@@ -1228,7 +1235,9 @@ int SrsHttpStreamServer::initialize_flv_streaming() @@ -1228,7 +1235,9 @@ int SrsHttpStreamServer::initialize_flv_streaming()
1228 continue; 1235 continue;
1229 } 1236 }
1230 1237
1231 - initialize_flv_entry(conf->arg0()); 1238 + if ((ret = initialize_flv_entry(conf->arg0())) != ERROR_SUCCESS) {
  1239 + return ret;
  1240 + }
1232 } 1241 }
1233 return ret; 1242 return ret;
1234 } 1243 }
@@ -1120,11 +1120,11 @@ int SrsServer::listen_stream_caster() @@ -1120,11 +1120,11 @@ int SrsServer::listen_stream_caster()
1120 SrsListener* listener = NULL; 1120 SrsListener* listener = NULL;
1121 1121
1122 std::string caster = _srs_config->get_stream_caster_engine(stream_caster); 1122 std::string caster = _srs_config->get_stream_caster_engine(stream_caster);
1123 - if (caster == SRS_CONF_DEFAULT_STREAM_CASTER_MPEGTS_OVER_UDP) { 1123 + if (srs_stream_caster_is_udp(caster)) {
1124 listener = new SrsUdpCasterListener(this, SrsListenerMpegTsOverUdp, stream_caster); 1124 listener = new SrsUdpCasterListener(this, SrsListenerMpegTsOverUdp, stream_caster);
1125 - } else if (caster == SRS_CONF_DEFAULT_STREAM_CASTER_RTSP) { 1125 + } else if (srs_stream_caster_is_rtsp(caster)) {
1126 listener = new SrsRtspListener(this, SrsListenerRtsp, stream_caster); 1126 listener = new SrsRtspListener(this, SrsListenerRtsp, stream_caster);
1127 - } else if (caster == SRS_CONF_DEFAULT_STREAM_CASTER_FLV) { 1127 + } else if (srs_stream_caster_is_flv(caster)) {
1128 listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster); 1128 listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster);
1129 } else { 1129 } else {
1130 ret = ERROR_STREAM_CASTER_ENGINE; 1130 ret = ERROR_STREAM_CASTER_ENGINE;
@@ -55,8 +55,8 @@ using namespace std; @@ -55,8 +55,8 @@ using namespace std;
55 // 115 packets is 3s. 55 // 115 packets is 3s.
56 #define SRS_PURE_AUDIO_GUESS_COUNT 115 56 #define SRS_PURE_AUDIO_GUESS_COUNT 115
57 57
58 -// when got these videos or audios, mix ok.  
59 -#define SRS_MIX_CORRECT_MIX_AV 10 58 +// when got these videos or audios, pure audio or video, mix ok.
  59 +#define SRS_MIX_CORRECT_PURE_AV 10
60 60
61 int _srs_time_jitter_string2int(std::string time_jitter) 61 int _srs_time_jitter_string2int(std::string time_jitter)
62 { 62 {
@@ -849,12 +849,25 @@ void SrsMixQueue::push(SrsSharedPtrMessage* msg) @@ -849,12 +849,25 @@ void SrsMixQueue::push(SrsSharedPtrMessage* msg)
849 849
850 SrsSharedPtrMessage* SrsMixQueue::pop() 850 SrsSharedPtrMessage* SrsMixQueue::pop()
851 { 851 {
852 - // when got 10+ videos or audios, mix ok.  
853 - // when got 1 video and 1 audio, mix ok.  
854 - if (nb_videos < SRS_MIX_CORRECT_MIX_AV && nb_audios < SRS_MIX_CORRECT_MIX_AV) {  
855 - if (nb_videos < 1 || nb_audios < 1) {  
856 - return NULL;  
857 - } 852 + bool mix_ok = false;
  853 +
  854 + // pure video
  855 + if (nb_videos >= SRS_MIX_CORRECT_PURE_AV && nb_audios == 0) {
  856 + mix_ok = true;
  857 + }
  858 +
  859 + // pure audio
  860 + if (nb_audios >= SRS_MIX_CORRECT_PURE_AV && nb_videos == 0) {
  861 + mix_ok = true;
  862 + }
  863 +
  864 + // got 1 video and 1 audio, mix ok.
  865 + if (nb_videos >= 1 && nb_audios >= 1) {
  866 + mix_ok = true;
  867 + }
  868 +
  869 + if (!mix_ok) {
  870 + return NULL;
858 } 871 }
859 872
860 // pop the first msg. 873 // pop the first msg.