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.Route("/screen", func(r chi.Router) {
|
||||||
r.With(auth.CanWatchOnly).Get("/", h.screenConfiguration)
|
r.With(auth.CanWatchOnly).Get("/", h.screenConfiguration)
|
||||||
r.With(auth.CanWatchOnly).Get("/image", h.screenImageGet)
|
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).Post("/", h.screenConfigurationChange)
|
||||||
r.With(auth.AdminsOnly).Get("/configurations", h.screenConfigurationsList)
|
r.With(auth.AdminsOnly).Get("/configurations", h.screenConfigurationsList)
|
||||||
|
@ -103,7 +103,12 @@ func (h *RoomHandler) screenCastGet(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
w.Header().Set("Content-Type", "image/jpeg")
|
w.Header().Set("Content-Type", "image/jpeg")
|
||||||
w.Write(bytes)
|
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() {
|
manager.desktop.OnBeforeScreenSizeChange(func() {
|
||||||
if manager.Streaming() {
|
if manager.Streaming() {
|
||||||
manager.destroyVideoPipeline()
|
manager.destroyVideoPipeline()
|
||||||
@ -66,7 +60,7 @@ func (manager *CaptureManagerCtx) Start() {
|
|||||||
manager.broadcast.destroyPipeline()
|
manager.broadcast.destroyPipeline()
|
||||||
}
|
}
|
||||||
|
|
||||||
if manager.screencast.Enabled() {
|
if manager.screencast.Started() {
|
||||||
manager.screencast.destroyPipeline()
|
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 {
|
if err := manager.screencast.createPipeline(); err != nil {
|
||||||
manager.logger.Panic().Err(err).Msg("unable to recreate screencast pipeline")
|
manager.logger.Panic().Err(err).Msg("unable to recreate screencast pipeline")
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package capture
|
package capture
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@ -13,13 +15,17 @@ import (
|
|||||||
|
|
||||||
type ScreencastManagerCtx struct {
|
type ScreencastManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
|
mu sync.Mutex
|
||||||
config *config.Capture
|
config *config.Capture
|
||||||
pipeline *gst.Pipeline
|
pipeline *gst.Pipeline
|
||||||
enabled bool
|
enabled bool
|
||||||
|
started bool
|
||||||
shutdown chan bool
|
shutdown chan bool
|
||||||
refresh chan bool
|
refresh chan bool
|
||||||
|
expires time.Time
|
||||||
|
timeout time.Duration
|
||||||
sample chan types.Sample
|
sample chan types.Sample
|
||||||
image *bytes.Buffer
|
image types.Sample
|
||||||
}
|
}
|
||||||
|
|
||||||
func screencastNew(config *config.Capture) *ScreencastManagerCtx {
|
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(),
|
logger: log.With().Str("module", "capture").Str("submodule", "screencast").Logger(),
|
||||||
config: config,
|
config: config,
|
||||||
enabled: config.Screencast,
|
enabled: config.Screencast,
|
||||||
|
started: false,
|
||||||
shutdown: make(chan bool),
|
shutdown: make(chan bool),
|
||||||
refresh: make(chan bool),
|
refresh: make(chan bool),
|
||||||
image: new(bytes.Buffer),
|
timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !manager.enabled {
|
||||||
|
return manager
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
manager.logger.Debug().Msg("subroutine started")
|
manager.logger.Debug().Msg("subroutine started")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-manager.shutdown:
|
case <-manager.shutdown:
|
||||||
manager.logger.Debug().Msg("shutting down")
|
manager.logger.Debug().Msg("shutting down")
|
||||||
|
ticker.Stop()
|
||||||
return
|
return
|
||||||
case <-manager.refresh:
|
case <-manager.refresh:
|
||||||
manager.logger.Debug().Msg("subroutine updated")
|
manager.logger.Debug().Msg("subroutine updated")
|
||||||
case sample := <-manager.sample:
|
case sample := <-manager.sample:
|
||||||
manager.image.Reset()
|
manager.image = sample
|
||||||
manager.image.Write(sample.Data)
|
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
|
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 {
|
func (manager *ScreencastManagerCtx) Enabled() bool {
|
||||||
return manager.enabled
|
return manager.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *ScreencastManagerCtx) Image() []byte {
|
func (manager *ScreencastManagerCtx) Started() bool {
|
||||||
return manager.image.Bytes()
|
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 {
|
func (manager *ScreencastManagerCtx) createPipeline() error {
|
||||||
|
manager.mu.Lock()
|
||||||
|
defer manager.mu.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
manager.logger.Info().
|
manager.logger.Info().
|
||||||
@ -98,6 +150,9 @@ func (manager *ScreencastManagerCtx) createPipeline() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (manager *ScreencastManagerCtx) destroyPipeline() {
|
func (manager *ScreencastManagerCtx) destroyPipeline() {
|
||||||
|
manager.mu.Lock()
|
||||||
|
defer manager.mu.Unlock()
|
||||||
|
|
||||||
if manager.pipeline == nil {
|
if manager.pipeline == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,9 @@ type BroadcastManager interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ScreencastManager interface {
|
type ScreencastManager interface {
|
||||||
Start() error
|
|
||||||
Stop()
|
|
||||||
Enabled() bool
|
Enabled() bool
|
||||||
Image() []byte
|
Started() bool
|
||||||
|
Image() ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CaptureManager interface {
|
type CaptureManager interface {
|
||||||
|
Loading…
Reference in New Issue
Block a user