From d70362db229fa07ac643c87483cae95c896a976a Mon Sep 17 00:00:00 2001 From: PHO Date: Sat, 6 Nov 2010 14:42:42 +0900 Subject: [PATCH] openPlayer now works? (not tested) --- EsounD.cabal | 4 ++- Sound/EsounD.hs | 66 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/EsounD.cabal b/EsounD.cabal index 47960a3..108bba0 100644 --- a/EsounD.cabal +++ b/EsounD.cabal @@ -29,7 +29,9 @@ Library network == 2.2.*, regions == 0.7.*, safer-file-handles == 0.8.*, - storablevector == 0.2.* + storablevector == 0.2.*, + transformers == 0.2.*, + unix == 2.4.* Exposed-Modules: Sound.EsounD diff --git a/Sound/EsounD.hs b/Sound/EsounD.hs index a088e90..f6de9a0 100644 --- a/Sound/EsounD.hs +++ b/Sound/EsounD.hs @@ -13,12 +13,21 @@ module Sound.EsounD import Bindings.EsounD import Control.Monad.CatchIO -import Control.Monad.Trans.Region +import Control.Monad.IO.Class +import Control.Monad.Trans.Region as R +import Control.Monad.Trans.Region.OnExit +import Control.Monad.Unicode import Data.Bits import Data.Int +import Foreign.C.String +import Foreign.C.Types +import Foreign.Ptr import Network import Prelude.Unicode -import System.IO.SaferFileHandles +import System.IO +import System.IO.SaferFileHandles.Unsafe +import System.Posix.IO +import System.Posix.Types class Frame fr where frameFmt ∷ fr → C'esd_format_t @@ -44,17 +53,20 @@ instance Channels Stereo where -- ^ An ESD handle for playing a stream. data Player fr ch (r ∷ * → *) = Player { - plRate ∷ Int - , plHandle ∷ RegionalFileHandle WriteMode r + 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 h' ← dup (plHandle pl) - return pl { plHandle = h' } + dup pl = do ch' ← R.dup (plCloseH pl) + return pl { plCloseH = ch' } -- | Open an ESD handle for playing a stream. -openPlayer ∷ ∀ fr ch s pr. +openPlayer ∷ ∀fr ch s pr. ( Frame fr , Channels ch , MonadCatchIO pr @@ -65,11 +77,39 @@ openPlayer ∷ ∀ fr ch s pr. -- ESD (if any). → RegionT s pr (Player fr ch (RegionT s pr)) openPlayer rate host name - = do let fmt = frameFmt ((⊥) ∷ fr) .&. - channelFmt ((⊥) ∷ ch) .&. - c'ESD_STREAM .&. - c'ESD_PLAY + = do h ← liftIO openSocket + ch ← onExit $ sanitizeIOError $ closeSocket h return Player { plRate = rate - , plHandle = error "FIXME: not implemented" + , 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" + +wrapSocket :: String -> CInt → IO Handle +wrapSocket e (-1) = fail e +wrapSocket _ fd = fdToHandle (Fd fd) + +closeSocket :: Handle → IO () +closeSocket h = do (Fd fd) ← handleToFd h + _ ← c'esd_close (fromIntegral fd) + return () + +withCStrOrNull :: Maybe String → (CString → IO a) → IO a +withCStrOrNull Nothing f = f nullPtr +withCStrOrNull (Just s) f = withCString s f -- 2.40.0