{-| Pulse Audio Pipes sink -}
module SDR.Pulse (
    pulseAudioSink,
    doPulse
    ) where

import Foreign.ForeignPtr
import Foreign.C.Types
import Control.Concurrent
import Data.ByteString.Internal
import Data.Vector.Storable     as VS

import Sound.Pulse.Simple
import Pipes
import Pipes.Concurrent

-- | Returns a consumer that sends all incoming data to pulseaudio. Runs Pulse Audio output writing in a different thread. This is probably what you want as it does not block the entire pipline while the data is being played.
pulseAudioSink :: IO (Consumer (VS.Vector Float) IO ())
pulseAudioSink = do
    (output, input) <- spawn $ bounded 1
    doIt <- doPulse
    forkOS $ runEffect $ fromInput input >-> doIt
    return $ toOutput output

-- | Returns a consumer that sends all incoming data to pulseaudio.
doPulse :: IO (Consumer (VS.Vector Float) IO ())
doPulse = do
    s <- simpleNew Nothing "Haskell SDR" Play Nothing "Software Defined Radio library" (SampleSpec (F32 LittleEndian) 48000 1) Nothing Nothing
    return $ for cat $ \buf ->
        lift $ do
            let (fp, offset, length) = VS.unsafeToForeignPtr buf
            simpleWriteRaw s (PS (castForeignPtr fp) (offset * 4) (length * 4))