Skip to content

Commit

Permalink
fix: support external RTSP servers using RtspServerMode (#270)
Browse files Browse the repository at this point in the history
Signed-off-by: Marc-Philippe Fuller <[email protected]>
Signed-off-by: Anthony Casagrande <[email protected]>
Co-authored-by: Anthony Casagrande <[email protected]>
  • Loading branch information
marcpfuller and ajcasagrande authored Sep 6, 2023
1 parent 626ade4 commit 0836578
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 38 deletions.
4 changes: 3 additions & 1 deletion cmd/res/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ Device:
Interval: "1h"

Driver:
EnableRtspServer: "true"
# RtspServerMode can be "internal", "external", or "none". Default is "internal" if left blank.
RtspServerMode: "internal"
RtspServerExecutable: "./rtsp-simple-server"
RtspServerHostName: "localhost"
RtspTcpPort: "8554"
RtspAuthenticationServer: "localhost:8000"
3 changes: 0 additions & 3 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
#!/usr/bin/dumb-init /bin/sh

echo "Run rtsp-simple-server..."
/rtsp-simple-server &

echo "Run device-usb-camera..."
/device-usb-camera $@
5 changes: 3 additions & 2 deletions internal/driver/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ const (
AutoStreaming = "AutoStreaming"
InputIndex = "InputIndex"
UrlRawQuery = "urlRawQuery"
EnableRtspServer = "EnableRtspServer"
RtspServerCmd = "./rtsp-simple-server"
RtspServerMode = "RtspServerMode"
RtspServerExe = "RtspServerExecutable"
RtspServerExeDefault = "./rtsp-simple-server"
RtspServerHostName = "RtspServerHostName"
DefaultRtspServerHostName = "localhost"
RtspTcpPort = "RtspTcpPort"
Expand Down
82 changes: 50 additions & 32 deletions internal/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ type Driver struct {
rtspAuthenticationServerUri string
mutex sync.Mutex
rtspAuthServer *echo.Echo
enableRtspServer bool
rtspServerMode RTSPServerMode
}

// NewProtocolDriver initializes the singleton Driver and returns it to the caller
Expand Down Expand Up @@ -115,12 +115,36 @@ func (d *Driver) Initialize(sdk interfaces.DeviceServiceSDK) error {
}

var err error
d.enableRtspServer, err = strconv.ParseBool(d.ds.DriverConfigs()[EnableRtspServer])
if err != nil {
return fmt.Errorf("failed to parse EnableRtspServer config: %s", err.Error())
// if RtspServerMode config parameter is empty, then it should default to
// "internal" to retain backwards-compatibility
d.rtspServerMode = RTSPServerMode(strings.ToLower(d.ds.DriverConfigs()[RtspServerMode]))
if d.rtspServerMode == "" {
d.rtspServerMode = RTSPServerModeInternal
} else {
if d.rtspServerMode != RTSPServerModeInternal && d.rtspServerMode != RTSPServerModeExternal {
return fmt.Errorf("%s value of \"%s\" is invalid. valid options are \"internal\", \"external\", and \"none\"",
RtspServerMode, d.rtspServerMode)
}
}
if !d.enableRtspServer {
return nil

if d.rtspServerMode == RTSPServerModeNone {
return nil // nothing left to do
}

rtspAuthenticationServerUri, ok := d.ds.DriverConfigs()[RtspAuthenticationServer]
if !ok {
rtspAuthenticationServerUri = DefaultRtspAuthenticationServer
d.lc.Warnf("service config %s not found. Use the default value: %s", RtspAuthenticationServer, DefaultRtspAuthenticationServer)
}
d.lc.Infof("RtspAuthenticationServer: %s", rtspAuthenticationServerUri)
d.rtspAuthenticationServerUri = rtspAuthenticationServerUri

if err := d.ds.SecretProvider().RegisterSecretUpdatedCallback(rtspAuthSecretName, d.secretUpdated); err != nil {
d.lc.Errorf("failed to register secret update callback: %v", err)
}

if d.rtspServerMode != RTSPServerModeInternal {
return nil // nothing left to do
}

rtspServerHostName, ok := d.ds.DriverConfigs()[RtspServerHostName]
Expand All @@ -139,35 +163,29 @@ func (d *Driver) Initialize(sdk interfaces.DeviceServiceSDK) error {
d.lc.Infof("RTSP TCP port: %s", rtspPort)
d.rtspTcpPort = rtspPort

rtspAuthenticationServerUri, ok := d.ds.DriverConfigs()[RtspAuthenticationServer]
if !ok {
rtspAuthenticationServerUri = DefaultRtspAuthenticationServer
d.lc.Warnf("service config %s not found. Use the default value: %s", RtspAuthenticationServer, DefaultRtspAuthenticationServer)
}
d.lc.Infof("RtspAuthenticationServer: %s", rtspAuthenticationServerUri)
d.rtspAuthenticationServerUri = rtspAuthenticationServerUri

if err := d.ds.SecretProvider().RegisterSecretUpdatedCallback(rtspAuthSecretName, d.secretUpdated); err != nil {
d.lc.Errorf("failed to register secret update callback: %v", err)
}

// check to see if rtsp-simple-server file/binary exists
_, err = os.Stat(RtspServerCmd)
rtspExecutable := d.ds.DriverConfigs()[RtspServerExe]
if rtspExecutable == "" {
// to ensure backwards compatibility
rtspExecutable = RtspServerExeDefault
}
_, err = os.Stat(rtspExecutable)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("%s file cannot be found: %s", RtspServerCmd, err.Error())
return fmt.Errorf("%s file cannot be found: %s", RtspServerExe, err.Error())
} else if os.IsPermission(err) {
return fmt.Errorf("permission denied for %s: %s", RtspServerCmd, err.Error())
return fmt.Errorf("permission denied for %s: %s", RtspServerExe, err.Error())
} else {
return fmt.Errorf("unknown error occurred while checking for rtsp-server binary file %s: %s", RtspServerCmd, err.Error())
return fmt.Errorf("unknown error occurred while checking for rtsp-server binary file %s: %s", rtspExecutable, err.Error())
}
}

rtspProc := exec.Command(RtspServerCmd)
rtspProc := exec.Command(rtspExecutable)
rtspProc.Stdout = os.Stdout
rtspProc.Stderr = os.Stderr
err = rtspProc.Start()
if err != nil {
return fmt.Errorf("unable to start %s process: %s", RtspServerCmd, err.Error())
return fmt.Errorf("unable to start %s process: %s", rtspExecutable, err.Error())
}

return nil
Expand All @@ -188,8 +206,8 @@ func (d *Driver) Start() error {
// Make sure the paths of existing devices are up-to-date.
go d.RefreshAllDevicePaths()

if !d.enableRtspServer {
d.lc.Info("Rtsp server is disabled")
if d.rtspServerMode == RTSPServerModeNone {
d.lc.Info("RTSP server is disabled")
return nil
}

Expand Down Expand Up @@ -404,13 +422,13 @@ func (d *Driver) ExecuteReadCommands(device *Device, req sdkModels.CommandReques
}
cv, err = sdkModels.NewCommandValue(req.DeviceResourceName, common.ValueTypeObject, data)
case VideoStreamUri:
if !d.enableRtspServer {
if d.rtspServerMode == RTSPServerModeNone {
return nil, errors.NewCommonEdgeX(errors.KindServerError, fmt.Sprintf(
"rtsp server is not enabled, cannot get stream URI for device %s", device.name), nil)
}
cv, err = sdkModels.NewCommandValue(req.DeviceResourceName, req.Type, device.rtspUri)
case VideoStreamingStatus:
if !d.enableRtspServer {
if d.rtspServerMode == RTSPServerModeNone {
return nil, errors.NewCommonEdgeX(errors.KindServerError, fmt.Sprintf(
"rtsp server is not enabled, cannot get streaming status for device %s", device.name), nil)
}
Expand Down Expand Up @@ -495,7 +513,7 @@ func (d *Driver) ExecuteWriteCommands(device *Device, req sdkModels.CommandReque
return errors.NewCommonEdgeXWrapper(edgexErr)
}
case VideoStopStreaming:
if !d.enableRtspServer {
if d.rtspServerMode == RTSPServerModeNone {
return errors.NewCommonEdgeX(errors.KindServerError, fmt.Sprintf(
"rtsp server is not enabled, cannot stop streaming for device %s", device.name), nil)
}
Expand Down Expand Up @@ -556,7 +574,7 @@ func (d *Driver) Stop(force bool) error {
// The call to Wait() waits for StopStreaming to return and startStreaming to end.
defer d.wg.Wait()

if !d.enableRtspServer {
if d.rtspServerMode == RTSPServerModeNone {
return nil
}

Expand Down Expand Up @@ -692,7 +710,7 @@ func (d *Driver) RemoveDevice(deviceName string, protocols map[string]models.Pro
d.mutex.Lock()
defer d.mutex.Unlock()
if device, ok := d.activeDevices[deviceName]; ok {
if d.enableRtspServer {
if d.rtspServerMode != RTSPServerModeNone {
device.StopStreaming()
}
delete(d.activeDevices, deviceName)
Expand Down Expand Up @@ -981,7 +999,7 @@ func (d *Driver) getDevice(name string) (*Device, errors.EdgeX) {

func (d *Driver) startStreaming(device *Device) errors.EdgeX {
// check to see if rtsp server is enabled
if !d.enableRtspServer {
if d.rtspServerMode == RTSPServerModeNone {
return errors.NewCommonEdgeX(errors.KindServerError, fmt.Sprintf(
"rtsp server is not enabled, cannot start streaming for device %s", device.name), nil)
}
Expand Down
8 changes: 8 additions & 0 deletions internal/driver/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ package driver

import "github.com/vladimirvivien/go4vl/v4l2"

type RTSPServerMode string

const (
RTSPServerModeInternal RTSPServerMode = "internal"
RTSPServerModeExternal RTSPServerMode = "external"
RTSPServerModeNone RTSPServerMode = "none"
)

type RTSPAuthRequest struct {
IP string `json:"ip"`
User string `json:"user"`
Expand Down

0 comments on commit 0836578

Please sign in to comment.