From: Duncan C. <dun...@wo...> - 2007-11-10 18:17:57
|
Fri Nov 9 21:25:45 PST 2007 Peter Gavin <pg...@gm...> * gstreamer: M.S.G.Bus: improve API, add documentation hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 29 +-- [_$_] +-- An asynchronous message bus subsystem. +-- [_$_] hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 33 - [_$_] +-- * Types [_$_] + -- | The 'Bus' is resposible for delivering 'Message's in a + -- first-in, first-out order, from the streaming threads to the + -- application. + -- [_$_] + -- Since the application typically only wants to deal with + -- delivery of these messages from one thread, the 'Bus' will + -- marshal the messages between different threads. This is + -- important since the actual streaming of media is done in + -- a thread separate from the application. + -- + -- The 'Bus' provides support for 'System.Glib.MainLoop.Source' + -- based notifications. This makes it possible to handle the + -- delivery in the GLib 'System.Glib.MainLoop.Source'. + -- + -- A message is posted on the bus with the 'busPost' method. With + -- the 'busPeek' and 'busPop' methods one can look at or retrieve + -- a previously posted message. + -- + -- The bus can be polled with the 'busPoll' method. This methods + -- blocks up to the specified timeout value until one of the + -- specified messages types is posted on the bus. The application + -- can then pop the messages from the bus to handle + -- them. Alternatively the application can register an + -- asynchronous bus function using 'busAddWatch'. This function + -- will install a 'System.Glib.MainLoop.Source' in the default + -- GLib main loop and will deliver messages a short while after + -- they have been posted. Note that the main loop should be + -- running for the asynchronous callbacks. + -- + -- It is also possible to get messages from the bus without any + -- thread marshalling with the 'busSetSyncHandler' method. This + -- makes it possible to react to a message in the same thread that + -- posted the message on the bus. This should only be used if the + -- application is able to deal with messages from different + -- threads. + -- [_$_] + -- Every 'Pipeline' has one bus. + -- + -- Note that a 'Pipeline' will set its bus into flushing state + -- when changing from 'StateReady' to 'StateNull'. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 75 + -- | The result of a 'BusSyncHandler'. + BusSyncReply, + -- | A handler that will be invoked synchronously when a new message + -- is injected into the bus. This function is mostly used internally. + -- Only one sync handler may be attached to a given bus. + BusSyncHandler, hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 84 +-- * Bus Operations + busGetFlags, + busSetFlags, + busUnsetFlags, hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 95 + busSetSyncHandler, + busUseSyncSignalHandler, hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 99 + busDisableSyncMessageEmission, + busEnableSyncMessageEmission, hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 105 +-- * Bus Signals hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 107 - afterBusMessage + afterBusMessage, + onBusSyncMessage, + afterBusSyncMessage hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 113 -import Control.Monad (liftM) +import Control.Monad ( liftM + , when ) +{#import Media.Streaming.GStreamer.Core.Object#} hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 126 +-- | Get the flags set on this bus. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 132 +-- | Set flags on this bus. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 139 +-- | Unset flags on this bus. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 146 +-- | Create a new bus. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 151 -busPost :: Bus +-- | Post a message to the bus. +busPost :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 158 - liftM toBool $ {# call bus_post #} bus message + liftM toBool $ {# call bus_post #} (toBus bus) message hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 160 -busHavePending :: Bus +-- | Check if there are pending messages on the bus. +busHavePending :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 165 - liftM toBool $ {# call bus_have_pending #} bus + liftM toBool $ {# call bus_have_pending #} $ toBus bus hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 167 -busPeek :: Bus +-- | Get the message at the front of the queue. It will remain on the +-- queue. +busPeek :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 173 - {# call bus_peek #} bus >>= maybePeek takeMiniObject + {# call bus_peek #} (toBus bus) >>= maybePeek takeMiniObject hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 175 -busPop :: Bus +-- | Get the message at the front of the queue. It will be removed +-- from the queue. +busPop :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 181 - {# call bus_pop #} bus >>= maybePeek takeMiniObject + {# call bus_pop #} (toBus bus) >>= maybePeek takeMiniObject hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 183 -busTimedPop :: Bus - -> ClockTime +-- | Get a message from the bus, waiting up to the specified timeout. +-- If the time given is 'Nothing', the function will wait forever. +-- If the time given is @0@, the function will behave like 'busPop'. +busTimedPop :: BusClass busT + => busT + -> Maybe ClockTime hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 190 -busTimedPop bus timeout = - {# call bus_timed_pop #} bus (fromIntegral timeout) >>= - maybePeek takeMiniObject +busTimedPop bus timeoutM = + let timeout = case timeoutM of + Just timeout' -> timeout' + Nothing -> clockTimeNone + in {# call bus_timed_pop #} (toBus bus) (fromIntegral timeout) >>= + maybePeek takeMiniObject hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 197 -busSetFlushing :: Bus +-- | If @flushing@ is 'True', the bus will flush out any queued +-- messages, as well as any future messages, until the function is +-- called with @flushing@ set to 'False'. +busSetFlushing :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 205 - {# call bus_set_flushing #} bus $ fromBool flushing + {# call bus_set_flushing #} (toBus bus) $ fromBool flushing + +-- these will leak memory, maybe one day we can set a destroy notifier... + +type CBusSyncHandler = Ptr Bus + -> Ptr Message + -> {# type gpointer #} + -> IO {# type GstBusSyncReply #} +marshalBusSyncHandler :: BusSyncHandler + -> IO {# type GstBusSyncHandler #} +marshalBusSyncHandler busSyncHandler = + makeBusSyncHandler cBusSyncHandler + where cBusSyncHandler :: CBusSyncHandler + cBusSyncHandler busPtr messagePtr _ = + do bus <- peekObject busPtr + message <- peekMiniObject messagePtr + reply <- busSyncHandler bus message + when (reply == BusDrop) $ + {# call gst_mini_object_unref #} (toMiniObject message) + return $ fromIntegral $ fromEnum reply +foreign import ccall "wrapper" + makeBusSyncHandler :: CBusSyncHandler + -> IO {# type GstBusSyncHandler #} + +-- the following mess is necessary to clean up safely after busSetSyncHandler. +-- gstreamer doesn't give us a nice way to do this (such as a DestroyNotify) +weakNotifyQuark, funPtrQuark :: Quark +weakNotifyQuark = unsafePerformIO $ quarkFromString "Gtk2HS::SyncHandlerWeakNotify" +funPtrQuark = unsafePerformIO $ quarkFromString "Gtk2HS::SyncHandlerFunPtr" + +getWeakNotify :: BusClass busT + => busT + -> IO (Maybe GWeakNotify) +getWeakNotify = objectGetAttributeUnsafe weakNotifyQuark hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 240 -busCreateWatch :: Bus +setWeakNotify :: BusClass busT + => busT + -> Maybe GWeakNotify + -> IO () +setWeakNotify = objectSetAttribute weakNotifyQuark + +getFunPtr :: BusClass busT + => busT + -> IO (Maybe {# type GstBusSyncHandler #}) +getFunPtr = objectGetAttributeUnsafe funPtrQuark + +setFunPtr :: BusClass busT + => busT + -> Maybe {# type GstBusSyncHandler #} + -> IO () +setFunPtr = objectSetAttribute funPtrQuark + +unsetSyncHandler :: BusClass busT + => busT + -> IO () +unsetSyncHandler bus = do + {# call bus_set_sync_handler #} (toBus bus) nullFunPtr nullPtr + oldWeakNotifyM <- getWeakNotify bus + case oldWeakNotifyM of + Just oldWeakNotify -> objectWeakunref bus oldWeakNotify + Nothing -> return () + setWeakNotify bus Nothing + oldFunPtrM <- getFunPtr bus + case oldFunPtrM of + Just oldFunPtr -> freeHaskellFunPtr oldFunPtr + Nothing -> return () + setFunPtr bus Nothing + +-- | Set the synchronous message handler on the bus. The function will +-- be called every time a new message is posted to the bus. Note +-- that the function will be called from the thread context of the +-- poster. +-- [_$_] +-- Calling this function will replace any previously set sync +-- handler. If 'Nothing' is passed to this function, it will unset +-- the handler. +busSetSyncHandler :: BusClass busT + => busT + -> Maybe BusSyncHandler + -> IO () +busSetSyncHandler bus busSyncHandlerM = do + objectWithLock bus $ do + unsetSyncHandler bus + case busSyncHandlerM of + Just busSyncHandler -> + do funPtr <- marshalBusSyncHandler busSyncHandler + setFunPtr bus $ Just funPtr + weakNotify <- objectWeakref bus $ freeHaskellFunPtr funPtr + setWeakNotify bus $ Just weakNotify + {# call bus_set_sync_handler #} (toBus bus) funPtr nullPtr + Nothing -> + return () + +-- | Use a synchronous message handler that converts all messages to signals. +busUseSyncSignalHandler :: BusClass busT + => busT + -> IO () +busUseSyncSignalHandler bus = do + objectWithLock bus $ do + unsetSyncHandler bus + {# call bus_set_sync_handler #} (toBus bus) cBusSyncSignalHandlerPtr nullPtr +foreign import ccall unsafe "&gst_bus_sync_signal_handler" + cBusSyncSignalHandlerPtr :: {# type GstBusSyncHandler #} + +-- | Create a watch for the bus. The 'Source' will dispatch a signal +-- whenever a message is on the bus. After the signal is dispatched, +-- the message is popped off the bus. +busCreateWatch :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 316 - liftM Source $ {# call bus_create_watch #} bus >>= + liftM Source $ {# call bus_create_watch #} (toBus bus) >>= hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 338 -busAddWatch :: Bus +-- | Adds a bus watch to the default main context with the given +-- priority. This function is used to receive asynchronous messages +-- in the main loop. +-- [_$_] +-- The watch can be removed by calling 'System.Glib.MainLoop.sourceRemove'. +busAddWatch :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 347 - -> IO Word + -> IO HandlerId hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 353 - bus + (toBus bus) hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 359 -busAddSignalWatch :: Bus +-- | Instructs GStreamer to stop emitting the @"sync-message"@ signal +-- for this bus. See 'busEnableSyncMessageEmission' for more +-- information. +-- [_$_] +-- In the event that multiple pieces of code have called +-- 'busEnableSyncMessageEmission', the sync-message +-- emissions will only be stopped after all calls to +-- 'busEnableSyncMessageEmission' were "cancelled" by +-- calling this function. +busDisableSyncMessageEmission :: BusClass busT + => busT + -> IO () +busDisableSyncMessageEmission = + {# call bus_disable_sync_message_emission #} . toBus + +-- | Instructs GStreamer to emit the @"sync-message"@ signal after +-- running the bus's sync handler. This function is here so that +-- programmers can ensure that they can synchronously receive +-- messages without having to affect what the bin's sync handler is. +-- [_$_] +-- This function may be called multiple times. To clean up, the +-- caller is responsible for calling 'busDisableSyncMessageEmission' +-- as many times as this function is called. +-- [_$_] +-- While this function looks similar to 'busAddSignalWatch', it is +-- not exactly the same -- this function enables synchronous +-- emission of signals when messages arrive; 'busAddSignalWatch' +-- adds an idle callback to pop messages off the bus +-- asynchronously. The @"sync-message"@ signal comes from the thread +-- of whatever object posted the message; the @"message"@ signal is +-- marshalled to the main thread via the main loop. +busEnableSyncMessageEmission :: BusClass busT + => busT + -> IO () +busEnableSyncMessageEmission = + {# call bus_enable_sync_message_emission #} . toBus + +-- | Adds a bus signal watch to the default main context with the +-- given priority. After calling this method, the bus will emit the +-- @"message"@ signal for each message posted on the bus. +-- [_$_] +-- This function may be called multiple times. To clean up, the +-- caller is responsible for calling 'busRemoveSignalWatch' as many +-- times. +busAddSignalWatch :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 408 - {# call bus_add_signal_watch_full #} bus $ fromIntegral priority + {# call bus_add_signal_watch_full #} (toBus bus) $ fromIntegral priority hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 410 -busRemoveSignalWatch :: Bus +-- | Remove the signal watch that was added with 'busAddSignalWatch'. +busRemoveSignalWatch :: BusClass busT + => busT hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 415 - {# call bus_remove_signal_watch #} + {# call bus_remove_signal_watch #} . toBus hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 417 +-- | Poll the bus for a message. Will block while waiting for messages +-- to come. You can specify the maximum amount of time to wait with +-- the @timeout@ parameter. If @timeout@ is negative, the function +-- will wait indefinitely. +-- [_$_] +-- Messages not in @events@ will be popped off the bus and ignored. +-- [_$_] +-- Because 'busPoll' is implemented using the @"message"@ signal +-- enabled by 'busAddSignalWatch', calling 'busPoll' will cause the +-- @"message"@ signal to be emitted for every message that the +-- function sees. Thus, a @"message"@ signal handler will see every +-- message that 'busPoll' sees -- neither will steal messages from +-- the other. +-- [_$_] +-- This function will run a main loop in the default main context +-- while polling. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 443 +-- | Connect to the @"message"@ signal. Emitted from a 'Source' added +-- to the mainloop. This signal will only be emitted when there is a +-- 'MainLoop' running. hunk ./gstreamer/Media/Streaming/GStreamer/Core/Bus.chs 455 +-- | A message has been posted on the bus. This signal is emitted from +-- the thread that posted the message so one has to be careful with +-- locking. +-- [_$_] +-- This signal will not be emitted by default, you must first call +-- 'busUseSyncSignalHandler' if you want this signal to be emitted +-- when a message is posted on the bus. +onBusSyncMessage, afterBusSyncMessage :: BusClass bus + => bus + -> (Message -> IO ()) + -> IO (ConnectId bus) +onBusSyncMessage = + connect_BOXED__NONE "sync-message" peekMiniObject False +afterBusSyncMessage = + connect_BOXED__NONE "sync-message" peekMiniObject True + hunk ./gstreamer/Media/Streaming/GStreamer/Core/Types.chs 75 + BusSyncHandler, hunk ./gstreamer/Media/Streaming/GStreamer/Core/Types.chs 335 +type BusSyncHandler = Bus + -> Message + -> IO BusSyncReply |