mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
lazy screencast.
This commit is contained in:
parent
75393905e8
commit
fdd98377b3
@ -63,7 +63,7 @@ func (h *RoomHandler) Route(r chi.Router) {
|
||||
r.Route("/screen", func(r chi.Router) {
|
||||
r.With(auth.CanWatchOnly).Get("/", h.screenConfiguration)
|
||||
r.With(auth.CanWatchOnly).Get("/image", h.screenImageGet)
|
||||
r.With(auth.CanWatchOnly).Get("/cast", h.screenCastGet)
|
||||
r.With(auth.CanWatchOnly).Get("/cast.jpg", h.screenCastGet)
|
||||
|
||||
r.With(auth.AdminsOnly).Post("/", h.screenConfigurationChange)
|
||||
r.With(auth.AdminsOnly).Get("/configurations", h.screenConfigurationsList)
|
||||
|
@ -103,7 +103,12 @@ func (h *RoomHandler) screenCastGet(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
bytes := screencast.Image()
|
||||
bytes, err := screencast.Image()
|
||||
if err != nil {
|
||||
utils.HttpInternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.Header().Set("Content-Type", "image/jpeg")
|
||||
w.Write(bytes)
|
||||
|
@ -51,12 +51,6 @@ func (manager *CaptureManagerCtx) Start() {
|
||||
}
|
||||
}
|
||||
|
||||
if manager.screencast.Enabled() {
|
||||
if err := manager.screencast.createPipeline(); err != nil {
|
||||
manager.logger.Panic().Err(err).Msg("unable to create screencast pipeline")
|
||||
}
|
||||
}
|
||||
|
||||
manager.desktop.OnBeforeScreenSizeChange(func() {
|
||||
if manager.Streaming() {
|
||||
manager.destroyVideoPipeline()
|
||||
@ -66,7 +60,7 @@ func (manager *CaptureManagerCtx) Start() {
|
||||
manager.broadcast.destroyPipeline()
|
||||
}
|
||||
|
||||
if manager.screencast.Enabled() {
|
||||
if manager.screencast.Started() {
|
||||
manager.screencast.destroyPipeline()
|
||||
}
|
||||
})
|
||||
@ -82,7 +76,7 @@ func (manager *CaptureManagerCtx) Start() {
|
||||
}
|
||||
}
|
||||
|
||||
if manager.screencast.Enabled() {
|
||||
if manager.screencast.Started() {
|
||||
if err := manager.screencast.createPipeline(); err != nil {
|
||||
manager.logger.Panic().Err(err).Msg("unable to recreate screencast pipeline")
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package capture
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -13,13 +15,17 @@ import (
|
||||
|
||||
type ScreencastManagerCtx struct {
|
||||
logger zerolog.Logger
|
||||
mu sync.Mutex
|
||||
config *config.Capture
|
||||
pipeline *gst.Pipeline
|
||||
enabled bool
|
||||
started bool
|
||||
shutdown chan bool
|
||||
refresh chan bool
|
||||
expires time.Time
|
||||
timeout time.Duration
|
||||
sample chan types.Sample
|
||||
image *bytes.Buffer
|
||||
image types.Sample
|
||||
}
|
||||
|
||||
func screencastNew(config *config.Capture) *ScreencastManagerCtx {
|
||||
@ -27,24 +33,34 @@ func screencastNew(config *config.Capture) *ScreencastManagerCtx {
|
||||
logger: log.With().Str("module", "capture").Str("submodule", "screencast").Logger(),
|
||||
config: config,
|
||||
enabled: config.Screencast,
|
||||
started: false,
|
||||
shutdown: make(chan bool),
|
||||
refresh: make(chan bool),
|
||||
image: new(bytes.Buffer),
|
||||
timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
if !manager.enabled {
|
||||
return manager
|
||||
}
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
manager.logger.Debug().Msg("subroutine started")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-manager.shutdown:
|
||||
manager.logger.Debug().Msg("shutting down")
|
||||
ticker.Stop()
|
||||
return
|
||||
case <-manager.refresh:
|
||||
manager.logger.Debug().Msg("subroutine updated")
|
||||
case sample := <-manager.sample:
|
||||
manager.image.Reset()
|
||||
manager.image.Write(sample.Data)
|
||||
manager.image = sample
|
||||
case <-ticker.C:
|
||||
if manager.started && time.Now().After(manager.expires) {
|
||||
manager.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@ -52,25 +68,61 @@ func screencastNew(config *config.Capture) *ScreencastManagerCtx {
|
||||
return manager
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) Start() error {
|
||||
manager.enabled = true
|
||||
return manager.createPipeline()
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) Stop() {
|
||||
manager.enabled = false
|
||||
manager.destroyPipeline()
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) Enabled() bool {
|
||||
return manager.enabled
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) Image() []byte {
|
||||
return manager.image.Bytes()
|
||||
func (manager *ScreencastManagerCtx) Started() bool {
|
||||
return manager.started
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) Image() ([]byte, error) {
|
||||
manager.expires = time.Now().Add(manager.timeout)
|
||||
|
||||
if !manager.started {
|
||||
err := manager.start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
select {
|
||||
case sample := <-manager.sample:
|
||||
return sample.Data, nil
|
||||
case <-time.After(1 * time.Second):
|
||||
return nil, fmt.Errorf("timeouted")
|
||||
}
|
||||
}
|
||||
|
||||
if manager.image.Data == nil {
|
||||
return nil, fmt.Errorf("image sample not found")
|
||||
}
|
||||
|
||||
return manager.image.Data, nil
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) start() error {
|
||||
if !manager.enabled {
|
||||
return fmt.Errorf("screenshot pipeline not enabled")
|
||||
}
|
||||
|
||||
err := manager.createPipeline()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
manager.started = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) stop() {
|
||||
manager.started = false
|
||||
manager.destroyPipeline()
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) createPipeline() error {
|
||||
manager.mu.Lock()
|
||||
defer manager.mu.Unlock()
|
||||
|
||||
var err error
|
||||
|
||||
manager.logger.Info().
|
||||
@ -98,6 +150,9 @@ func (manager *ScreencastManagerCtx) createPipeline() error {
|
||||
}
|
||||
|
||||
func (manager *ScreencastManagerCtx) destroyPipeline() {
|
||||
manager.mu.Lock()
|
||||
defer manager.mu.Unlock()
|
||||
|
||||
if manager.pipeline == nil {
|
||||
return
|
||||
}
|
||||
|
@ -13,10 +13,9 @@ type BroadcastManager interface {
|
||||
}
|
||||
|
||||
type ScreencastManager interface {
|
||||
Start() error
|
||||
Stop()
|
||||
Enabled() bool
|
||||
Image() []byte
|
||||
Started() bool
|
||||
Image() ([]byte, error)
|
||||
}
|
||||
|
||||
type CaptureManager interface {
|
||||
|
Loading…
Reference in New Issue
Block a user