lazy screencast.

This commit is contained in:
Miroslav Šedivý 2021-01-23 15:17:52 +01:00
parent 75393905e8
commit fdd98377b3
5 changed files with 83 additions and 30 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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")
}

View File

@ -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
}

View File

@ -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 {