aboutsummaryrefslogtreecommitdiff
path: root/hsm-stream/Hsm/Stream.hs
blob: e0b2b5b3c1620b40d41237e69b6da9359835e0bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE TypeFamilies #-}

module Hsm.Stream
  ( Stream
  , startStream
  , stopStream
  , runStream
  )
where

import Control.Monad (void, when)
import Effectful (Dispatch (Static), DispatchOf, Eff, IOE, liftIO, (:>))
import Effectful.Dispatch.Static (SideEffects (WithSideEffects), StaticRep, evalStaticRep, getStaticRep, unsafeEff_)
import Effectful.Exception (finally)
import Foreign.C.String (withCString)
import Foreign.Ptr (Ptr, nullPtr)
import Hsm.Log (Log, Severity (Info), logMsg)
import Hsm.Stream.FFI
  ( GstElement
  , gstDeinit
  , gstElementSetState
  , gstInit
  , gstObjectUnref
  , gstParseLaunch
  , gstStateNull
  , gstStatePlaying
  )
import System.Environment (setEnv)

data Stream (a :: * -> *) (b :: *)

type instance DispatchOf Stream = Static WithSideEffects

newtype instance StaticRep Stream
  = Stream (Ptr GstElement)

startStream :: (Log "stream" :> es, Stream :> es) => Eff es ()
startStream = do
  Stream pipeline <- getStaticRep
  logMsg Info "Starting stream"
  unsafeEff_ . void $ gstElementSetState pipeline gstStatePlaying

stopStream :: (Log "stream" :> es, Stream :> es) => Eff es ()
stopStream = do
  Stream pipeline <- getStaticRep
  logMsg Info "Stopping stream"
  unsafeEff_ . void $ gstElementSetState pipeline gstStateNull

runStream :: (IOE :> es, Log "stream" :> es) => Bool -> Eff (Stream : es) a -> Eff es a
runStream suppressXLogs action = do
  when suppressXLogs $ do
    logMsg Info "Suppressing external loggers"
    liftIO $ setEnv "GST_DEBUG" "none"
    liftIO $ setEnv "LIBCAMERA_LOG_LEVELS" "FATAL"
    liftIO $ setEnv "WEBRTCSINK_SIGNALLING_SERVER_LOG" "none"
  logMsg Info "Initializing gstreamer library"
  liftIO $ gstInit nullPtr nullPtr
  logMsg Info $ "Parsing gstreamer pipeline: " <> pipelineStr
  pipeline <- liftIO . withCString pipelineStr $ \cStr -> gstParseLaunch cStr nullPtr
  evalStaticRep (Stream pipeline) . finally action $ stopStream >> endStream
  where
    pipelineStr = "libcamerasrc ! videoconvert ! vp8enc deadline=1 ! webrtcsink run-signalling-server=true"
    endStream = do
      Stream pipeline <- getStaticRep
      logMsg Info "Unrefing gstreamer pipeline"
      liftIO $ gstObjectUnref pipeline
      logMsg Info "De-initializing gstreamer library"
      liftIO gstDeinit