AirenSoft / OvenMediaEngine

OvenMediaEngine (OME) is a Sub-Second Latency Live Streaming Server with Large-Scale and High-Definition. #WebRTC #LLHLS
https://OvenMediaEngine.com/ome
GNU Affero General Public License v3.0
2.53k stars 1.06k forks source link

Can't get stream to work in OvenPlayer locally #1012

Closed JahzyB closed 1 year ago

JahzyB commented 1 year ago

I'm trying to stream locally from OME to OvenPlayer and I can't get it to work. I'm pretty lost and am just trying different things. If I set the file to file: 'wss://192.168.1.102:3333/app/stream' in the config for OvenPlayer and try to play I get this error: [2023-02-02 19:12:56.699] E [SPRtcSig-T3333:10] HttpServer | http_transaction.cpp:163 | Invalid parse status: 400. If I try file: 'wss://192.168.1.102:3334/app/stream' in the player config I get [2023-02-02 19:13:21.455] E [SPRtcSig-T3334:12] OpenSSL | tls.cpp:193 | An error occurred while accept SSL connection: [OpenSSL] error:0A000412:SSL routines::sslv3 alert bad certificate (167773202).

Server.xml:

<?xml version="1.0" encoding="UTF-8"?>

<Server version="8">
    <Name>OvenMediaEngine</Name>
    <!-- Host type (origin/edge) -->
    <Type>origin</Type>
    <!-- Specify IP address to bind (* means all IPs) -->
    <IP>*</IP>
    <PrivacyProtection>false</PrivacyProtection>

    <!-- 
    To get the public IP address(mapped address of stun) of the local server. 
    This is useful when OME cannot obtain a public IP from an interface, such as AWS or docker environment. 
    If this is successful, you can use ${PublicIP} in your settings.
    -->
    <StunServer>stun.l.google.com:19302</StunServer>

    <Modules>
        <!-- 
        Currently OME only supports h2 like all browsers do. Therefore, HTTP/2 only works on TLS ports.         
        -->
        <HTTP2>
            <Enable>true</Enable>
        </HTTP2>

        <LLHLS>
            <Enable>true</Enable>
        </LLHLS>

        <!-- P2P works only in WebRTC and is experiment feature -->
        <P2P>
            <!-- disabled by default -->
            <Enable>false</Enable>
            <MaxClientPeersPerHostPeer>2</MaxClientPeersPerHostPeer>
        </P2P>
    </Modules>

<!-- Settings for the ports to bind -->
<Bind>
    <!-- Enable this configuration if you want to use API Server -->
    <!--
    <Managers>
        <API>
            <Port>8081</Port>
            <TLSPort>8082</TLSPort>
            <WorkerCount>1</WorkerCount>
        </API>
    </Managers>
    -->

    <Providers>
        <!-- Pull providers -->
        <RTSPC>
            <WorkerCount>1</WorkerCount>
        </RTSPC>
        <OVT>
            <WorkerCount>1</WorkerCount>
        </OVT>
        <!-- Push providers -->
        <RTMP>
            <Port>1935</Port>
            <WorkerCount>1</WorkerCount>
        </RTMP>
        <SRT>
            <Port>9999</Port>
            <WorkerCount>1</WorkerCount>
        </SRT>
        <MPEGTS>
            <!--
                Listen on port 4000~4005 (<Port>4000-4004,4005/udp</Port>)
                This is just a demonstration to show that you can configure the port in several ways
            -->
            <Port>4000/udp</Port>
        </MPEGTS>
        <WebRTC>
            <Signalling>
                <Port>3333</Port>
                <TLSPort>3334</TLSPort>
                <WorkerCount>1</WorkerCount>
            </Signalling>

            <IceCandidates>
                <IceCandidate>*:10000/udp</IceCandidate>
                <!-- 
                    If you want to stream WebRTC over TCP, specify IP:Port for TURN server.
                    This uses the TURN protocol, which delivers the stream from the built-in TURN server to the player's TURN client over TCP. 
                    For detailed information, refer https://airensoft.gitbook.io/ovenmediaengine/streaming/webrtc-publishing#webrtc-over-tcp
                -->
                <TcpRelay>*:3478</TcpRelay>
                <!-- TcpForce is an option to force the use of TCP rather than UDP in WebRTC streaming. (You can omit ?transport=tcp accordingly.) If <TcpRelay> is not set, playback may fail. -->
                <TcpForce>true</TcpForce>
                <TcpRelayWorkerCount>1</TcpRelayWorkerCount>
            </IceCandidates>
        </WebRTC>
    </Providers>

    <Publishers>
        <OVT>
            <Port>9000</Port>
            <WorkerCount>1</WorkerCount>
        </OVT>
        <LLHLS>
            <!-- 
            OME only supports h2, so LLHLS works over HTTP/1.1 on non-TLS ports. 
            LLHLS works with higher performance over HTTP/2, 
            so it is recommended to use a TLS port.
            -->
            <Port>80</Port>
            <!-- If you want to use TLS, specify the TLS port -->
            <TLSPort>443</TLSPort>
            <WorkerCount>1</WorkerCount>
        </LLHLS>
        <WebRTC>
            <Signalling>
                <Port>3333</Port>
                <TLSPort>3334</TLSPort>
                <WorkerCount>1</WorkerCount>
            </Signalling>
            <IceCandidates>
                <IceCandidate>*:10000-10005/udp</IceCandidate>
                <!-- 
                    If you want to stream WebRTC over TCP, specify IP:Port for TURN server.
                    This uses the TURN protocol, which delivers the stream from the built-in TURN server to the player's TURN client over TCP. 
                    For detailed information, refer https://airensoft.gitbook.io/ovenmediaengine/streaming/webrtc-publishing#webrtc-over-tcp
                -->
                <TcpRelay>*:3478</TcpRelay>
                <!-- TcpForce is an option to force the use of TCP rather than UDP in WebRTC streaming. (You can omit ?transport=tcp accordingly.) If <TcpRelay> is not set, playback may fail. -->
                <TcpForce>true</TcpForce>
                <TcpRelayWorkerCount>1</TcpRelayWorkerCount>
            </IceCandidates>
        </WebRTC>
    </Publishers>
</Bind>

    <!--
        Enable this configuration if you want to use API Server

        <AccessToken> is a token for authentication, and when you invoke the API, you must put "Basic base64encode(<AccessToken>)" in the "Authorization" header of HTTP request.
        For example, if you set <AccessToken> to "ome-access-token", you must set "Basic b21lLWFjY2Vzcy10b2tlbg==" in the "Authorization" header.
    -->
    <!--
    <Managers>
        <Host>
            <Names>
                <Name>*</Name>
            </Names>
            <TLS>
                <CertPath>path/to/file.crt</CertPath>
                <KeyPath>path/to/file.key</KeyPath>
                <ChainCertPath>path/to/file.crt</ChainCertPath>
            </TLS>
        </Host>
        <API>
            <AccessToken>ome-access-token</AccessToken>

            <CrossDomains>
                <Url>*.airensoft.com</Url>
                <Url>http://*.sub-domain.airensoft.com</Url>
                <Url>http?://airensoft.*</Url>
            </CrossDomains>
        </API>
    </Managers>
    -->

    <VirtualHosts>
        <!-- You can use wildcard like this to include multiple XMLs -->
        <VirtualHost include="VHost*.xml" />
        <VirtualHost>
            <Name>default</Name>
            <!--Distribution is a value that can be used when grouping the same vhost distributed across multiple servers. This value is output to the events log, so you can use it to aggregate statistics. -->
            <Distribution>ovenmediaengine.com</Distribution>

            <!-- Settings for multi ip/domain and TLS -->
            <Host>
                <Names>
                    <!-- Host names
                        <Name>stream1.airensoft.com</Name>
                        <Name>stream2.airensoft.com</Name>
                        <Name>*.sub.airensoft.com</Name>
                        <Name>192.168.0.1</Name>
                    -->
                    <Name>192.168.1.102</Name>
                </Names>

                <TLS>
                    <CertPath>/opt/ovenmediaengine/bin/edge_conf/cert.crt</CertPath>
                    <KeyPath>/opt/ovenmediaengine/bin/edge_conf/privkey.key</KeyPath>
                    <ChainCertPath>/opt/ovenmediaengine/bin/edge_conf/fullchain.crt</ChainCertPath>
                </TLS>

            </Host>

            <!--    
            Refer https://airensoft.gitbook.io/ovenmediaengine/signedpolicy
            <SignedPolicy>
                <PolicyQueryKeyName>policy</PolicyQueryKeyName>
                <SignatureQueryKeyName>signature</SignatureQueryKeyName>
                <SecretKey>aKq#1kj</SecretKey>

                <Enables>
                    <Providers>rtmp,webrtc,srt</Providers>
                    <Publishers>webrtc,hls,llhls,dash,lldash</Publishers>
                </Enables>
            </SignedPolicy>
            -->

            <!--
            <AdmissionWebhooks>
                <ControlServerUrl></ControlServerUrl>
                <SecretKey></SecretKey>
                <Timeout>3000</Timeout>
                <Enables>
                    <Providers>rtmp,webrtc,srt</Providers>
                    <Publishers>webrtc,hls,llhls,dash,lldash</Publishers>
                </Enables>
            </AdmissionWebhooks>
            -->

            <!-- <Origins>
                <Properties>
                    <NoInputFailoverTimeout>3000</NoInputFailoverTimeout>
                    <UnusedStreamDeletionTimeout>60000</UnusedStreamDeletionTimeout>
                </Properties>
                <Origin>
                    <Location>/app/stream</Location>
                    <Pass>
                        <Scheme>ovt</Scheme>
                        <Urls><Url>origin.com:9000/app/stream_720p</Url></Urls>
                    </Pass>
                    <ForwardQueryParams>false</ForwardQueryParams>
                </Origin>
                <Origin>
                    <Location>/app/</Location>
                    <Pass>
                        <Scheme>ovt</Scheme>
                        <Urls><Url>origin.com:9000/app/</Url></Urls>
                    </Pass>
                </Origin>
                <Origin>
                    <Location>/edge/</Location>
                    <Pass>
                        <Scheme>ovt</Scheme>
                        <Urls><Url>origin.com:9000/app/</Url></Urls>
                    </Pass>
                </Origin>
            </Origins> -->

            <!-- Settings for applications -->
            <Applications>
                <Application>
                    <Name>app</Name>
                    <!-- Application type (live/vod) -->
                    <Type>live</Type>
                    <OutputProfiles>
                        <!-- Enable this configuration if you want to hardware acceleration using GPU -->
                        <HardwareAcceleration>false</HardwareAcceleration>
                        <OutputProfile>
                            <Name>bypass_stream</Name>
                            <OutputStreamName>${OriginStreamName}</OutputStreamName>
                            <Encodes>
                                <Audio>
                                    <Bypass>true</Bypass>
                                </Audio>
                                <Video>
                                    <Bypass>true</Bypass>
                                </Video>
                                <Audio>
                                    <Codec>opus</Codec>
                                    <Bitrate>128000</Bitrate>
                                    <Samplerate>48000</Samplerate>
                                    <Channel>2</Channel>
                                </Audio>
                                <!--                            
                                <Video>
                                    <Codec>vp8</Codec>
                                    <Bitrate>1024000</Bitrate>
                                    <Framerate>30</Framerate>
                                    <Width>1280</Width>
                                    <Height>720</Height>
                                    <Preset>faster</Preset>
                                </Video>
                                -->
                            </Encodes>
                        </OutputProfile>
                    </OutputProfiles>
                    <Providers>
                        <OVT />
                        <WebRTC />
                        <RTMP />
                        <SRT />
                        <MPEGTS>
                            <StreamMap>
                                <!--
                                    Set the stream name of the client connected to the port to "stream_${Port}"
                                    For example, if a client connets to port 4000, OME creates a "stream_4000" stream
                                    <Stream>
                                        <Name>stream_${Port}</Name>
                                        <Port>4000,4001-4004</Port>
                                    </Stream>
                                    <Stream>
                                        <Name>stream_4005</Name>
                                        <Port>4005</Port>
                                    </Stream>
                                -->
                                <Stream>
                                    <Name>stream_${Port}</Name>
                                    <Port>4000</Port>
                                </Stream>
                            </StreamMap>
                        </MPEGTS>
                        <RTSPPull />
                        <WebRTC>
                            <Timeout>30000</Timeout>
                        </WebRTC>
                    </Providers>
                    <Publishers>
                        <AppWorkerCount>1</AppWorkerCount>
                        <StreamWorkerCount>8</StreamWorkerCount>
                        <OVT />
                        <WebRTC>
                            <Timeout>30000</Timeout>
                            <Rtx>false</Rtx>
                            <Ulpfec>false</Ulpfec>
                            <JitterBuffer>false</JitterBuffer>
                        </WebRTC>
                        <LLHLS>
                            <ChunkDuration>0.2</ChunkDuration>
                            <SegmentDuration>6</SegmentDuration>
                            <SegmentCount>10</SegmentCount>
                            <CrossDomains>
                                <Url>*</Url>
                            </CrossDomains>
                        </LLHLS>
                    </Publishers>
                </Application>
            </Applications>
        </VirtualHost>
    </VirtualHosts>
</Server>
getroot commented 1 year ago

Try ws://192.168.1.102:3333/app/stream not wss://192.168.1.102:3333/app/stream

JahzyB commented 1 year ago

When I try that I just get "Can not play due to unknown reasons" and nothing at all in the logs.

getroot commented 1 year ago

upload your entire log file /var/log/ovenmediaengine/ovenmediaengine.log

JahzyB commented 1 year ago

log

getroot commented 1 year ago
JahzyB commented 1 year ago
docker run
  -d
  --name='ovenmediaengine'
  --net='bridge'
  -e TZ="America/New_York"
  -e HOST_OS="Unraid"
  -e HOST_HOSTNAME="host"
  -e HOST_CONTAINERNAME="ovenmediaengine"
  -l net.unraid.docker.managed=dockerman
  -l net.unraid.docker.icon='https://www.gitbook.com/cdn-cgi/image/width=40,height=40,fit=contain,dpr=1,format=auto/https%3A%2F%2F3312312173-files.gitbook.io%2F~%2Ffiles%2Fv0%2Fb%2Fgitbook-legacy-files%2Fo%2Fspaces%252F-Lcd00MyPtgKKaEeNUki%252Favatar-1606304387707.png%3Fgeneration%3D1606304387898170%26alt%3Dmedia'
  -p '1935:1935/tcp'
  -p '3333:3333/tcp'
  -p '3334:3334/tcp'
  -p '3478:3478/tcp'
  -p '9000:9000/tcp'
  -p '9999:9999/udp'
  -p '4000:4000/udp'
  -v '/mnt/user/appdata/ovenmediaengine/origin_conf':'/opt/ovenmediaengine/bin/origin_conf':'rw'
  -v '/mnt/user/appdata/ovenmediaengine/edge_conf':'/opt/ovenmediaengine/bin/edge_conf':'rw'
  -v '/mnt/user/appdata/ovenmediaengine/logs':'/opt/ovenmediaengine/bin/logs':'rw' 'airensoft/ovenmediaengine'
JahzyB commented 1 year ago

I think I may be doing something dumb with my nginx config. I have 443 in my nginx docker container mapped to 444 on the host and 80 in the container to 83 on the host. Then I've got this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test</title>
</head>

<body>
    <!-- OvenPlayer will be initialized inside this element. -->
    <div id="player_id"></div>

    <!-- Load OvenPlayer via CDN -->
    <script src="https://cdn.jsdelivr.net/npm/ovenplayer/dist/ovenplayer.js"></script>

    <script>

        // Initialize OvenPlayer
        const player = OvenPlayer.create('player_id', {
            sources: [
                {
                    label: 'label_for_webrtc',
                    // Set the type to 'webrtc'
                    type: 'webrtc',
                    // Set the file to WebRTC Signaling URL with OvenMediaEngine 
                    file: 'ws://192.168.1.102:3333/app/stream'
                }
            ]
        });
    </script>
</body>

</html>

set up in my /config/www in the nginx container. In the nginx config I've got traffic redirect to https set up so I assumed that if I go to the host's IP:444 I should get the stream. When I go there I see OvenPlayer with "Can not play due to unknown reasons" and have got nothing showing in the logs.

Now if I change file: 'ws://192.168.1.102:3333/app/stream' to file: 'wss://192.168.1.102:3333/app/stream' or file: 'wss://192.168.1.102:3334/app/stream' then I do see something in the logs. I get what I posted up above:

file: 'wss://192.168.1.102:3333/app/stream' - [2023-02-02 19:12:56.699] E [SPRtcSig-T3333:10] HttpServer | http_transaction.cpp:163  | Invalid parse status: 400

file: 'wss://192.168.1.102:3334/app/stream' - [2023-02-02 19:13:21.455] E [SPRtcSig-T3334:12] OpenSSL | tls.cpp:193  | An error occurred while accept SSL connection: [OpenSSL] error:0A000412:SSL routines::sslv3 alert bad certificate (167773202)

The end state I'm looking for here is for me to be able to stream from OBS on my PC to the server I have set up on a separate host locally and then be able to access the stream externally by going to my public domain.

getroot commented 1 year ago

You should use a URL like this: ws://192.168.1.102:3333/app/stream or wss://domain:3334/app/stream (domain must be associated with certificate)

I don't understand your nginx related explanation.

Does the problem reproduce on demo.ovenplayer.com? If playback works fine on demo.ovenplayer.com, try the following.

Try replacing <Bind><Publishers><WebRTC><IceCandidates><TcpRelay>*:3478 to <Bind><Publishers><WebRTC><IceCandidates><TcpRelay>192.168.1.102:3478 in the Server.xml.

JahzyB commented 1 year ago

Now I'm actually seeing a connection in the logs being formed when I go to mydomain.com. I'm not actually seeing anything playing in the player, though. In the Firefox console I see WebRTC: ICE failed, add a STUN server and see about:webrtc for more details.. When I go there it looks like it tried to connect to one of the ICE ports 10000-10005 and it failed. I'm seeing "IcePort is disconnected" in the logs.

I see when I start the server that it does resolve the public IP address from the STUN server so I'm not sure what the issue is now. I checked in Edge and Chrome and it's just a black screen as well but in those browsers it shows the red circle and "Sub-Second Latency Streaming" by the play button. When I stop streaming from OBS the log does show in the statistics that bytes were sent out. I'm just seeing a black screen, though.

Current config:

<?xml version="1.0" encoding="UTF-8"?>
<Server version="8">
        <Name>OvenMediaEngine</Name>
        <Type>origin</Type>
        <IP>*</IP>
        <PrivacyProtection>false</PrivacyProtection>
        <StunServer>stun.l.google.com:19302</StunServer>
        <Modules>
                <HTTP2>
                        <Enable>true</Enable>
                </HTTP2>
                <LLHLS>
                        <Enable>false</Enable>
                </LLHLS>
                <P2P>
                        <Enable>false</Enable>
                        <MaxClientPeersPerHostPeer>2</MaxClientPeersPerHostPeer>
                </P2P>
        </Modules>
        <Bind>
                <Providers>
                        <RTMP>
                                <Port>1935</Port>
                                <WorkerCount>1</WorkerCount>
                        </RTMP>
                        <WebRTC>
                                <Signalling>
                                        <Port>3333</Port>
                                        <TLSPort>3334</TLSPort>
                                        <WorkerCount>1</WorkerCount>
                                </Signalling>
                                <IceCandidates>
                                        <TcpRelay>*:3478</TcpRelay>
                                        <IceCandidate>*:10000-10005/udp</IceCandidate>
                                        <TcpForce>false</TcpForce>
                                        <TcpRelayWorkerCount>1</TcpRelayWorkerCount>
                                </IceCandidates>
                        </WebRTC>
                </Providers>
                <Publishers>
                        <WebRTC>
                                <Signalling>
                                        <Port>3333</Port>
                                        <TLSPort>3334</TLSPort>
                                        <WorkerCount>1</WorkerCount>
                                </Signalling>
                                <IceCandidates>
                                        <IceCandidate>*:10000-10005/udp</IceCandidate>
                                        <TcpRelay>*:3478</TcpRelay>
                                        <TcpForce>false</TcpForce>
                                        <TcpRelayWorkerCount>1</TcpRelayWorkerCount>
                                </IceCandidates>
                        </WebRTC>
                </Publishers>
        </Bind>
        <VirtualHosts>
            <VirtualHost>
                <Name>mydomain.com</Name>
                <Distribution>mydomain.com</Distribution>
                <Host>
                        <Names>
                            <Name>mydomain.com</Name>
                            <Name>www.mydomain.com</Name>
                        </Names>
                        <TLS>
                            <CertPath>/opt/ovenmediaengine/bin/certs/letsencrypt/live/mydomain.com/cert.pem</CertPath>
                            <KeyPath>/opt/ovenmediaengine/bin/certs/letsencrypt/live/mydomain.com/privkey.pem</KeyPath>
                            <ChainCertPath>/opt/ovenmediaengine/bin/certs/letsencrypt/live/mydomain.com/priv-fullchain-bundle.pem</ChainCertPath>
                        </TLS>
                </Host>
            <Applications>
                <Application>
                    <Name>app</Name>
                    <Type>live</Type>
                    <OutputProfiles>
                        <HardwareAcceleration>false</HardwareAcceleration>
                        <OutputProfile>
                            <Name>bypass_stream</Name>
                            <OutputStreamName>${OriginStreamName}</OutputStreamName>
                            <Encodes>
                                <Video>
                                    <Bypass>true</Bypass>
                                </Video>
                                <Audio>
                                    <Bypass>true</Bypass>
                                </Audio>
                            </Encodes>
                        </OutputProfile>
                    </OutputProfiles>
                    <Providers>
                        <OVT />
                        <WebRTC />
                        <RTMP />
                        <SRT />
                        <MPEGTS />
                        <RTSPPull />
                        <WebRTC>
                                <Timeout>30000</Timeout>
                        </WebRTC>
                    </Providers>
                    <Publishers>
                        <AppWorkerCount>1</AppWorkerCount>
                        <StreamWorkerCount>8</StreamWorkerCount>
                        <OVT />
                        <WebRTC>
                            <Timeout>30000</Timeout>
                            <Rtx>false</Rtx>
                            <Ulpfec>false</Ulpfec>
                            <JitterBuffer>false</JitterBuffer>
                        </WebRTC>
                    </Publishers>
                </Application>
            </Applications>
        </VirtualHost>
    </VirtualHosts>
</Server>
getroot commented 1 year ago
  1. Add -p 10000-10005:10000-10005/udp parameter when running docker, or
  2. Try playing with ws://ip:port/app/stream?transport=tcp or
  3. Set <Publishers><WebRTC><IceCandidates><TcpForce> to true.
JahzyB commented 1 year ago
  1. Add -p 10000-10005:10000-10005/udp parameter when running docker, or

That did it! Finally got it working. Thanks for all your help.

Actually it worked for just a little bit and now it's back to just showing a black screen with a play button. I didn't change anything outside of your recommendation and it stopped working after a couple of viewers went to the stream. Anything that could make it suddenly just black screen like that after working properly?

getroot commented 1 year ago

Try with WebRTC/tcp as well. You can choose either 2 or 3. You should upload a log file after such a problem occurs so we can further analyze your problem. Problems like yours have never been reported other than network issues.

JahzyB commented 1 year ago

I attached logs from around when it happened. I just tried the tcpforce option and it didn't resolve the issue.

getroot commented 1 year ago

This is obviously the player not being able to connect to your server 108.xxx.xxx.xx2:3478 or 108.xxx.xxx.xx2:10000/udp. Check the firewall or network side. Can external players access your 108.xxx.xxx.xx2:3478?

JahzyB commented 1 year ago

Okay, I just messed up some settings in my firewall. Thanks for all your help! Could you possibly delete your screenshot above since it contains my domain that I had not intended on publicizing at this time? I appreciate it!