]> gitweb @ CieloNegro.org - EsounD.git/blob - Sound/EsounD/Player.hs
Sound.EsounD.Player
[EsounD.git] / Sound / EsounD / Player.hs
1 -- | EsounD player streams.
2 module Sound.EsounD.Player
3     ( Player
4     , openPlayer
5     )
6     where
7
8 import Bindings.EsounD
9 import Control.Monad.IO.Class
10 import Control.Monad.Trans.Region
11 import Control.Monad.Trans.Region.OnExit
12 import Control.Monad.Unicode
13 import Data.Bits
14 import Foreign.C.String
15 import Network
16 import Prelude.Unicode
17 import Sound.EsounD.Internals
18 import System.IO
19 import System.IO.SaferFileHandles.Unsafe
20
21
22 -- ^ An opaque ESD handle for playing a stream.
23 data Player fr ch (r ∷ * → *)
24     = Player {
25         plRate   ∷ !Int
26       -- THINKME: We really want to use RegionalFileHandle but we
27       -- can't, because safer-file-handles currently provides no ways
28       -- to wrap ordinary handles.
29       , plHandle ∷ !Handle
30       , plCloseH ∷ !(CloseHandle r)
31       }
32
33 instance Dup (Player fr ch) where
34     dup pl = do ch' ← dup (plCloseH pl)
35                 return pl { plCloseH = ch' }
36
37 -- | Open an ESD handle for playing a stream.
38 openPlayer ∷ ∀fr ch s pr.
39                ( Frame fr
40                , Channels ch
41                , MonadIO pr
42                )
43            ⇒ Int          -- ^ sample rate for the stream.
44            → HostName     -- ^ host to connect to.
45            → Maybe String -- ^ name used to identify this stream to
46                            --   ESD (if any).
47            → RegionT s pr (Player fr ch (RegionT s pr))
48 openPlayer rate host name
49     = do h  ← liftIO openSocket
50          ch ← onExit $ sanitizeIOError $ closeSocket h
51          return Player {
52                       plRate   = rate
53                     , plHandle = h
54                     , plCloseH = ch
55                     }
56     where
57       fmt :: C'esd_format_t
58       fmt = frameFmt   ((⊥) ∷ fr) .&.
59             channelFmt ((⊥) ∷ ch) .&.
60             c'ESD_STREAM            .&.
61             c'ESD_PLAY
62
63       openSocket :: IO Handle
64       openSocket = withCString    host $ \hostPtr →
65                    withCStrOrNull name $ \namePtr →
66                        c'esd_play_stream
67                        fmt
68                        (fromIntegral rate)
69                        hostPtr
70                        namePtr
71                        ≫= wrapSocket "esd_play_stream() returned an error"