[Haskell-cafe] FFI woes!
sebastian.sylvan at gmail.com
Thu Dec 16 10:20:51 EST 2004
On Thu, 16 Dec 2004 12:38:26 +0000, Jules Bean <jules at jellybean.co.uk> wrote:
> On 16 Dec 2004, at 06:57, Sebastian Sylvan wrote:
> > Here's the problem though. If the SamplePlaybackRaw is currently
> > playing sound when it gets garbage collected, I want to keep the sound
> > resource (SoundSample) alive until the playback has finished.
> I probably haven't understood the details correctly but why not just
> spawn a thread in your 'start playback' function. This thread (a) keeps
> a reference to the soundsample (which guarantees it will never be
> GC'ed) and (b) checks every second or so to see if the playing has
> finished. If the playing has finished, it arranges to no longer hold
> the reference, and in due course GC will take it out.
This is my "if-all-else-fails" backup.
I really don't want to poll the sound sample all the time since it
uses up resources needlessly. If it comes to that, though, it's pretty
much guaranteed that it will get the job done.
The plan was to try to initiate the polling loop only when the GC
wants to delete the sound channel.
Here's what I imagine a typical execution could look like
1. Sound resource, s, is loaded
2. Calling "play" on s, returns a "channel" in which the sound is being played.
3. Repeat 2 any number of times.
4. The GC is being invoked. s may no longer be in scope, but the
"channels" are still referencing the sound resource so it won't get
collected. If the channel(s) are out of scope and the GC tries to
collect them, they will each spawn a "keep-alive-loop" in their
finalizer which has no other purpose but to keep the sound resource
alive for however long it takes to finish playing.
This is what I tried to do. I've now tried to do it with weak pointers
as well. I get the finalizer to run, but for some reason the finalizer
for the sound resource gets invoked before the finalizer for the
channel. This is extremply strange since the channel contains a
reference to the "ForeignPtr CSoundSample" so I wouldn't expect the
sound resource finalizer to EVER get invoked while there are still
channels around that are referencing it.
Here's the latest attempt:
-- the sound resource.
-- The finalizer will simply call the C-library's "free"-function
sampleLoad :: String -> IO SoundSample
sampleLoad s = do cs <- newCString s
samplePtr <- fsound_SampleLoad (-1) cs 0 0 0
finalizer <- mkSampleFinalizer sampleFinalizer
newForeignPtr finalizer samplePtr
-- The playback
-- contains the channel AND a reference to the SoundSample
-- so the soundsample should NEVER get finalized before the
data SamplePlaybackRaw = SP !CInt !SoundSample
type SamplePlayback = Weak SamplePlaybackRaw
-- play a sample
samplePlay :: SoundSample -> IO SamplePlayback
samplePlay sample = do ch <- withForeignPtr sample (fsound_PlaySound (-1))
let spb = SP ch sample -- SamplePlaybackRaw
mkWeakPtr spb (Just (samplePlaybackFinalizer spb))
samplePlaybackFinalizer :: SamplePlaybackRaw -> IO ()
samplePlaybackFinalizer (SP ch sample) =
do putStrLn "Starting keep-alive loop for sample playback"
forkIO (keepAlive ch sample)
keepAlive :: CInt -> SoundSample -> IO ()
keepAlive ch sample = do putStrLn "Keeping channel alive!"
threadDelay 500000 -- wait a while
b <- fsound_IsPlaying ch
case cscharToBool b of
True -> keepAlive ch sample
False -> putStrLn "Finished keeping
More information about the Haskell-Cafe