{-
Copyright 2016 Markus Ongyerth
This file is part of pulseaudio-hs.
Monky is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Monky is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with pulseaudio-hs. If not, see .
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards #-}
{-|
Module : Sound.Pulse.Sinkinfo
Description : provides the time type used for pa_sink_info.
Maintianer : ongy
Stability : experimental
-}
module Sound.Pulse.Sinkinfo
( SinkFlags(..)
, SinkState(..)
, Sinkinfo(..)
, getContextSinks
, getContextSinkByName
, getContextSinkByIndex
)
where
#if __GLASGOW_HASKELL__ < 800
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
#endif
#include
import Control.Applicative ((<$>), (<*>))
import Sound.Pulse.Volume
import Sound.Pulse.Operation
import Sound.Pulse.Userdata
import Data.Word (Word32, Word8, Word)
import Foreign.Ptr (Ptr, FunPtr, freeHaskellFunPtr, castFunPtrToPtr, castPtrToFunPtr)
import Foreign.C.Types (CInt(..), CUInt(..))
import Foreign.C.String (peekCString, withCString, CString)
import Foreign.Storable (Storable(..))
import Sound.Pulse.Context (Context)
import Sound.Pulse.ChannelPosition
import Sound.Pulse.SampleSpec
import Sound.Pulse.Def (SinkFlags(..), sinkFlagssFromInt, SinkState(..), sinkStateFromInt)
data PropList -- TODO :)
data FormatInfo -- TODO
data SinkPortInfo -- TODO
-- |Type used for pa_sink_info
data Sinkinfo = Sinkinfo
{ siName :: String
, siIndex :: Word32
, siDescription :: String
, siSampleSpec :: SampleSpec
, siChannelMap :: ChannelMap
, siOwnerModule :: Word32
, siVolume :: CVolume
, siMute :: Bool
, siMonitorSource :: Word32
, siMonitorSourceName :: String
, siLatency :: Word
, siDriver :: String
, siFlags :: [SinkFlags]
, siProplist :: Ptr PropList
, siConfiguredLatency :: Word
, siBaseVolume :: Volume
, siState :: SinkState
, siVolumeSteps :: Word32
, siCard :: Word32
, siPorts :: [Ptr SinkPortInfo]
, siActivePort :: Ptr SinkPortInfo
, siFormats :: [Ptr FormatInfo]
} deriving (Eq, Show)
instance Storable Sinkinfo where
sizeOf _ = #{size struct pa_sink_info}
alignment _ = #{alignment struct pa_sink_info}
peek p = Sinkinfo
<$> (peekCString =<< #{peek struct pa_sink_info, name} p)
<*> #{peek struct pa_sink_info, index} p
<*> (peekCString =<< #{peek struct pa_sink_info, description} p)
<*> #{peek struct pa_sink_info, sample_spec} p
<*> #{peek struct pa_sink_info, channel_map} p
<*> #{peek struct pa_sink_info, owner_module} p
<*> #{peek struct pa_sink_info, volume} p
<*> ((/= (0 :: CInt)) <$> (#{peek struct pa_sink_info, mute} p))
<*> #{peek struct pa_sink_info, monitor_source} p
<*> (peekCString =<< #{peek struct pa_sink_info, monitor_source_name} p)
<*> #{peek struct pa_sink_info, latency} p
<*> (peekCString =<< #{peek struct pa_sink_info, driver} p)
<*> (sinkFlagssFromInt <$> (#{peek struct pa_sink_info, mute} p))
<*> #{peek struct pa_sink_info, proplist} p
<*> #{peek struct pa_sink_info, configured_latency} p
<*> #{peek struct pa_sink_info, base_volume} p
<*> (sinkStateFromInt <$> (#{peek struct pa_sink_info, mute} p))
<*> #{peek struct pa_sink_info, n_volume_steps} p
<*> #{peek struct pa_sink_info, card} p
<*> do
size :: Word8 <- #{peek struct pa_sink_info, n_ports} p
ptr <- #{peek struct pa_sink_info, ports} p
mapM (peekElemOff ptr . fromIntegral) [0.. size - 1]
<*> #{peek struct pa_sink_info, active_port} p
<*> do
size :: Word8 <- #{peek struct pa_sink_info, n_formats} p
ptr :: Ptr (Ptr FormatInfo) <- #{peek struct pa_sink_info, formats} p
mapM (peekElemOff ptr . fromIntegral) [0.. size - 1]
poke _ (Sinkinfo {..}) = error "PA: Currently no sinkinfo poke"
type SinkinfoCB = Context -> Ptr Sinkinfo -> CInt -> Ptr Userdata -> IO ()
foreign import ccall "wrapper" mkSinkinfoCB :: SinkinfoCB -> IO (FunPtr SinkinfoCB)
foreign import ccall "pa_context_get_sink_info_list" pa_context_get_sink_info_list :: Context -> FunPtr SinkinfoCB -> Ptr Userdata -> IO (Ptr UOperation)
foreign import ccall "pa_context_get_sink_info_by_name" pa_context_get_sink_info_by_name :: Context -> CString -> FunPtr SinkinfoCB -> Ptr Userdata -> IO (Ptr UOperation)
foreign import ccall "pa_context_get_sink_info_by_index" pa_context_get_sink_info_by_index :: Context -> CUInt -> FunPtr SinkinfoCB -> Ptr Userdata -> IO (Ptr UOperation)
mkCallback :: (Sinkinfo -> IO ()) -> IO () -> IO (FunPtr SinkinfoCB)
mkCallback fun endf = mkSinkinfoCB $
\_ ptr end fP -> if end == 0
then fun =<< peek ptr
else do
endf -- Call the user end function
-- free the FunPtr defiend here
freeHaskellFunPtr (castPtrToFunPtr fP)
-- |Get all sinks from a context.
getContextSinks
:: Context -- ^The context
-> (Sinkinfo -> IO ()) -- ^List callback. Will be called once per list entry
-> IO () -- ^End callback. Will be called once after all list entries
-> IO Operation
getContextSinks cxt fun endf = do
funP <- mkCallback fun endf
ptrToOperation =<< pa_context_get_sink_info_list cxt funP (castFunPtrToPtr funP)
-- |Get a sink by name
getContextSinkByName
:: Context
-> String
-> (Sinkinfo -> IO ())
-> IO Operation
getContextSinkByName cxt name fun = do
funP <- mkCallback fun (return ())
ptrToOperation =<< withCString name (\ptr -> pa_context_get_sink_info_by_name cxt ptr funP (castFunPtrToPtr funP))
-- |Get a sink by index
getContextSinkByIndex
:: Context
-> Word32
-> (Sinkinfo -> IO ())
-> IO Operation
getContextSinkByIndex cxt idx fun = do
funP <- mkCallback fun (return ())
ptrToOperation =<< pa_context_get_sink_info_by_index cxt (fromIntegral idx) funP (castFunPtrToPtr funP)