Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.idea/
.tmp/

go2rtc
go2rtc.yaml
go2rtc.json

Expand All @@ -12,3 +13,7 @@ go2rtc_win*
0_test.go

.DS_Store

*.mp3
*.wav
*.al
103 changes: 103 additions & 0 deletions fix_vto_codecs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/bin/bash
#
# This script fixes the VTO audio codecs before supplying the stream url to go2rtc.
#
# Usage: ./fix_vto_codecs.sh [--debug] [--https] <VTO stream URL>
#
# Examples:
#
# ./fix_vto_codecs.sh rtsp://user:[email protected]/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
# ./fix_vto_codecs.sh rtsp://user:[email protected]/cam/realmonitor?channel=1&subtype=1
#
# If the VTO has HTTPS enabled:
# ./fix_vto_codecs.sh --https rtsp://user:[email protected]/cam/realmonitor?channel=1&subtype=0
#
# With ffmpeg prefix:
# ./fix_vto_codecs.sh ffmpeg:rtsp://user:[email protected]/cam/realmonitor?channel=1&subtype=0#video=copy#audio=copy
#

set -euo pipefail

usage() {
echo "Usage: ${0} [--debug] [--https] <VTO stream URL>" >&2
exit "${1}"
}

debug=false
protocol="http"
extra_curl_args=()

positional_args=()
while [[ $# -gt 0 ]]; do
case $1 in
--debug)
debug=true
shift
;;
--https)
protocol="https"
extra_curl_args+=("--insecure")
shift
;;
-*)
echo "Unknown option ${1}" >&2
usage 1
;;
*)
positional_args+=("$1")
shift
;;
esac
done

set -- "${positional_args[@]}"
unset positional_args

if [[ $# -ne 1 ]]; then
echo "Expected 1 positional argument, got $#" >&2
usage 1
fi

vto_stream_url="${1}"

if [[ "${vto_stream_url}" != "rtsp://"* && "${vto_stream_url}" != "ffmpeg:rtsp://"* ]]; then
echo "VTO stream URL does not start with rtsp:// or ffmpeg:rtsp://" >&2
usage 1
fi

if [[ "${debug}" == "true" ]]; then
set -x
extra_curl_args+=("--verbose")
fi

vto_host_with_creds="${vto_stream_url#"ffmpeg:"}"
vto_host_with_creds="${vto_host_with_creds#"rtsp://"}"
vto_host_with_creds="${vto_host_with_creds%%"/"*}"
if [[ "${vto_host_with_creds}" =~ :[0-9]+$ ]]; then
vto_host_with_creds="${vto_host_with_creds%":"*}"
fi

query="action=setConfig"
# PCMA: average audio quality, but good for WebRTC and 2-way audio
query+="&Encode[0].MainFormat[0].Audio.Compression=G.711A"
# 16000Hz yields better audio quality, but try 8000Hz if your VTO does not support it
query+="&Encode[0].MainFormat[0].Audio.Frequency=8000"
# AAC: best audio quality, good for Frigate recordings
query+="&Encode[0].ExtraFormat[0].Audio.Compression=AAC"

# PS: the current config can be retrieved with:
# curl -fsSL --digest --globoff \
# http://user:[email protected]/cgi-bin/configManager.cgi?action=getConfig&name=Encode

output=$(
curl --fail --silent --show-error --digest --globoff "${extra_curl_args[@]}" \
"${protocol}://${vto_host_with_creds}/cgi-bin/configManager.cgi?${query}"
)

if [[ "${output}" != $'OK\r' ]]; then
echo "Failed to set VTO codecs. Response:" >&2
echo "${output}" >&2
exit 1
fi

echo -n "${vto_stream_url}"
13 changes: 13 additions & 0 deletions internal/dahua/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dahua

import (
"github.com/AlexxIT/go2rtc/internal/streams"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/dahua"
)

func Init() {
streams.HandleFunc("dahua", func(source string) (core.Producer, error) {
return dahua.Dial(source)
})
}
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/AlexxIT/go2rtc/internal/api/ws"
"github.com/AlexxIT/go2rtc/internal/app"
"github.com/AlexxIT/go2rtc/internal/bubble"
"github.com/AlexxIT/go2rtc/internal/dahua"
"github.com/AlexxIT/go2rtc/internal/debug"
"github.com/AlexxIT/go2rtc/internal/doorbird"
"github.com/AlexxIT/go2rtc/internal/dvrip"
Expand Down Expand Up @@ -84,6 +85,7 @@ func main() {
dvrip.Init() // dvrip source
tapo.Init() // tapo source
isapi.Init() // isapi source
dahua.Init() // dahua source
mpegts.Init() // mpegts passive source
roborock.Init() // roborock source
homekit.Init() // homekit source
Expand Down
154 changes: 154 additions & 0 deletions pkg/dahua/CGI_SDK_API.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
11. Audio

11.1 Audio MIME type

MIME Description
Audio/PCM
Audio/ADPCM
Audio/G.711A
Audio/G.711Mu
Audio/G.726
Audio/G.729

92
Audio/MPEG2
Audio/AMR
Audio/AAC



11.2 Post Audio

URL Syntax http://<ip>/cgi-bin/audio.cgi?action=postAudio&<paramName>=<paramValue>[&<paramName>=<paramValue>...]
Comment paramValue as below table.
Response OK or ERROR


ParamName ParamValue type Description
httptype string singlepart:HTTP content is a continuous flow of audio
packets
multipart:HTTP content type is
multipart/x-mixed-replace,and each audio packet ends
with a boundary string
channel integer The audio channel



11.2.1 Example for singlepart

The RUL of transmit a singlepart、channel 1 audio stream(encoded with G.711 A-law) is:
http: //<ip>/cgi-bin/audio.cgi?action=postAudio&httptype=singlepart&channel=1


example:
POST /cgi-bin/audio.cgi?action=postAudio&httptype=singlepart&channel=1 HTTP/1.1
Content-Type: Audio/G.711A
Content-Length:9999999


<Audio data>
<Audio data>



11.2.2 Example for multipart

The RUL of transmit a multipart、channel 1 audio stream(encoded with G.711 A-law) is:
http: //<ip>/cgi-bin/audio.cgi?action=postAudio&httptype= multipart &channel=1


example:
POST /cgi-bin/audio.cgi?action=postAudio&httptype= multipart &channel=1 HTTP/1.1
Content-Type: multipart/x-mixed-replace; boundary=<boundary>
--<boundary>
Content-Type: Audio/G.711A

93
Content-Length: 800


<Audio data>
--<boundary>



11.3 Get Audio

URL Syntax http://<ip>/cgi-bin/audio.cgi?action=getAudio&<paramName>=<paramValue>[&<paramName>=<paramValue>...]
Comment paramValue as below table.
Response OK or ERROR




ParamName ParamValue type Description
httptype string singlepart:HTTP content is a continuous flow of audio
packets
multipart:HTTP content type is
multipart/x-mixed-replace,and each audio packet ends
with a boundary string
channel integer The audio channel




11.3.1 Example for singlepart

The RUL of Request a singlepart、channel 1 audio stream(encoded with G.711 A-law) is:
http: //<ip>/cgi-bin/audio.cgi?action=getAudio&httptype=singlepart&channel=1


If the request was successful, the server returns a continuous flow of audio packets.The content type is only set at the beginning of the
connection.
Return:
HTTP Code: 200 OK
Content-Type: Audio/G.711A
Body:
<Audio data>
<Audio data>



11.3.2 Example for multipart

The RUL of Request a multipart、channel 1 audio stream(encoded with G.711 A-law) is:
http: //<ip>/cgi-bin/audio.cgi?action=getAudio&httptype=multipart&channel=1


If the request was successful, the server returns a continuous flow of audio packets. The content type is “multipart/x-mixed-replace” and each
audio packet ends with a boundary string.
94
Return:
HTTP Code: 200 OK
Content-Type: multipart/x-mixed-replace; boundary=<boundary>
--<boundary>
Content-Type: Audio/G.711A
Content-Length: 800


<Audio data>
--<boundary>




11.4 Audio Input

11.4.1 getCollect

URL Syntax http://<ip>/cgi-bin/devAudioInput.cgi?action=getCollect
Comment Get Audio input channel number.
Below response means there are 2 audio input channels.
Response result=2




11.5 Audio Output

11.5.1 getCollect

URL Syntax http://<ip>/cgi-bin/devAudioOutput.cgi?action=getCollect
Comment Get Audio output channel number.
Below response means there are 2 audio output channels.
Response result=2
Loading