arut / nginx-rtmp-module

NGINX-based Media Streaming Server
http://nginx-rtmp.blogspot.com
BSD 2-Clause "Simplified" License
13.46k stars 3.51k forks source link

Way to redirect parameters from source to target with push #920

Open caleblanchard opened 7 years ago

caleblanchard commented 7 years ago

When utilizing the push directive is there a way to redirect any parameters passed in to the source url to the target url?

Example: Publishing to application via rtmp://server/live/stream?parm1=1&parm2=2

config file:

application live {
   live on;
   meta copy;
   push rtmp://differentserver/live/stream?{copy parameters from stream being published (i.e. parm1=1&parm2=2)};
}
coditori commented 7 years ago

You can put them in your first RTMP request and It'll push them to your destination RTMP server. Just change it to

application live {
   live on;
   meta copy;
   push rtmp://differentserver/live;
}

Either way if you want to give the destination RTMP server (which is rtmp://differentserver here) from Database of somewhere else just use on_publish and 3xx redirect.

caleblanchard commented 7 years ago

Through looking at the log file i found that just like there are $name and $app variables, there is an $args variable that I can use. However, it looks like the variables don't work when using the normal push directive. They work when using exec_push but not just push. Right now I am using a work around of using exec_push ffmpeg to redirect the stream so that I can use the $name and $args variables.

coditori commented 7 years ago

It's not efficent then because FFMPEG needs some hardware stuff like CPU and RAM. Like I said you can use on_publish and call a HTTP rest service like this:

application live {
   live on;
   on_publish http://localhost:8000/rtmp-redirect
}

take a look at https://github.com/arut/nginx-rtmp-module/wiki/Directives#on_publish

caleblanchard commented 7 years ago

I guess I am not clear on what on_publish does. What is the http://localhost:8000/rtmp-redirect going to do?

coditori commented 7 years ago

It's a callback that you can work on yours parameters there. http://localhost:8000/rtmp-redirect this is just an example. E.g imagine that I have a webservice on above URL. I can catch the parameters is first RTMP URL and then use a HTTP redirect in my webservice to tell the Nginx-rtmp what to do. All things are happend in here: http://localhost:8000/rtmp-redirect.

gavalierm commented 7 years ago

@massoudAfrashteh

But: How create push duplication with on_publish?

i try push (clone) to many services (1 in X out) and push is really great directive for this:

My encoder uri is: rtmp://service0/livepp/?service1_secret=foo&service2_secret=bar&service3_secret=blah

rtmp {
        server {
                listen 1935;
                chunk_size 4096;

                application livepp {
                        live on;
                        record off;
                        meta copy;

                        push rtmp://service1/live/$arg_service1_secret;
                        push rtmp://service2/live/$arg_service2_secret;
                        push rtmp://service3/live/$arg_service3_secret;

                }
        }
}

but this not working, because args is not working in simple "push" directive (what is crazy)...

Can you got me some advices to figure this out?

Thank you.

coditori commented 7 years ago

Hi just can use $args not any other parameters that are not listed in rtmp-module

czb1n commented 7 years ago
rtmp {
        server {
                listen 1935;
                application live {
                        live on;
                        push rtmp://otherserver/live/$name?$args;
                }
        }
}

e.g rtmp://server/live/stream?t=123 >>> rtmp://otherserver/live/stream?t=123

I want to use $name and $args in push directive, but is not working... Can you tell me how to figure this out? Thank you.

@massoudAfrashteh

coditori commented 7 years ago

Hi $args will contain all arguments after "?" E.g "rtmp://server/live/stream?t=123&a=10&p=20&u=11" then $args will be "t=123&a=10&p=20&u=11". I suggest to run a bash file inside your application then send your variables there and check values.

czb1n commented 7 years ago

Thanks, but I use $name and $args in exec_publish directive to run a bash is work, but in push directive $name and $args can't parse variables, it just "$name" and "args" string.

coditori commented 7 years ago

@czb1n could you please share your bash example with $name and $args?

czb1n commented 7 years ago

@massoudAfrashteh like i said, run a bash is work. but in the 'push' directive, $name and $args can't parse. example :

rtmp {
        server {
                listen 1935;
                application live {
                        live on;
                        push rtmp://otherserver/live/$name?$args;
                        exec_publish bash -c "echo $name'?'$args >> test.txt";
                }
        }
}

push rtmp://otherserver/live/$name?$args -> can't not parse variables. exec_publish bash -c "echo $name'?'$args >> test.txt" -> can parse variables.

denniskrol commented 7 years ago

Did you ever find a way? Running into this exact issue.

coditori commented 7 years ago

@gavalierm @czb1n @denniskrol Forget "push" it does not work with "$args" if you want to pass some parameters to another server there are some ways:

In Origin Server(s)

  1. "on_publish" in origin Nginx which call a web application (in web application side redirect to target server with simple "if" based on $args). (EFFICIENT)
  2. Another is using FFMPEG in origin server with "exec_publish ffmpeg ... " (NOT EFFICIENT)

Then in Target Server(s):

  1. you need to define N number of RTMP applications based on your $args parameters (STATIC)
  2. or use "exec_publish ffmpeg ..." (DYNAMIC)

Note: Just read "on_publish" documentation. Choosing each of these depending on your architecture. If you still have problems please read wiki carefully.

ChaosPower commented 6 years ago

Does $arg_varname work? Have not tested it out yet.

mattelacchiato commented 4 years ago

I am having the same problem: I want to push to youtube, which changes its secret from time to time. When I push to my nginx, I want to add a GET parameter like rtmp://localhost/live/foo?yt=<secrect>. This secret should the passed to to the push directive like push rtmp://youtube.com/live2/<secret>.

grahamPegNetwork commented 4 years ago

I feel like I have a similar situation. I would like to be able to receive streams on multiple addresses then push them to corresponding remote addresses. Eg: In: Rtmp://server1/live/abc Out: Push rtmp://server2/live/abc In: Rtmp://server1/live/def Out:Push rtmp://server2/live/def

not404-found commented 4 years ago

Has anyone managed to get the parameters? It is not clear how to do this with the on_publish method. Could you give a real working example? @coditori

rtpm url: rtmp://ip:1935/test/1?ykey=1234 here is my test config:

worker_processes  auto;
events {
    worker_connections  1024;
}

# RTMP configuration
rtmp {
    server {
        listen 1935; # Listen on standard RTMP port
        chunk_size 4000;

        application test{
            live on;
            on_publish http://192.168.99.100:8090/onpublishtest ;
        }
    }
}

http {
    sendfile off;
    tcp_nopush on;
    aio on;
    directio 512;
    default_type application/octet-stream;

    server {
        listen 8090;

        location / {
               # some
        }
        location /onpublishtest {
               rewrite ^.*$ rtmp://a.rtmp.youtube.com/live2/$arg_ykey permanent
       }
    }
} 
aitzkovitz commented 4 years ago

Has anyone found a way to deal with this?

Essentially, I'm just trying to access request variables that were sent in rtmp url (rtmp://example.com/app?id=123&id2=abc).

I understand you can hook into events like publish or play to access these parameters, but you can only return 1 url and status code, and I'm trying to push out to 3 different ingests.

E.g.: push rtmp://a.rtmp.youtube.com/live1?id=123; push rtmp://a.rtmp.youtube.com/live2?id=456; push rtmp://a.rtmp.youtube.com/live3?id=789;

Would appreciate any help.

safavakili commented 2 years ago

I couldn't find any easy ways. I did it by changing the source code in _ngx_rtmp_relaymodule.c in nginx-rtmp-module.

I added a flag (forward_auth) for nginx.conf:

rtmp { 
    server { 
        max_message 5M; 
    listen 1936;
        chunk_size 4000;
    application live{
        live on;
        push rtmp://next_rtmp_server_url:1935/live;
                forward_auth on;
    }
   }
}

to make your nginx pass the arguments you should add _forwardauth on;

and here is my _ngx_rtmp_relaymodule.c : ngx_rtmp_relay_module.txt

MehdiJafari84 commented 1 year ago

Hello guys!

You can use this solution that works for me for Instagram live. I wrote a webservice method to redirect rtmp with $name and $args in C# language.

For example you want to redirect "rtmp://source/app/name?p1=foo&p2=blah" to "rtmp://destination/app/name?p1=foo&p2=blah"

Source RTMP block:

rtmp {
    server {
        listen 1935;
        buflen 500ms;
            notify_method get;
            publish_time_fix off;
        allow play all;     
        application app {
                    live on;
                    record off;
            on_publish http://mywebsite/api/v1/live/MyRedirect;
             }              
    }
}

Inside webservice method, is up to you to write a webservice or simple callback method in any language.

public HttpResponseMessage MyRedirect()
        {
           //Nginx posts $name and $args to this method
           //we handle params and recreate $args here
            string args = "p1=" + HttpContext.Current.Request.Params["p1"] + "&p2=" + HttpContext.Current.Request.Params["p2"];
           //get stream name here you can change it if destination is diffrent
            string name = HttpContext.Current.Request.Params["name"];
           //Url to redirect
            string url = "rtmp://destination/app/" + name + "?" + args;
           //--------> 301 redirect
            var response = Request.CreateResponse(HttpStatusCode.Moved); 
           // put your final url in header
            response.Headers.Location = new Uri(url);  
            return response;
        }

Above method returns 301 redirect or move with destination url in response header.

FYI for Facebook and Instagram you should use Stunnel to relay rtmp to rtmps. In my case my destination is rtmp://127.0.01:19350/rtmp/name?args which is set in the Stunnel config.

hope this helps.