arut / nginx-rtmp-module

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

Difference between on_play and on_publish #1730

Open narayanan-ka opened 1 year ago

narayanan-ka commented 1 year ago

I can't understand the difference between on_play and on_publish. Can @arut please explain to me in simple terms ?Your response would be helpful. I can't understand which one to use.

My use case is : Have a django api server for authentication and I intend to use the nginx rtmp module for live streaming and video on demand. For live, i'm currently using the on_publish and on_publish_done which point to 2 functions on my django end to invoke a start a stream and stop a stream. However, For VOD, however, I need to allow the user to upload the file first to nginx after clicking upload and then nginx handles the processing and playing. Can I use the same 2 on_publish and on_publish_done to accept an upload from django end inside the rtmp block.

I have something like this :

    application vod {
        # Live status
        live off;

        # disable consuming the stream from nginx as rtmp
        deny play all;

        # Push the video stream to the local vod application for playing flv's
        push rtmp://www.mydomain.come:4935/vod-flv/;

        # Make HTTP request & use HTTP retcode
        # to decide whether to allow publishing
        # from this connection or not
        # The on_publish callback will redirect the RTMP stream to the streamer's username, rather than their secret stream key
        on_publish      http://www.mydomain.come:80/my-api/vod/startstream/;

        on_publish_dcome http://www.mydomain.come:80/my-api/vod/stopstream/;
    }

    application vod-flv {
        live off;
        # Only accept publishing from localhost.
        # (the `app` RTMP ingest application)
        allow publish www.mydomain.come;

        # play /opt/data/vod-flv/;
        flv_path  /opt/data/vod-flv/;

        allow publish all;

        allow play all;

        Use FLV encryption
        flv_keys on;
        flv_key_path /opt/data/keys/flv;
        flv_fragments_per_key 6;
        flv_key_url /keys/flv/;
    }
lovgrandma commented 1 year ago

With on_publish you can forward the on publish request to a server. I use it to allow users to use the same streamkey but redirect to another application with the name set to the actual uuid of the individual stream I want to begin.

That is my workflow. on_play I havent used. Maybe someone else has a better explanation.

See my example go server:

func main() {
       go serverStreamingServer()
}

func serveStreamingServer() *http.Server {
    http.HandleFunc("/stream/publish", handleIngestLiveStreamPublishAuthentication)
    log.Printf("Media Compliant Server listening at %v", streamingServicesPort)
    err := http.ListenAndServe(serviceAddress+streamingServicesPort, nil)
    if err != nil {
        log.Fatalf("Failed to run Media Compliant Server: %v", err)
    }
    return &http.Server{}
}
func handleIngestLiveStreamPublishAuthentication(w http.ResponseWriter, r *http.Request) {
    log.Println("Received Publish request at /stream/publish")
    body, err := io.ReadAll(r.Body)
    if err != nil {
        // Handle error
        log.Println("Error reading request body:", err)
        http.Error(w, "Error reading request body", http.StatusInternalServerError)
        return
    }

    query, err := url.ParseQuery(string(body))
    if err != nil {
        log.Println("Error parsing query string:", err)
        http.Error(w, "Error parsing query string", http.StatusInternalServerError)
        return
    }

    // Get the value of the "name" field
    streamKey := query.Get("name")
    if streamKey == "" {
        log.Println("Name field is missing")
        http.Error(w, "Name field is missing", http.StatusBadRequest)
        return
    }

    // Check if the stream key is valid or authorized
    if isValidStreamKey(streamKey) == true {
                // based on stream key get application and name of stream
        redirectStreamUrl := streamingServer + "/hls_" + application + "/" + name
        w.Header().Set("Location", redirectStreamUrl)
        w.WriteHeader(http.StatusFound)
        return
    }
    // Send an error response for invalid or unauthorized stream key
    w.WriteHeader(http.StatusForbidden)
    fmt.Fprint(w, "Stream denied")
    return
}

Took me a while to figure this out. Its primarily for a use case in which I can handle authentication and setting of stream id/pathing without having user change their streamkey ever.

Redirect it back to your nginx but to another application that actually ingests stream. Otherwise, I dont think you need to use on_publish if you dont have any sort of ceremony your streaming solution needs to do.

My understanding of on_publish_done is that fires when the stream has ended. So when the stream is complete and you have business logic for complete streams you should use that.

narayanan-ka commented 1 year ago

@lovgrandma Sorry for reverting late. Got lost in the list of notifications on Git. I did exactly Already what you have done for on_publish and on_publish done. I still cant wrap my head around on_play and on_play done. Form the directives listed here https://github.com/arut/nginx-rtmp-module/wiki/Directives#on_publish It seems on_publish is for remote push while on_play for remote_pull. Only if we know what both terms mean from a workflow perspective ?

Sora012 commented 11 months ago

I know this is old issue, but "on_play" is called when someone is trying to view/read/access the stream. "on_publish" is for when someone is trying to publish a stream.

on_publish: can be used to authenticate a stream key and redirect the key to a new location for direct playback without leaking the private stream key

on_publish_done: can be used to de-auth a stream key, you could set a stream in a database as "live" from "on_publish" and then with "on_publish_done" set it as "offline"

on_play: can be used to deny if a stream is private and a wrong password is given, and to increment a view counter

on_play_done: is when a reader/viewer has finished playback. It could be used to remove a "viewer" from a live view counter.

Edit: The above are example ideas, I imagine it could be used in a variety of really creative ways. I personally used "on_play" and "on_play_done" to increase and decrease a view counter per stream, and "on_publish" and "on_publish_done" to authenticate a stream key and if successful redirect the stream to a public username and set a stream as online, or offline.