Sebastian Sylvan wrote:
>Ben Rudiak-Gould wrote:
>>Why not spawn a thread which starts the playback, waits for it to
>>finish, and then exits, and wrap the whole thread in a call to
>>withForeignPtr? Then your finalizer won't be called prematurely.
>
>Well I could do this, but for one it would be cumbersome to stop
>playback.

I don't think it is. Let me try to specify the problem precisely to make sure we're talking about the same thing. We have an interface something like this:

   loadSong :: String -> IO (Ptr SongRep)
   playSong :: Ptr SongRep -> IO ()
   stopPlaying :: Ptr SongRep -> IO ()  -- it will also stop by itself
   isPlaying :: Ptr SongRep -> IO Bool
   freeSong :: Ptr SongRep -> IO ()     -- unsafe if song is playing

and we want an interface like this:

   loadSong' :: String -> IO Song
   playSong' :: Song -> IO ()
   stopPlaying' :: Song -> IO ()
   isPlaying' :: Song -> IO Bool

I think this implementation will work:

   type Song = ForeignPtr SongRep

   loadSong' name =
     loadSong name >>= newForeignPtr freeSong

   playSong' song =
     forkIO (withForeignPtr song (\s -> playSong s >> waitForSilence s))

   waitForSilence s =
     do threadDelay 500000
        b <- isPlaying s
        when b (waitForSilence s)

   stopPlaying' song = withForeignPtr song stopPlaying

   isPlaying' song = withForeignPtr song isPlaying

If you need the return value from playSong, this should also work:

   playSong' song =
     do rtn <- withForeignPtr song playSong
        forkIO (withForeignPtr song waitForSilence)
        return rtn

But this won't work, because the withForeignPtr call will return before the thread exits:

   brokenPlaySong' song =
     withForeignPtr song (\s -> playSong >> forkIO (waitForSilence s))


-- Ben

_______________________________________________
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to