module Xine (
XineConf(..), VisualType(..), defaultConf,
XineHandle, open, openWith, close, isClosed,
MRL, StreamId,
openStream, closeStream, getCurrent,
SeekArg(..),
play, seek, stop, pause,
EngineStatus(..), MetaType(..),
getStatus, getMetadata
) where
import Xine.Foreign
import Xine.Internal.Handle
import Xine.Internal.Stream (StreamId)
import qualified Xine.Internal.Stream as S
import Control.Concurrent.MVar
import Control.Monad (unless)
import Data.Maybe (fromJust)
data XineConf = XineConf
{ audioDriver :: !(Maybe String)
, videoDriver :: !(Maybe String)
, visualType :: !VisualType
}
defaultConf :: XineConf
defaultConf = XineConf
{ audioDriver = Nothing
, videoDriver = Nothing
, visualType = None
}
open :: IO XineHandle
open = openWith defaultConf
openWith :: XineConf -> IO XineHandle
openWith conf = do
engine <- xine_new
xine_init engine
ap <- maybe (fail "Failed to open the audio driver") return =<<
xine_open_audio_driver engine (audioDriver conf)
vp <- maybe (fail "Failed to open the video driver") return =<<
xine_open_video_driver engine (videoDriver conf) (visualType conf)
h_ <- newMVar $ XineHandle_ engine ap vp S.empty Nothing Open
return $ XineHandle h_
close :: XineHandle -> IO ()
close h@(XineHandle hv) = do
withXineHandle h $ \h_ -> do
mapM_ xine_close (S.streams $ hStreams h_)
xine_close_audio_driver (hEngine h_) (hAudioPort h_)
xine_close_video_driver (hEngine h_) (hVideoPort h_)
xine_exit (hEngine h_)
modifyMVar_ hv $ \x -> return x { hState = Closed }
openStream :: XineHandle -> MRL -> IO StreamId
openStream h uri = do
modifyXineHandle h $ \h_ -> do
st <- maybe (fail "Failed to open a new stream") return =<<
xine_stream_new (hEngine h_) (hAudioPort h_) (hVideoPort h_)
ret <- xine_open st uri
unless (ret == 1) (fail "Failed to open MRL")
let (s, i) = S.insert st (hStreams h_)
return $ h_ { hStreams = s
, hCurrent = Just i }
fromJust `fmap` getCurrent h
closeStream :: XineHandle -> StreamId -> IO ()
closeStream h sid = modifyXineHandle h $ \h_ ->
case S.lookup sid (hStreams h_) of
Just st -> do
xine_close st
return $ h_ { hStreams = S.delete sid (hStreams h_) }
Nothing -> return h_
getCurrent :: XineHandle -> IO (Maybe StreamId)
getCurrent h = withXineHandle h $ \hv -> return (hCurrent hv)
play :: XineHandle -> StreamId -> IO ()
play h sid = withStream h sid $ \st -> do
ret <- xine_play st 0 0
unless (ret == 1) (fail "Failed to start playback")
data SeekArg
= SeekTime Int
| SeekPos Int
deriving (Eq, Show)
seek :: XineHandle -> StreamId -> SeekArg -> IO ()
seek h sid arg = withStream h sid $ \st -> do
ret <- xine_trick_mode st (trick arg) (val arg)
unless (ret == 1) (fail "Seek failed")
where
val (SeekTime x) = x
val (SeekPos x) = x
trick (SeekTime _) = TrickSeekToTime
trick (SeekPos _) = TrickSeekToPosition
stop :: XineHandle -> StreamId -> IO ()
stop h sid = withStream h sid $ \st -> xine_stop st
pause :: XineHandle -> StreamId -> IO ()
pause h sid = withStream h sid $ \st -> xine_get_param st Speed >>=
xine_set_param st Speed . toggle
where
toggle Pause = Normal
toggle _ = Pause
getStatus :: XineHandle -> IO EngineStatus
getStatus h = withXineHandle h $ \h_ ->
case hCurrent h_ of
Just sid -> xine_get_status (fromJust $ S.lookup sid (hStreams h_))
Nothing -> return Idle
getMetadata :: XineHandle -> StreamId -> MetaType -> IO String
getMetadata h sid m = withStream h sid $ \st -> xine_get_meta_info st m