summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Main.hs18
-rw-r--r--src/Trivstream/Options.hs37
-rw-r--r--src/Trivstream/Options/Utils.hs32
-rw-r--r--src/Trivstream/Types.hs92
-rw-r--r--trivstream.cabal24
-rw-r--r--trivstream.nix14
6 files changed, 212 insertions, 5 deletions
diff --git a/src/Main.hs b/src/Main.hs
index c2e4af9..70c3ad5 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -1,4 +1,22 @@
1module Main where 1module Main where
2 2
3
4import Trivstream.Types
5import Trivstream.Options
6
7
8import Options.Applicative
9
10import Control.Lens
11import Data.Default.Class
12import Data.Serialize
13import Data.Conduit.Cereal
14
15import Sound.Pulse.Simple
16import Sound.JACK
17
18import Network.Socket
19
20
3main :: IO () 21main :: IO ()
4main = undefined 22main = undefined
diff --git a/src/Trivstream/Options.hs b/src/Trivstream/Options.hs
new file mode 100644
index 0000000..a777942
--- /dev/null
+++ b/src/Trivstream/Options.hs
@@ -0,0 +1,37 @@
1{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}
2
3module Trivstream.Options
4 ( withOptions
5 ) where
6
7
8import Trivstream.Types
9import Trivstream.Options.Utils
10import Paths_trivstream (version)
11
12
13import Options.Applicative
14
15import Control.Monad.Reader
16import Control.Monad.IO.Class
17
18
19withOptions :: MonadIO m => ReaderT Configuration a -> IO a
20withOptions f = liftIO (execParser options) >>= runReaderT f
21 where
22 options = options' `info` mconcat [ header $ concat [ "trivstream "
23 , show version
24 , " - "
25 , "A trivial client & server for streaming audio between pulseaudio and jack over udp/tcp"
26 ]
27 , footer $ concat [ "trivstream "
28 , show version
29 , " (", $(gitBranch), "@", $(gitHash), (if $(gitDirty) then "*" else ""), ")"
30 ]
31 ]
32 options' = Configuration <$> argument rCI (help "Mode of operation" <> value def <> showDefault <> metavar "MODE")
33 <*> optional ( undefined
34 )
35 <*> audioOptions
36
37 audioOptions = undefined
diff --git a/src/Trivstream/Options/Utils.hs b/src/Trivstream/Options/Utils.hs
new file mode 100644
index 0000000..30694d8
--- /dev/null
+++ b/src/Trivstream/Options/Utils.hs
@@ -0,0 +1,32 @@
1{-# LANGUAGE StandaloneDeriving #-}
2
3module Trivstream.Options.Utils
4 ( rCI
5 ) where
6
7import Options.Applicative
8
9import Data.Char
10import Data.Maybe
11
12import Network.Socket
13
14
15deriving instance Enum Family
16deriving instance Bounded Family
17
18
19rCI :: (Show a, Read a) => ReadM a
20rCI = eitherReader rRep'
21 where
22 rRep' str = case mapMaybe readMaybe $ cases str of
23 [] -> Left $ "Could not parse `" ++ str ++ "'"
24 [x] -> Right x
25 xs -> Left $ "Ambiguous parse for `" ++ str ++ "': " ++ show xs
26 cases [] = [[]]
27 cases (c:cs) = [(c':cs') | c' <- [toLower c, c, toUpper c], cs' <- cases cs]
28
29rFamily :: ReadM Family
30rFamily = undefined
31 where
32 families = filter isSupportedFamily [minBound..maxBound]
diff --git a/src/Trivstream/Types.hs b/src/Trivstream/Types.hs
new file mode 100644
index 0000000..8cdd592
--- /dev/null
+++ b/src/Trivstream/Types.hs
@@ -0,0 +1,92 @@
1{-# LANGUAGE TemplateHaskell #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, DeriveGeneric #-}
3
4module Trivstream.Types
5 ( AudioConfig(..)
6 , AudioBackend(..)
7 , SampleRate(..)
8 , Configuration(..)
9 , Mode (..)
10 ) where
11
12
13import Control.Lens
14import Control.Lens.TH
15import Data.Default.Class (Default(..))
16import Data.Serialize (Serialize)
17import GHC.Generics (Generic)
18
19import Foreign.C.Types (CInt(..))
20
21import Sound.Pulse.Simple (ChannelPosition(..), ChannelPan(..))
22import Sound.JACK ()
23
24import Network.Socket (Family(..), SocketType(..), ProtocolNumber(..), SockAddr(..))
25
26
27deriving instance Generic ChannelPan
28instance Serialize ChannelPan
29
30deriving instance Generic ChannelPosition
31instance Serialize ChannelPosition
32
33
34data AudioBackend = Pulse | Jack
35 deriving (Enum, Eq, Generic)
36
37instance Default AudioBackend where
38 def = Pulse
39
40instance Serialize AudioBackend
41
42
43-- | Numeric instances consider this value to be in `kHz`
44newtype SampleRate = SampleRate Int
45 deriving (Eq, Ord, Enum, Num, Real, Integral, Generic)
46makePrisms ''SampleRate
47
48instance Default SampleRate where
49 def = 44100
50
51instance Serialize SampleRate
52
53
54data AudioConfig = AudioConfig
55 { _aBackend :: AudioBackend
56 , _aChannels :: [Maybe ChannelPosition]
57 , _aRate :: SampleRate
58 } deriving (Generic)
59makeLenses ''AudioConfig
60
61instance Default AudioConfig where
62 def = AudioConfig
63 { _aBackend = def
64 , _aChannels = [Just $ ChannelNormal PanLeft, Just $ ChannelNormal PanRight]
65 , _aRate = def
66 }
67
68instance Serialize AudioConfig
69
70
71data Mode = Server | Client
72 deriving (Enum, Eq, Generic, Show)
73
74instance Default Mode where
75 def = Server
76
77instance Serialize Mode
78
79
80data Configuration = Configuration
81 { _cMode :: Mode
82 , _cSocketDesc :: Maybe (Family, SocketType, ProtocolNumber, SockAddr)
83 , _cAudio :: AudioConfig
84 } deriving (Generic)
85makeLenses ''Configuration
86
87instance Default Configuration where
88 def = Configuration
89 { _cMode = def
90 , _cSocketDesc = Nothing
91 , _cAudio = def
92 }
diff --git a/trivstream.cabal b/trivstream.cabal
index 546fc1a..a8dc9ec 100644
--- a/trivstream.cabal
+++ b/trivstream.cabal
@@ -1,6 +1,6 @@
1name: trivstream 1name: trivstream
2version: 0.0.0 2version: 0.0.0
3synopsis: A trivial client & server for streaming audio over udp between pulseaudio & jack 3synopsis: A trivial client & server for streaming audio between pulseaudio and jack over udp/tcp
4-- description: 4-- description:
5license: GPL-3 5license: GPL-3
6author: Gregor Kleen 6author: Gregor Kleen
@@ -13,8 +13,28 @@ cabal-version: >=1.10
13 13
14executable trivstream 14executable trivstream
15 main-is: Main.hs 15 main-is: Main.hs
16 -- other-modules: 16 extensions: TemplateHaskell
17 , DeriveGeneric
18 , StandaloneDeriving
19 , GeneralizedNewtypeDeriving
20 , OverloadedStrings
21 other-modules: Trivstream.Types
17 -- other-extensions: 22 -- other-extensions:
18 build-depends: base >=4.9 && <5 23 build-depends: base >=4.9 && <5
24 , cereal >=0.5.3.0 && <1
25 , cereal-conduit >=0.7.3 && <1
26 , conduit >=1.2.6.6 && <2
27 , conduit-extra >=1.1.13.2 && <2
28 , data-default-class >=0.1.2.0 && <1
29 , gitrev >=1.2.0 && <2
30 , jack >=0.7.0.3 && <1
31 , lens >=4.14 && <5
32 , network >=2.6.2.1 && <3
33 , mtl
34 , optparse-applicative >=0.12.1.0 && <1
35 , pulse-simple >=0.1.14 && <1
36 , socket-activation >=0.1.0.1 && <1
37 , transformers
19 hs-source-dirs: src 38 hs-source-dirs: src
20 default-language: Haskell2010 39 default-language: Haskell2010
40 ghc-options: -threaded
diff --git a/trivstream.nix b/trivstream.nix
index 2521a88..7e8c872 100644
--- a/trivstream.nix
+++ b/trivstream.nix
@@ -1,11 +1,19 @@
1{ mkDerivation, base, stdenv }: 1{ mkDerivation, base, cereal, cereal-conduit, conduit
2, conduit-extra, data-default-class, gitrev, jack, lens, mtl
3, network, optparse-applicative, pulse-simple, socket-activation
4, stdenv, transformers
5}:
2mkDerivation { 6mkDerivation {
3 pname = "trivstream"; 7 pname = "trivstream";
4 version = "0.0.0"; 8 version = "0.0.0";
5 src = ./.; 9 src = ./.;
6 isLibrary = false; 10 isLibrary = false;
7 isExecutable = true; 11 isExecutable = true;
8 executableHaskellDepends = [ base ]; 12 executableHaskellDepends = [
9 description = "A trivial client & server for streaming audio over udp between pulseaudio & jack"; 13 base cereal cereal-conduit conduit conduit-extra data-default-class
14 gitrev jack lens mtl network optparse-applicative pulse-simple
15 socket-activation transformers
16 ];
17 description = "A trivial client & server for streaming audio between pulseaudio and jack over udp/tcp";
10 license = stdenv.lib.licenses.gpl3; 18 license = stdenv.lib.licenses.gpl3;
11} 19}