mirror of
https://github.com/m1k1o/neko.git
synced 2025-07-19 09:37:50 +02:00
Add ability to restart broadcast
This commit is contained in:
parent
a5830dc440
commit
acc3c286a1
10 changed files with 60 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
||||||
ARG BASE_IMAGE=m1k1o/neko:base
|
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/nvidia-base:latest
|
||||||
FROM $BASE_IMAGE
|
FROM $BASE_IMAGE
|
||||||
|
|
||||||
ARG SRC_URL="https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US"
|
ARG SRC_URL="https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US"
|
||||||
|
|
|
@ -33,13 +33,6 @@ RUN go mod download
|
||||||
COPY server/ .
|
COPY server/ .
|
||||||
RUN ./build
|
RUN ./build
|
||||||
|
|
||||||
FROM ghcr.io/m1k1o/neko/intel-firefox:latest
|
FROM cave-firefox:latest
|
||||||
|
|
||||||
RUN set -eux; apt-get update; \
|
|
||||||
apt-get install -y --no-install-recommends intel-media-va-driver-non-free i965-va-driver-shaders; \
|
|
||||||
#
|
|
||||||
# clean up
|
|
||||||
apt-get clean -y; \
|
|
||||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
|
||||||
|
|
||||||
COPY --from=server /src/bin/neko /usr/bin/neko
|
COPY --from=server /src/bin/neko /usr/bin/neko
|
||||||
|
|
|
@ -10,10 +10,16 @@ services:
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "host.docker.internal:host-gateway"
|
- "host.docker.internal:host-gateway"
|
||||||
volumes:
|
volumes:
|
||||||
- ./bin/firefox:/home/neko/.mozilla/firefox
|
- ./bin/home/neko:/home/neko
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri/renderD128:/dev/dri/renderD128
|
- /dev/dri:/dev/dri
|
||||||
- /dev/dri/card0:/dev/dri/card0
|
deploy:
|
||||||
|
resources:
|
||||||
|
reservations:
|
||||||
|
devices:
|
||||||
|
- driver: nvidia
|
||||||
|
count: 1
|
||||||
|
capabilities: [gpu]
|
||||||
privileged: true
|
privileged: true
|
||||||
environment:
|
environment:
|
||||||
NEKO_SCREEN: 1920x1080@60
|
NEKO_SCREEN: 1920x1080@60
|
||||||
|
@ -23,4 +29,5 @@ services:
|
||||||
NEKO_ICELITE: 1
|
NEKO_ICELITE: 1
|
||||||
NEKO_BROADCAST_URL: rtmp://ome.thuan.au:1935/app/stream-neko
|
NEKO_BROADCAST_URL: rtmp://ome.thuan.au:1935/app/stream-neko
|
||||||
NEKO_NAT1TO1: 192.168.0.34
|
NEKO_NAT1TO1: 192.168.0.34
|
||||||
NEKO_HWENC:
|
NEKO_HWENC: NVENC
|
||||||
|
NEKO_VIDEO_CODEC: h264
|
||||||
|
|
|
@ -14,9 +14,10 @@ type BroacastManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
pipeline *gst.Pipeline
|
pipeline *gst.Pipeline
|
||||||
pipelineMu sync.Mutex
|
pipelineMu sync.Mutex
|
||||||
pipelineFn func(url string) (string, error)
|
pipelineFn func(url string) (string, error)
|
||||||
|
pipelineRestart chan bool
|
||||||
|
|
||||||
url string
|
url string
|
||||||
started bool
|
started bool
|
||||||
|
@ -29,10 +30,11 @@ func broadcastNew(pipelineFn func(url string) (string, error), defaultUrl string
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
return &BroacastManagerCtx{
|
return &BroacastManagerCtx{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
pipelineFn: pipelineFn,
|
pipelineFn: pipelineFn,
|
||||||
url: defaultUrl,
|
pipelineRestart: make(chan bool),
|
||||||
started: defaultUrl != "",
|
url: defaultUrl,
|
||||||
|
started: defaultUrl != "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +73,10 @@ func (manager *BroacastManagerCtx) Started() bool {
|
||||||
return manager.started
|
return manager.started
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (manager *BroacastManagerCtx) GetRestart() chan bool {
|
||||||
|
return manager.pipelineRestart
|
||||||
|
}
|
||||||
|
|
||||||
func (manager *BroacastManagerCtx) Url() string {
|
func (manager *BroacastManagerCtx) Url() string {
|
||||||
manager.mu.Lock()
|
manager.mu.Lock()
|
||||||
defer manager.mu.Unlock()
|
defer manager.mu.Unlock()
|
||||||
|
|
|
@ -53,6 +53,25 @@ func (manager *CaptureManagerCtx) Start() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
_, ok := <-manager.broadcast.GetRestart()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !manager.broadcast.Started() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.broadcast.destroyPipeline()
|
||||||
|
err := manager.broadcast.createPipeline()
|
||||||
|
if err != nil && !errors.Is(err, types.ErrCapturePipelineAlreadyExists) {
|
||||||
|
manager.logger.Panic().Err(err).Msg("unable to recreate broadcast pipeline")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
before, ok := <-manager.desktop.GetScreenSizeChangeChannel()
|
before, ok := <-manager.desktop.GetScreenSizeChangeChannel()
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
videoSrc = "ximagesrc display-name=%s show-pointer=true use-damage=false ! video/x-raw,framerate=%d/1 ! vaapipostproc ! queue ! "
|
videoSrc = "ximagesrc display-name=%s show-pointer=true use-damage=false ! video/x-raw,framerate=%d/1 ! videoconvert ! queue ! "
|
||||||
audioSrc = "pulsesrc device=%s ! audio/x-raw,channels=2 ! audioconvert ! "
|
audioSrc = "pulsesrc device=%s ! audio/x-raw,channels=2 ! audioconvert ! "
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,7 +47,8 @@ func NewBroadcastPipeline(device string, display string, pipelineSrc string, url
|
||||||
// replace display
|
// replace display
|
||||||
pipelineStr = strings.Replace(pipelineStr, "{display}", display, -1)
|
pipelineStr = strings.Replace(pipelineStr, "{display}", display, -1)
|
||||||
} else {
|
} else {
|
||||||
pipelineStr = fmt.Sprintf("flvmux name=mux ! rtmpsink location='%s live=1' %s audio/x-raw,channels=2 ! audioconvert ! voaacenc ! mux. %s video/x-raw,format=NV12 ! vaapih264enc rate-control=cbr bitrate=%d keyframe-period=180 quality-level=7 ! h264parse ! mux.", url, audio, video, 8000)
|
birate := 8000
|
||||||
|
pipelineStr = fmt.Sprintf("flvmux name=mux ! rtmpsink location='%s live=1 subscribe=stream-neko buffer=1200000' %s audio/x-raw,channels=2 ! audioconvert ! voaacenc ! mux. %s video/x-raw,format=NV12 ! nvh264enc name=encoder rc-lookahead=20 preset=2 gop-size=120 temporal-aq=true bitrate=%d vbv-buffer-size=%d rc-mode=cbr bframes=0 ! h264parse config-interval=-1 ! mux.", url, audio, video, birate, birate)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipelineStr, nil
|
return pipelineStr, nil
|
||||||
|
|
|
@ -14,6 +14,7 @@ type BroadcastManager interface {
|
||||||
Start(url string) error
|
Start(url string) error
|
||||||
Stop()
|
Stop()
|
||||||
Started() bool
|
Started() bool
|
||||||
|
GetRestart() chan bool
|
||||||
Url() string
|
Url() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OP_MOVE = 0x01
|
OP_MOVE = 0x01
|
||||||
OP_SCROLL = 0x02
|
OP_SCROLL = 0x02
|
||||||
OP_KEY_DOWN = 0x03
|
OP_KEY_DOWN = 0x03
|
||||||
OP_KEY_UP = 0x04
|
OP_KEY_UP = 0x04
|
||||||
OP_KEY_CLK = 0x05
|
OP_KEY_CLK = 0x05
|
||||||
|
OP_RESTART_BROADCAST = 0x06
|
||||||
)
|
)
|
||||||
|
|
||||||
type PayloadHeader struct {
|
type PayloadHeader struct {
|
||||||
|
|
|
@ -121,6 +121,9 @@ func (ws *WebSocketHandler) connectUpstream() {
|
||||||
|
|
||||||
ws.logger.Debug().Msgf("key up %d", payload.Key)
|
ws.logger.Debug().Msgf("key up %d", payload.Key)
|
||||||
}
|
}
|
||||||
|
case webrtc.OP_RESTART_BROADCAST:
|
||||||
|
ws.logger.Info().Msg("Restarting broadcast")
|
||||||
|
ws.capture.Broadcast().GetRestart() <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ func New(sessions types.SessionManager, desktop types.DesktopManager, capture ty
|
||||||
conf: conf,
|
conf: conf,
|
||||||
sessions: sessions,
|
sessions: sessions,
|
||||||
desktop: desktop,
|
desktop: desktop,
|
||||||
|
capture: capture,
|
||||||
webrtc: webrtc,
|
webrtc: webrtc,
|
||||||
state: state,
|
state: state,
|
||||||
upgrader: websocket.Upgrader{
|
upgrader: websocket.Upgrader{
|
||||||
|
@ -88,6 +89,7 @@ type WebSocketHandler struct {
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
sessions types.SessionManager
|
sessions types.SessionManager
|
||||||
desktop types.DesktopManager
|
desktop types.DesktopManager
|
||||||
|
capture types.CaptureManager
|
||||||
webrtc types.WebRTCManager
|
webrtc types.WebRTCManager
|
||||||
state *state.State
|
state *state.State
|
||||||
conf *config.WebSocket
|
conf *config.WebSocket
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue