@ -14,6 +14,13 @@
# include "Thread/semaphore.h"
# include "Common/config.h"
# include "Player/MediaPlayer.h"
# include "Network/TcpServer.h"
# include "Network/sockutil.h"
# include "Http/HttpSession.h"
# include "Rtmp/RtmpSession.h"
# include "Rtsp/RtspSession.h"
# include "Rtmp/RtmpPusher.h"
# include "Pusher/MediaPusher.h"
# include "Extension/Frame.h"
using namespace std ;
@ -164,6 +171,89 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved){
extern int start_main ( int argc , char * argv [ ] ) ;
std : : shared_ptr < TcpServer > startRtmpServer ( uint16_t port ) {
auto server = std : : make_shared < TcpServer > ( ) ;
server - > start < RtmpSession > ( port ) ;
InfoL < < " RTMP Server listening on port " < < port ;
return server ;
}
std : : shared_ptr < TcpServer > startRtspServer ( uint16_t port ) {
auto server = std : : make_shared < TcpServer > ( ) ;
if ( port = = 0 )
{
port = 554 ;
}
server - > start < RtspSession > ( port ) ;
InfoL < < " RTSP Server listening on port " < < port ;
return server ;
}
void startRtmpPushers ( const std : : string & url , const std : : string & targetUrl ) {
MediaInfo mediaInfo ( url ) ;
auto mediaSource = MediaSource : : find ( mediaInfo ) ;
if ( ! mediaSource ) {
// 文件不存在 [AUTO-TRANSLATED:f97c8ce8]
// File does not exist
WarnL < < url < < " not existed: " ;
return ;
}
auto poller = EventPollerPool : : Instance ( ) . getPoller ( ) ;
auto pusher = std : : make_shared < MediaPusher > ( mediaSource , poller ) ;
std : : weak_ptr < MediaSource > weak_src = mediaSource ;
// src用完了, 可以直接置空, 防止main函数持有它(MP4Reader持有它即可) [AUTO-TRANSLATED:52e6393a]
// src is used up, can be set to empty directly, to prevent the main function from holding it (MP4Reader holds it)
mediaSource = nullptr ;
std : : weak_ptr < MediaPusher > weak_pusher = pusher ;
pusher - > setOnShutdown ( [ poller , url , weak_pusher , weak_src ] ( const SockException & ex ) {
if ( ! weak_src . lock ( ) ) {
// 媒体注销导致的推流中断,不在重试推流 [AUTO-TRANSLATED:625b3e1a]
// Media cancellation causes push interruption, no retry push
WarnL < < " MediaSource released: " < < ex < < " , publish stopped " ;
return ;
}
WarnL < < " Server connection is closed: " < < ex < < " , republish after 2 seconds " ;
// 重新推流, 2秒后重试 [AUTO-TRANSLATED:f8a261a3]
// Repush, retry after 2 seconds
poller - > doDelayTask ( 2 * 1000 , [ weak_pusher , url ] ( ) {
if ( auto strong_push = weak_pusher . lock ( ) ) {
strong_push - > publish ( url ) ;
}
return 0 ;
} ) ;
} ) ;
// 设置发布结果处理逻辑 [AUTO-TRANSLATED:ce9de055]
// Set the publish result handling logic
pusher - > setOnPublished ( [ poller , weak_pusher , url ] ( const SockException & ex ) {
if ( ! ex ) {
InfoL < < " Publish success, please play with player: " < < url ;
return ;
}
WarnL < < " Publish fail: " < < ex < < " , republish after 2 seconds " ;
// 如果发布失败,就重试 [AUTO-TRANSLATED:b37fd4aa]
// If the publish fails, retry
poller - > doDelayTask ( 2 * 1000 , [ weak_pusher , url ] ( ) {
if ( auto strong_push = weak_pusher . lock ( ) ) {
strong_push - > publish ( url ) ;
}
return 0 ;
} ) ;
} ) ;
pusher - > publish ( targetUrl ) ;
}
static semaphore sem ;
JNI_API ( jboolean , startServer , jstring ini_dir ) {
string sd_path = stringFromJstring ( env , ini_dir ) ;
string ini_file = sd_path + " /zlmediakit.ini " ;
@ -175,38 +265,28 @@ JNI_API(jboolean, startServer, jstring ini_dir){
DebugL < < " ini file: " < < ini_file ;
thread s_th ( [ sd_path , ini_file , pem_file ] ( ) {
s_tread_id = pthread_self ( ) ;
try {
//http根目录修改默认路径
mINI : : Instance ( ) [ Http : : kRootPath ] = sd_path + " /httpRoot " ;
//mp4录制点播根目录修改默认路径
mINI : : Instance ( ) [ Protocol : : kMP4SavePath ] = sd_path + " /httpRoot " ;
//hls根目录修改默认路径
mINI : : Instance ( ) [ Protocol : : kHlsSavePath ] = sd_path + " /httpRoot " ;
//替换默认端口号(在配置文件未生成时有效)
mINI : : Instance ( ) [ " http.port " ] = 8080 ;
mINI : : Instance ( ) [ " http.sslport " ] = 8443 ;
mINI : : Instance ( ) [ " rtsp.port " ] = 8554 ;
mINI : : Instance ( ) [ " rtsp.port " ] = 0 ;
mINI : : Instance ( ) [ " rtsp.sslport " ] = 8332 ;
mINI : : Instance ( ) [ " rtsp.sslport " ] = 0 ;
mINI : : Instance ( ) [ " general.enableVhost " ] = 0 ;
for ( auto & pr : mINI : : Instance ( ) ) {
//替换hook默认地址
replace ( pr . second , " https://127.0.0.1/ " , " http://127.0.0.1:8080/ " ) ;
}
//默认打开hook
mINI : : Instance ( ) [ " hook.enable " ] = 0 ;
//默认打开http api调试
mINI : : Instance ( ) [ " api.apiDebug " ] = 1 ;
int argc = 5 ;
const char * argv [ ] = { " " , " -c " , ini_file . data ( ) , " -s " , pem_file . data ( ) } ;
start_main ( argc , ( char * * ) argv ) ;
s_tread_id = 0 ;
} catch ( std : : exception & ex ) {
WarnL < < ex . what ( ) ;
}
Logger : : Instance ( ) . add ( std : : make_shared < ConsoleChannel > ( " ConsoleChannel " , LTrace ) ) ;
// Load the configuration file
// initConfig();
// Initialize the event loop
EventPollerPool : : Instance ( ) . setPoolSize ( 4 ) ;
// Start the RTMP server
auto rtmpSvr = startRtmpServer ( 1935 ) ;
auto rtspSvr = startRtspServer ( 554 ) ;
// Start the RTMP pushers
// startRtmpPushers("", "");
// Wait for the signal to exit
signal ( SIGINT , [ ] ( int ) { sem . post ( ) ; } ) ;
signal ( SIGTERM , [ ] ( int ) { sem . post ( ) ; } ) ;
sem . wait ( ) ;
} ) ;
// static onceToken s_token([]{
@ -216,17 +296,8 @@ JNI_API(jboolean, startServer, jstring ini_dir){
return true ;
} ;
extern semaphore g_zl_sem ;
JNI_API ( void , stopServer ) {
g_zl_sem . post ( ) ;
s_tread_id = 0 ;
#if 0
if ( s_tread_id ) {
pthread_kill ( s_tread_id , SIGINT ) ;
s_tread_id = 0 ;
}
# endif
sem . post ( ) ;
}
JNI_API ( jlong , createMediaPlayer , jstring url , jobject callback ) {