mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-09-26 20:31:11 +08:00
Add /api/ffmpeg for playing files and tts on cameras with two-way audio
This commit is contained in:
51
internal/ffmpeg/api.go
Normal file
51
internal/ffmpeg/api.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package ffmpeg
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/internal/streams"
|
||||
)
|
||||
|
||||
func apiFFmpeg(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
query := r.URL.Query()
|
||||
dst := query.Get("dst")
|
||||
stream := streams.Get(dst)
|
||||
if stream == nil {
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var src string
|
||||
if s := query.Get("file"); s != "" {
|
||||
if streams.Validate(s) == nil {
|
||||
src = "ffmpeg:" + s + "#audio=auto#input=file"
|
||||
}
|
||||
} else if s = query.Get("live"); s != "" {
|
||||
if streams.Validate(s) == nil {
|
||||
src = "ffmpeg:" + s + "#audio=auto"
|
||||
}
|
||||
} else if s = query.Get("text"); s != "" {
|
||||
if strings.IndexAny(s, `'"&%$`) < 0 {
|
||||
src = "ffmpeg:tts?text=" + s
|
||||
if s = query.Get("voice"); s != "" {
|
||||
src += "&voice=" + s
|
||||
}
|
||||
src += "#audio=auto"
|
||||
}
|
||||
}
|
||||
|
||||
if src == "" {
|
||||
http.Error(w, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := stream.Play(src); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/internal/api"
|
||||
"github.com/AlexxIT/go2rtc/internal/app"
|
||||
"github.com/AlexxIT/go2rtc/internal/ffmpeg/device"
|
||||
"github.com/AlexxIT/go2rtc/internal/ffmpeg/hardware"
|
||||
@@ -40,6 +41,8 @@ func Init() {
|
||||
|
||||
streams.HandleFunc("ffmpeg", NewProducer)
|
||||
|
||||
api.HandleFunc("api/ffmpeg", apiFFmpeg)
|
||||
|
||||
device.Init(defaults["bin"])
|
||||
hardware.Init(defaults["bin"])
|
||||
}
|
||||
|
@@ -85,16 +85,21 @@
|
||||
|
||||
<div>
|
||||
<h2>Play audio</h2>
|
||||
<pre>example: ffmpeg:https://example.com/song.mp3#audio=pcma#input=file</pre>
|
||||
<input id="play-url" type="text" placeholder="url">
|
||||
<label><input type="radio" name="play" value="file" checked>file - play remote (https://example.com/song.mp3) or local (/media/song.mp3) file</label><br>
|
||||
<label><input type="radio" name="play" value="live">live - play remote live stream (radio, etc.)</label><br>
|
||||
<label><input type="radio" name="play" value="text">text - play Text To Speech (if your FFmpeg support this)</label><br>
|
||||
<br>
|
||||
<input id="play-url" type="text" placeholder="path / url / text">
|
||||
<a id="play-send" href="#">send</a> / cameras with two way audio support
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('play-send').addEventListener('click', ev => {
|
||||
ev.preventDefault();
|
||||
const url = new URL('api/streams', location.href);
|
||||
// action - file / live / text
|
||||
const action = document.querySelector('input[name="play"]:checked').value;
|
||||
const url = new URL('api/ffmpeg', location.href);
|
||||
url.searchParams.set('dst', src);
|
||||
url.searchParams.set('src', document.getElementById('play-url').value);
|
||||
url.searchParams.set(action, document.getElementById('play-url').value);
|
||||
fetch(url, {method: 'POST'});
|
||||
});
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user