]> gitweb @ CieloNegro.org - EsounD.git/blobdiff - Sound/EsounD/Player.hs
Sound.EsounD.Player
[EsounD.git] / Sound / EsounD / Player.hs
diff --git a/Sound/EsounD/Player.hs b/Sound/EsounD/Player.hs
new file mode 100644 (file)
index 0000000..0d2b209
--- /dev/null
@@ -0,0 +1,71 @@
+-- | EsounD player streams.
+module Sound.EsounD.Player
+    ( Player
+    , openPlayer
+    )
+    where
+
+import Bindings.EsounD
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Region
+import Control.Monad.Trans.Region.OnExit
+import Control.Monad.Unicode
+import Data.Bits
+import Foreign.C.String
+import Network
+import Prelude.Unicode
+import Sound.EsounD.Internals
+import System.IO
+import System.IO.SaferFileHandles.Unsafe
+
+
+-- ^ An opaque ESD handle for playing a stream.
+data Player fr ch (r ∷ * → *)
+    = Player {
+        plRate   ∷ !Int
+      -- THINKME: We really want to use RegionalFileHandle but we
+      -- can't, because safer-file-handles currently provides no ways
+      -- to wrap ordinary handles.
+      , plHandle ∷ !Handle
+      , plCloseH ∷ !(CloseHandle r)
+      }
+
+instance Dup (Player fr ch) where
+    dup pl = do ch' ← dup (plCloseH pl)
+                return pl { plCloseH = ch' }
+
+-- | Open an ESD handle for playing a stream.
+openPlayer ∷ ∀fr ch s pr.
+               ( Frame fr
+               , Channels ch
+               , MonadIO pr
+               )
+           ⇒ Int          -- ^ sample rate for the stream.
+           → HostName     -- ^ host to connect to.
+           → Maybe String -- ^ name used to identify this stream to
+                           --   ESD (if any).
+           → RegionT s pr (Player fr ch (RegionT s pr))
+openPlayer rate host name
+    = do h  ← liftIO openSocket
+         ch ← onExit $ sanitizeIOError $ closeSocket h
+         return Player {
+                      plRate   = rate
+                    , plHandle = h
+                    , plCloseH = ch
+                    }
+    where
+      fmt :: C'esd_format_t
+      fmt = frameFmt   ((⊥) ∷ fr) .&.
+            channelFmt ((⊥) ∷ ch) .&.
+            c'ESD_STREAM            .&.
+            c'ESD_PLAY
+
+      openSocket :: IO Handle
+      openSocket = withCString    host $ \hostPtr →
+                   withCStrOrNull name $ \namePtr →
+                       c'esd_play_stream
+                       fmt
+                       (fromIntegral rate)
+                       hostPtr
+                       namePtr
+                       ≫= wrapSocket "esd_play_stream() returned an error"